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
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# 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:
|
||||
Reference in New Issue
Block a user