evan.jarrett.net / atcr-appview
ATProto Container Registry - OCI-compliant registry using AT Protocol for manifest storage
Pull this image
docker pull atcr.io/evan.jarrett.net/atcr-appview:latest
Overview
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:
- AppView (this component) - Registry API + web interface
- Hold Service - Storage backend with embedded PDS for blob storage
- 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 (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:
# 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:
# 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:
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_URLhostname, oratcr.io - Description: Service name used for JWT
serviceandissuerfields. 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
falseto 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
debugfor detailed troubleshooting - Production: Use
infoorwarn
ATCR_LOG_FORMATTER
- Default:
text - Options:
text,json - Description: Log output format
- Production: Use
jsonfor 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_INTERVALfor 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
truefor 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:
# 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:
# 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:
# 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 for comprehensive production deployment guide.
Quick Production Checklist
Before going to production:
- Set
ATCR_BASE_URLto your public HTTPS URL - Set
ATCR_DEFAULT_HOLD_DIDto a production hold service - Enable Jetstream backfill (
ATCR_BACKFILL_ENABLED=true) - Use
ATCR_LOG_FORMATTER=jsonfor 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 - All available environment variables with documentation
- deploy/.env.prod.template - Production configuration template
- deploy/README.md - Production deployment guide
- Hold Service Documentation - Storage backend setup