# ATCR Production Deployment with Caddy # For UpCloud Rocky Linux deployment # # Usage: # 1. Copy .env.prod.template to .env and fill in your values # 2. docker compose -f deploy/docker-compose.prod.yml up -d # # Domains: # - atcr.io → AppView (registry API + web UI) # - hold01.atcr.io → Hold service (presigned URL generator) # - blobs.atcr.io → S3 object storage (CNAME to UpCloud S3) services: caddy: image: caddy:2-alpine container_name: atcr-caddy restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" # HTTP/3 environment: APPVIEW_DOMAIN: ${APPVIEW_DOMAIN:-atcr.io} HOLD_DOMAIN: ${HOLD_DOMAIN:-hold01.atcr.io} volumes: - caddy_data:/data - caddy_config:/config configs: - source: caddyfile target: /etc/caddy/Caddyfile networks: - atcr-network healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:2019/metrics"] interval: 30s timeout: 10s retries: 3 start_period: 10s atcr-appview: build: context: .. dockerfile: Dockerfile.appview image: atcr-appview:latest container_name: atcr-appview restart: unless-stopped environment: # Server configuration ATCR_HTTP_ADDR: :5000 ATCR_BASE_URL: https://${APPVIEW_DOMAIN:-atcr.io} ATCR_SERVICE_NAME: ${APPVIEW_DOMAIN:-atcr.io} # Storage configuration (derived from HOLD_DOMAIN) ATCR_DEFAULT_HOLD_DID: ${ATCR_DEFAULT_HOLD_DID:-did:web:${HOLD_DOMAIN:-hold01.atcr.io}} # Authentication ATCR_AUTH_KEY_PATH: /var/lib/atcr/auth/private-key.pem ATCR_AUTH_CERT_PATH: /var/lib/atcr/auth/private-key.crt ATCR_TOKEN_EXPIRATION: ${ATCR_TOKEN_EXPIRATION:-300} # UI configuration ATCR_UI_ENABLED: ${ATCR_UI_ENABLED:-true} ATCR_UI_DATABASE_PATH: /var/lib/atcr/ui.db # Logging ATCR_LOG_LEVEL: ${ATCR_LOG_LEVEL:-info} ATCR_LOG_FORMATTER: ${ATCR_LOG_FORMATTER:-text} # Jetstream configuration JETSTREAM_URL: ${JETSTREAM_URL:-wss://jetstream2.us-west.bsky.network/subscribe} ATCR_BACKFILL_ENABLED: ${ATCR_BACKFILL_ENABLED:-true} ATCR_RELAY_ENDPOINT: ${ATCR_RELAY_ENDPOINT:-https://relay1.us-east.bsky.network} ATCR_BACKFILL_INTERVAL: ${ATCR_BACKFILL_INTERVAL:-1h} volumes: # Persistent data: auth keys, UI database, OAuth tokens, Jetstream cache - atcr-appview-data:/var/lib/atcr networks: - atcr-network healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5000/v2/"] interval: 30s timeout: 10s retries: 3 start_period: 30s atcr-hold: build: context: .. dockerfile: Dockerfile.hold image: atcr-hold:latest container_name: atcr-hold restart: unless-stopped environment: # Hold service configuration (derived from HOLD_DOMAIN) HOLD_PUBLIC_URL: ${HOLD_PUBLIC_URL:-https://${HOLD_DOMAIN:-hold01.atcr.io}} HOLD_SERVER_ADDR: :8080 HOLD_ALLOW_ALL_CREW: ${HOLD_ALLOW_ALL_CREW:-false} HOLD_PUBLIC: ${HOLD_PUBLIC:-false} HOLD_OWNER: ${HOLD_OWNER:-} HOLD_BLUESKY_POSTS_ENABLED: ${HOLD_BLUESKY_POSTS_ENABLED:-true} # Embedded PDS configuration HOLD_DATABASE_DIR: ${HOLD_DATABASE_DIR:-/var/lib/atcr-hold} # HOLD_KEY_PATH: ${HOLD_KEY_PATH} # Optional, defaults to {HOLD_DATABASE_DIR}/signing.key # Storage driver STORAGE_DRIVER: ${STORAGE_DRIVER:-s3} # S3/UpCloud Object Storage configuration AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-} AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-} AWS_REGION: ${AWS_REGION:-us-east-1} S3_BUCKET: ${S3_BUCKET:-atcr-blobs} S3_ENDPOINT: ${S3_ENDPOINT:-} # Logging ATCR_LOG_LEVEL: ${ATCR_LOG_LEVEL:-debug} ATCR_LOG_FORMATTER: ${ATCR_LOG_FORMATTER:-text} # Optional: Filesystem storage (comment out S3 vars above) # STORAGE_DRIVER: filesystem # STORAGE_ROOT_DIR: /var/lib/atcr/hold volumes: # PDS data (carstore SQLite + signing keys) - atcr-hold-data:/var/lib/atcr-hold networks: - atcr-network healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 30s networks: atcr-network: driver: bridge ipam: config: - subnet: 172.29.0.0/24 volumes: caddy_data: driver: local caddy_config: driver: local atcr-appview-data: driver: local atcr-hold-data: driver: local configs: caddyfile: content: | # ATCR AppView - Main registry + web UI ${APPVIEW_DOMAIN:-atcr.io} { # Reverse proxy to AppView container reverse_proxy atcr-appview:5000 { # Preserve original host header header_up Host {host} header_up X-Real-IP {remote_host} } # Enable compression encode gzip # Logging log { output file /data/logs/appview.log { roll_size 100mb roll_keep 10 } } } # ATCR Hold Service - Storage presigned URL generator ${HOLD_DOMAIN:-hold01.atcr.io} { # Reverse proxy to Hold service container reverse_proxy atcr-hold:8080 { # Preserve original host header header_up Host {host} header_up X-Real-IP {remote_host} } # Enable compression encode gzip # Logging log { output file /data/logs/hold.log { roll_size 100mb roll_keep 10 } } }