322 lines
12 KiB
Markdown
322 lines
12 KiB
Markdown
# ATCR AppView
|
|
|
|
> The registry frontend component of ATCR (ATProto Container Registry)
|
|
|
|
## Overview
|
|
|
|
**AppView** is the frontend server component of ATCR. It serves as the OCI-compliant registry API endpoint and web interface that Docker clients interact with when pushing and pulling container images.
|
|
|
|
### What AppView Does
|
|
|
|
AppView is the orchestration layer that:
|
|
|
|
- **Serves the OCI Distribution API V2** - Compatible with Docker, containerd, podman, and all OCI clients
|
|
- **Resolves ATProto identities** - Converts handles (`alice.bsky.social`) and DIDs (`did:plc:xyz123`) to PDS endpoints
|
|
- **Routes manifests** - Stores container image manifests as ATProto records in users' Personal Data Servers
|
|
- **Routes blobs** - Proxies blob (layer) operations to hold services for S3-compatible storage
|
|
- **Provides web UI** - Browse repositories, search images, view tags, track pull counts, manage stars
|
|
- **Manages authentication** - Validates OAuth tokens and issues registry JWTs to Docker clients
|
|
|
|
### The ATCR Ecosystem
|
|
|
|
AppView is the **frontend** of a multi-component architecture:
|
|
|
|
1. **AppView** (this component) - Registry API + web interface
|
|
2. **[Hold Service](https://atcr.io/r/evan.jarrett.net/atcr-hold)** - Storage backend with embedded PDS for blob storage
|
|
3. **Credential Helper** - Client-side tool for ATProto OAuth authentication
|
|
|
|
**Data flow:**
|
|
```
|
|
Docker Client → AppView (resolves identity) → User's PDS (stores manifest)
|
|
↓
|
|
Hold Service (stores blobs in S3/Storj/etc.)
|
|
```
|
|
|
|
Manifests (small JSON metadata) live in users' ATProto PDS, while blobs (large binary layers) live in hold services. AppView orchestrates the routing between these components.
|
|
|
|
## When to Run Your Own AppView
|
|
|
|
Most users can simply use **https://atcr.io** - you don't need to run your own AppView.
|
|
|
|
**Run your own AppView if you want to:**
|
|
- Host a private/organizational container registry with ATProto authentication
|
|
- Run a public registry for a specific community
|
|
- Customize the registry UI or policies
|
|
- Maintain full control over registry infrastructure
|
|
|
|
**Prerequisites:**
|
|
- A running [Hold service](https://atcr.io/r/evan.jarrett.net/atcr-hold) (required for blob storage)
|
|
- (Optional) Domain name with SSL/TLS certificates for production
|
|
- (Optional) Access to ATProto Jetstream for real-time indexing
|
|
|
|
## Quick Start
|
|
|
|
### Using Docker Compose
|
|
|
|
The fastest way to run AppView alongside a Hold service:
|
|
|
|
```bash
|
|
# Clone repository
|
|
git clone https://tangled.org/@evan.jarrett.net/at-container-registry
|
|
cd atcr
|
|
|
|
# Copy and configure environment
|
|
cp .env.appview.example .env.appview
|
|
# Edit .env.appview - set ATCR_DEFAULT_HOLD_DID (see Configuration below)
|
|
|
|
# Start services
|
|
docker-compose up -d
|
|
|
|
# Verify
|
|
curl http://localhost:5000/v2/
|
|
```
|
|
|
|
### Minimal Configuration
|
|
|
|
At minimum, you must set:
|
|
|
|
```bash
|
|
# Required: Default hold service for blob storage
|
|
ATCR_DEFAULT_HOLD_DID=did:web:127.0.0.1:8080
|
|
|
|
# Recommended for production
|
|
ATCR_BASE_URL=https://registry.example.com
|
|
ATCR_HTTP_ADDR=:5000
|
|
```
|
|
|
|
See **Configuration Reference** below for all options.
|
|
|
|
## Configuration Reference
|
|
|
|
AppView is configured entirely via environment variables. Load them with:
|
|
```bash
|
|
source .env.appview
|
|
./bin/atcr-appview serve
|
|
```
|
|
|
|
Or via Docker Compose (recommended).
|
|
|
|
### Server Configuration
|
|
|
|
#### `ATCR_HTTP_ADDR`
|
|
- **Default:** `:5000`
|
|
- **Description:** HTTP listen address for the registry API and web UI
|
|
- **Example:** `:5000`, `:8080`, `0.0.0.0:5000`
|
|
|
|
#### `ATCR_BASE_URL`
|
|
- **Default:** Auto-detected from `ATCR_HTTP_ADDR` (e.g., `http://127.0.0.1:5000`)
|
|
- **Description:** Public URL for the AppView service. Used to generate OAuth redirect URIs and JWT realm claims.
|
|
- **Development:** Auto-detection works fine (`http://127.0.0.1:5000`)
|
|
- **Production:** Set to your public URL (e.g., `https://atcr.example.com`)
|
|
- **Example:** `https://atcr.io`, `http://127.0.0.1:5000`
|
|
|
|
#### `ATCR_SERVICE_NAME`
|
|
- **Default:** Derived from `ATCR_BASE_URL` hostname, or `atcr.io`
|
|
- **Description:** Service name used for JWT `service` and `issuer` fields. Controls token scope.
|
|
- **Example:** `atcr.io`, `registry.example.com`
|
|
|
|
#### `ATCR_DEBUG_ADDR`
|
|
- **Default:** `:5001`
|
|
- **Description:** Debug listen address for pprof debugging endpoints
|
|
- **Example:** `:5001`, `:6060`
|
|
|
|
### Storage Configuration
|
|
|
|
#### `ATCR_DEFAULT_HOLD_DID` ⚠️ REQUIRED
|
|
- **Default:** None (required)
|
|
- **Description:** DID of the default hold service for blob storage. Used when users don't have their own hold configured in their sailor profile. AppView routes all blob operations to this hold.
|
|
- **Format:** `did:web:hostname[:port]`
|
|
- **Docker Compose:** `did:web:atcr-hold:8080` (internal Docker network)
|
|
- **Local dev:** `did:web:127.0.0.1:8080`
|
|
- **Production:** `did:web:hold01.atcr.io`
|
|
- **Note:** This hold must be reachable from AppView. To find a hold's DID, visit `https://hold-url/.well-known/did.json`
|
|
|
|
### Authentication Configuration
|
|
|
|
#### `ATCR_AUTH_KEY_PATH`
|
|
- **Default:** `/var/lib/atcr/auth/private-key.pem`
|
|
- **Description:** Path to JWT signing private key (RSA). Auto-generated if missing.
|
|
- **Note:** Keep this secure - it signs all registry JWTs issued to Docker clients
|
|
|
|
#### `ATCR_AUTH_CERT_PATH`
|
|
- **Default:** `/var/lib/atcr/auth/private-key.crt`
|
|
- **Description:** Path to JWT signing certificate. Auto-generated if missing.
|
|
- **Note:** Paired with `ATCR_AUTH_KEY_PATH`
|
|
|
|
#### `ATCR_TOKEN_EXPIRATION`
|
|
- **Default:** `300` (5 minutes)
|
|
- **Description:** JWT token expiration in seconds. Registry JWTs are short-lived for security.
|
|
- **Recommendation:** Keep between 300-900 seconds (5-15 minutes)
|
|
|
|
### Web UI Configuration
|
|
|
|
#### `ATCR_UI_ENABLED`
|
|
- **Default:** `true`
|
|
- **Description:** Enable the web interface. Set to `false` to run registry API only (no web UI, no database).
|
|
- **Use case:** API-only deployments where you don't need the browsing interface
|
|
|
|
#### `ATCR_UI_DATABASE_PATH`
|
|
- **Default:** `/var/lib/atcr/ui.db`
|
|
- **Description:** SQLite database path for UI data (OAuth sessions, stars, pull counts, repository metadata)
|
|
- **Note:** For multi-instance deployments, use PostgreSQL (see production docs)
|
|
|
|
### Logging Configuration
|
|
|
|
#### `ATCR_LOG_LEVEL`
|
|
- **Default:** `info`
|
|
- **Options:** `debug`, `info`, `warn`, `error`
|
|
- **Description:** Log verbosity level
|
|
- **Development:** Use `debug` for detailed troubleshooting
|
|
- **Production:** Use `info` or `warn`
|
|
|
|
#### `ATCR_LOG_FORMATTER`
|
|
- **Default:** `text`
|
|
- **Options:** `text`, `json`
|
|
- **Description:** Log output format
|
|
- **Production:** Use `json` for structured logging (easier to parse with log aggregators)
|
|
|
|
### Hold Health Check Configuration
|
|
|
|
AppView periodically checks if hold services are reachable and caches results to display health indicators in the UI.
|
|
|
|
#### `ATCR_HEALTH_CHECK_INTERVAL`
|
|
- **Default:** `15m`
|
|
- **Description:** How often to check health of hold endpoints in the background
|
|
- **Format:** Duration string (e.g., `5m`, `15m`, `30m`, `1h`)
|
|
- **Recommendation:** 15-30 minutes for production
|
|
|
|
#### `ATCR_HEALTH_CACHE_TTL`
|
|
- **Default:** `15m`
|
|
- **Description:** How long to cache health check results before re-checking
|
|
- **Format:** Duration string (e.g., `15m`, `30m`, `1h`)
|
|
- **Note:** Should be >= `ATCR_HEALTH_CHECK_INTERVAL` for efficiency
|
|
|
|
### Jetstream Configuration (ATProto Event Streaming)
|
|
|
|
Jetstream provides real-time indexing of ATProto records (manifests, tags) into the AppView database for the web UI.
|
|
|
|
#### `JETSTREAM_URL`
|
|
- **Default:** `wss://jetstream2.us-west.bsky.network/subscribe`
|
|
- **Description:** Jetstream WebSocket URL for real-time ATProto events
|
|
- **Note:** Connects to Bluesky's public Jetstream by default
|
|
|
|
#### `ATCR_BACKFILL_ENABLED`
|
|
- **Default:** `false`
|
|
- **Description:** Enable periodic sync of historical ATProto records. Set to `true` for production to ensure database completeness.
|
|
- **Recommendation:** Enable for production AppView instances
|
|
|
|
#### `ATCR_RELAY_ENDPOINT`
|
|
- **Default:** `https://relay1.us-east.bsky.network`
|
|
- **Description:** ATProto relay endpoint for backfill sync API
|
|
- **Note:** Used when `ATCR_BACKFILL_ENABLED=true`
|
|
|
|
#### `ATCR_BACKFILL_INTERVAL`
|
|
- **Default:** `1h`
|
|
- **Description:** How often to run backfill sync
|
|
- **Format:** Duration string (e.g., `30m`, `1h`, `2h`, `24h`)
|
|
|
|
### Legacy Configuration
|
|
|
|
#### `TEST_MODE`
|
|
- **Default:** `false`
|
|
- **Description:** Enable test mode (skips some validations). Do not use in production.
|
|
|
|
## Web Interface Features
|
|
|
|
The AppView web UI provides:
|
|
|
|
- **Home page** - Featured repositories and recent pushes feed
|
|
- **Repository pages** - View tags, manifests, pull instructions, health status
|
|
- **Search** - Find repositories by owner handle or repository name
|
|
- **User profiles** - View a user's repositories and activity
|
|
- **Stars** - Favorite repositories (requires OAuth login)
|
|
- **Pull counts** - Track image pull statistics
|
|
- **Multi-arch support** - Display platform-specific manifests (linux/amd64, linux/arm64)
|
|
- **Health indicators** - Real-time hold service reachability status
|
|
- **Install scripts** - Host credential helper installation scripts at `/install.sh`
|
|
|
|
## Deployment Scenarios
|
|
|
|
### Public Registry (like atcr.io)
|
|
|
|
Open to all ATProto users:
|
|
|
|
```bash
|
|
# AppView config
|
|
ATCR_BASE_URL=https://registry.example.com
|
|
ATCR_DEFAULT_HOLD_DID=did:web:hold01.example.com
|
|
ATCR_UI_ENABLED=true
|
|
ATCR_BACKFILL_ENABLED=true
|
|
|
|
# Hold config (linked hold service)
|
|
HOLD_PUBLIC=true # Allow public pulls
|
|
HOLD_ALLOW_ALL_CREW=true # Allow all authenticated users to push
|
|
```
|
|
|
|
### Private Organizational Registry
|
|
|
|
Restricted to crew members only:
|
|
|
|
```bash
|
|
# AppView config
|
|
ATCR_BASE_URL=https://registry.internal.example.com
|
|
ATCR_DEFAULT_HOLD_DID=did:web:hold.internal.example.com
|
|
ATCR_UI_ENABLED=true
|
|
|
|
# Hold config (linked hold service)
|
|
HOLD_PUBLIC=false # Require auth for pulls
|
|
HOLD_ALLOW_ALL_CREW=false # Only owner + explicit crew can push
|
|
HOLD_OWNER=did:plc:your-org-did # Organization DID
|
|
```
|
|
|
|
### Development/Testing
|
|
|
|
Local Docker Compose setup:
|
|
|
|
```bash
|
|
# AppView config
|
|
ATCR_HTTP_ADDR=:5000
|
|
ATCR_DEFAULT_HOLD_DID=did:web:atcr-hold:8080
|
|
ATCR_LOG_LEVEL=debug
|
|
|
|
# Hold config (linked hold service)
|
|
STORAGE_DRIVER=filesystem
|
|
STORAGE_ROOT_DIR=/tmp/atcr-hold
|
|
HOLD_PUBLIC=true
|
|
HOLD_ALLOW_ALL_CREW=true
|
|
```
|
|
|
|
## Production Deployment
|
|
|
|
For production deployments with:
|
|
- Multiple AppView instances (load balancing)
|
|
- PostgreSQL database (instead of SQLite)
|
|
- SSL/TLS certificates
|
|
- Systemd service files
|
|
- Log rotation
|
|
- Monitoring
|
|
|
|
See **[deploy/README.md](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/README.md)** for comprehensive production deployment guide.
|
|
|
|
### Quick Production Checklist
|
|
|
|
Before going to production:
|
|
|
|
- [ ] Set `ATCR_BASE_URL` to your public HTTPS URL
|
|
- [ ] Set `ATCR_DEFAULT_HOLD_DID` to a production hold service
|
|
- [ ] Enable Jetstream backfill (`ATCR_BACKFILL_ENABLED=true`)
|
|
- [ ] Use `ATCR_LOG_FORMATTER=json` for structured logging
|
|
- [ ] Secure JWT keys (`ATCR_AUTH_KEY_PATH`, `ATCR_AUTH_CERT_PATH`)
|
|
- [ ] Configure SSL/TLS termination (nginx/Caddy/Cloudflare)
|
|
- [ ] Set up database backups (if using SQLite, consider PostgreSQL)
|
|
- [ ] Monitor hold health checks
|
|
- [ ] Test OAuth flow end-to-end
|
|
- [ ] Verify Docker push/pull works
|
|
|
|
## Configuration Files Reference
|
|
|
|
- **[.env.appview.example](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/.env.appview.example)** - All available environment variables with documentation
|
|
- **[deploy/.env.prod.template](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/.env.prod.template)** - Production configuration template
|
|
- **[deploy/README.md](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/README.md)** - Production deployment guide
|
|
- **[Hold Service Documentation](https://atcr.io/r/evan.jarrett.net/atcr-hold)** - Storage backend setup
|