# 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