Files
musicshare/docker-compose.prod.yml
T
chrisandClaude Opus 5.5 7f46ba2d1b Production deploy for musicshare.binarygnome.com
- docker-compose.prod.yml overlay: Caddy with automatic HTTPS on one
  origin (web at /, API at /api incl. websocket), internal-only Postgres/
  Redis/API/web, secure cookies, private-network servers blocked, nightly
  pg_dump backups kept 14 days
- deploy/export-db.sh and import-db.sh to carry a database to the server
  (same TOKEN_ENCRYPTION_KEY required for stored connections)
- Base compose no longer requires apps/api/.env
- README: deployment, Spotify via scrobblers, SMTP settings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
2026-10-05 19:16:40 -04:00

87 lines
2.3 KiB
YAML

# Production overlay. On the server:
# cp deploy/production.env.example deploy/production.env # fill in secrets
# docker compose -f docker-compose.yml -f docker-compose.prod.yml --env-file deploy/production.env up -d --build
#
# Adds Caddy (HTTPS on 80/443) in front, keeps the database, Redis, API and web
# app off the public internet, and runs nightly database backups.
x-prod-api: &prod-api
env_file: deploy/production.env
environment:
NODE_ENV: production
DATABASE_URL: postgres://musicshare:${POSTGRES_PASSWORD:?set in production.env}@postgres:5432/musicshare
REDIS_URL: redis://redis:6379
WEB_URL: https://${DOMAIN}
API_PUBLIC_URL: https://${DOMAIN}/api
COOKIE_SECURE: 'true'
# Hosted: never let users point us at private networks.
ALLOW_PRIVATE_SERVER_URLS: 'false'
services:
postgres:
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set in production.env}
ports: !reset []
redis:
ports: !reset []
migrate:
<<: *prod-api
api:
<<: *prod-api
ports: !reset []
worker:
<<: *prod-api
web:
build:
args:
NEXT_PUBLIC_API_URL: https://${DOMAIN}/api
NEXT_PUBLIC_DONATION_URL: ${DONATION_URL:-}
ports: !reset []
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3
environment:
DOMAIN: ${DOMAIN:?set in production.env}
volumes:
- ./deploy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- web
- api
# Nightly pg_dump into ./backups, keeping the last 14 days.
backup:
image: postgres:17
restart: unless-stopped
environment:
PGPASSWORD: ${POSTGRES_PASSWORD:?set in production.env}
volumes:
- ./backups:/backups
entrypoint: ["/bin/sh", "-c"]
command:
- |
while true; do
f=/backups/musicshare-$$(date +%Y%m%d-%H%M).sql.gz
pg_dump -h postgres -U musicshare musicshare | gzip > "$$f" && echo "backup ok: $$f" || echo "backup FAILED"
find /backups -name 'musicshare-*.sql.gz' -mtime +14 -delete
sleep 86400
done
depends_on:
postgres:
condition: service_healthy
volumes:
caddy_data:
caddy_config: