services: tranquil-pds: build: context: . dockerfile: Dockerfile image: tranquil-pds:latest restart: unless-stopped ports: - "127.0.0.1:3000:3000" environment: SERVER_HOST: "0.0.0.0" SERVER_PORT: "3000" PDS_HOSTNAME: "${PDS_HOSTNAME:?PDS_HOSTNAME is required}" DATABASE_URL: "postgres://tranquil_pds:${DB_PASSWORD:?DB_PASSWORD is required}@db:5432/pds" S3_ENDPOINT: "http://minio:9000" AWS_REGION: "us-east-1" S3_BUCKET: "pds-blobs" AWS_ACCESS_KEY_ID: "${MINIO_ROOT_USER:-minioadmin}" AWS_SECRET_ACCESS_KEY: "${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}" VALKEY_URL: "redis://valkey:6379" JWT_SECRET: "${JWT_SECRET:?JWT_SECRET is required (min 32 chars)}" DPOP_SECRET: "${DPOP_SECRET:?DPOP_SECRET is required (min 32 chars)}" MASTER_KEY: "${MASTER_KEY:?MASTER_KEY is required (min 32 chars)}" CRAWLERS: "${CRAWLERS:-https://bsky.network}" FRONTEND_DIR: "/app/frontend/dist" depends_on: db: condition: service_healthy minio: condition: service_healthy valkey: condition: service_healthy healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/xrpc/_health"] interval: 30s timeout: 10s retries: 3 start_period: 10s deploy: resources: limits: memory: 1G reservations: memory: 256M db: image: postgres:18-alpine restart: unless-stopped environment: POSTGRES_USER: tranquil_pds POSTGRES_PASSWORD: "${DB_PASSWORD:?DB_PASSWORD is required}" POSTGRES_DB: pds volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U tranquil_pds -d pds"] interval: 10s timeout: 5s retries: 5 start_period: 10s deploy: resources: limits: memory: 512M reservations: memory: 128M minio: image: minio/minio:RELEASE.2025-10-15T17-29-55Z restart: unless-stopped command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: "${MINIO_ROOT_USER:-minioadmin}" MINIO_ROOT_PASSWORD: "${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}" volumes: - minio_data:/data healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 30s timeout: 10s retries: 3 start_period: 10s deploy: resources: limits: memory: 512M reservations: memory: 128M minio-init: image: minio/mc:RELEASE.2025-07-16T15-35-03Z depends_on: minio: condition: service_healthy entrypoint: > /bin/sh -c " mc alias set local http://minio:9000 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD}; mc mb --ignore-existing local/pds-blobs; mc anonymous set none local/pds-blobs; exit 0; " environment: MINIO_ROOT_USER: "${MINIO_ROOT_USER:-minioadmin}" MINIO_ROOT_PASSWORD: "${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required}" valkey: image: valkey/valkey:9-alpine restart: unless-stopped command: valkey-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - valkey_data:/data healthcheck: test: ["CMD", "valkey-cli", "ping"] interval: 10s timeout: 5s retries: 3 start_period: 5s deploy: resources: limits: memory: 300M reservations: memory: 64M nginx: image: nginx:1.28-alpine restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./nginx.prod.conf:/etc/nginx/nginx.conf:ro - ./certs:/etc/nginx/certs:ro - acme_challenge:/var/www/acme:ro depends_on: - tranquil-pds healthcheck: test: ["CMD", "nginx", "-t"] interval: 30s timeout: 10s retries: 3 certbot: image: certbot/certbot:v5.2.2 volumes: - ./certs:/etc/letsencrypt - acme_challenge:/var/www/acme entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/acme; sleep 12h & wait $${!}; done'" prometheus: image: prom/prometheus:v3.8.0 restart: unless-stopped ports: - "127.0.0.1:9090:9090" volumes: - ./observability/prometheus.yml:/etc/prometheus/prometheus.yml:ro - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--storage.tsdb.retention.time=30d' deploy: resources: limits: memory: 256M volumes: postgres_data: minio_data: valkey_data: prometheus_data: acme_challenge: