diff --git a/docs/appview.md b/docs/appview.md index 2d179e6..e4830a0 100644 --- a/docs/appview.md +++ b/docs/appview.md @@ -1,104 +1,321 @@ # ATCR AppView -The **AppView** is the OCI-compliant registry server for ATCR (ATProto Container Registry). It provides the Docker Registry HTTP API V2 and a web interface for browsing container images. +> The registry frontend component of ATCR (ATProto Container Registry) -## What is AppView? +## Overview -AppView serves as the central registry server that: +**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. -- **Serves OCI Distribution API** - Compatible with Docker, containerd, podman, and other OCI clients -- **Resolves ATProto identities** - Converts handles and DIDs to PDS endpoints -- **Routes manifests** - Stores container manifests as ATProto records in users' Personal Data Servers -- **Routes blobs** - Proxies blob operations to hold services (S3-compatible storage) -- **Provides web UI** - Browse, search, and star repositories +### What AppView Does -## Image Format +AppView is the orchestration layer that: -Container images use ATProto identities: +- **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:** ``` -atcr.io/alice.bsky.social/myapp:latest -atcr.io/did:plc:xyz123/myapp:latest +Docker Client → AppView (resolves identity) → User's PDS (stores manifest) + ↓ + Hold Service (stores blobs in S3/Storj/etc.) ``` -## Using ATCR +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. -### Push Images +## 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 -# Install credential helper -curl -fsSL https://atcr.io/install.sh | bash +# Clone repository +git clone https://tangled.org/@evan.jarrett.net/at-container-registry +cd atcr -# Configure Docker (add to ~/.docker/config.json) -{ - "credHelpers": { - "atcr.io": "atcr" - } -} - -# Push images (authenticates automatically) -docker tag myapp:latest atcr.io/yourhandle/myapp:latest -docker push atcr.io/yourhandle/myapp:latest -``` - -### Pull Images - -```bash -# Public images (no auth required) -docker pull atcr.io/alice.bsky.social/myapp:latest - -# Private images (automatic OAuth authentication) -docker pull atcr.io/yourhandle/private-app:latest -``` - -## Running Your Own AppView - -Deploy your own registry instance with Docker Compose: - -```bash -# Create configuration +# Copy and configure environment cp .env.appview.example .env.appview -# Edit .env.appview with your settings +# Edit .env.appview - set ATCR_DEFAULT_HOLD_DID (see Configuration below) # Start services docker-compose up -d + +# Verify +curl http://localhost:5000/v2/ ``` -### Configuration +### Minimal Configuration -Key environment variables: +At minimum, you must set: -- `ATCR_HTTP_ADDR` - HTTP listen address (default: `:5000`) -- `ATCR_BASE_URL` - Public URL for OAuth/JWT realm -- `ATCR_DEFAULT_HOLD_DID` - Default hold service DID for blob storage (required) -- `ATCR_UI_ENABLED` - Enable web interface (default: `true`) -- `JETSTREAM_URL` - ATProto event stream URL for real-time updates +```bash +# Required: Default hold service for blob storage +ATCR_DEFAULT_HOLD_DID=did:web:127.0.0.1:8080 -See [deployment documentation](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/README.md) for production setup. +# Recommended for production +ATCR_BASE_URL=https://registry.example.com +ATCR_HTTP_ADDR=:5000 +``` -## Features +See **Configuration Reference** below for all options. -- ✅ **OCI-compliant** - Full Docker Registry API V2 support -- ✅ **ATProto OAuth** - Secure authentication with DPoP -- ✅ **Decentralized storage** - Manifests stored in users' PDS -- ✅ **Web UI** - Browse repositories, view tags, search images -- ✅ **Real-time updates** - Jetstream integration for live indexing -- ✅ **Multi-arch support** - ARM64, AMD64, and other platforms -- ✅ **BYOS** - Bring Your Own Storage via hold services +## Configuration Reference -## Storage Architecture +AppView is configured entirely via environment variables. Load them with: +```bash +source .env.appview +./bin/atcr-appview serve +``` -**Hybrid model:** -- **Manifests** → ATProto records in user's PDS (small JSON metadata) -- **Blobs** → Hold services with S3-compatible backends (large binary layers) +Or via Docker Compose (recommended). -This design keeps metadata portable and federated while leveraging cheap blob storage for layers. +### Server Configuration -## License +#### `ATCR_HTTP_ADDR` +- **Default:** `:5000` +- **Description:** HTTP listen address for the registry API and web UI +- **Example:** `:5000`, `:8080`, `0.0.0.0:5000` -MIT +#### `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` -**Documentation:** https://tangled.org/@evan.jarrett.net/at-container-registry -**Source Code:** https://tangled.org/@evan.jarrett.net/at-container-registry +#### `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