- 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
87 lines
2.3 KiB
YAML
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:
|