Production Docker Compose, generated properly.
Pick your stack and get the parts tutorials skip: health-gated startup, restart policies, ports bound to localhost, memory limits and nightly database backups.
docker-compose.yml
# Generated by ComposeKit · solyxlabs.com
# Start: cp .env.example .env (set strong passwords: openssl rand -base64 24)
# docker compose up -d
name: app
services:
app:
build: . # or: image: ghcr.io/you/yourapp:main
restart: unless-stopped
# no ports: Caddy is the public door and reaches app:3000 internally
environment:
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/api/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
deploy:
resources:
limits:
memory: 768M
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
deploy: { resources: { limits: { memory: 512M } } }
pg-backup:
image: postgres:16-alpine
restart: unless-stopped
environment:
PGPASSWORD: ${POSTGRES_PASSWORD}
volumes:
- ./backups:/backups
entrypoint: |
sh -c 'while true; do
pg_dump -h postgres -U ${POSTGRES_USER} ${POSTGRES_DB} | gzip > /backups/backup-$$(date +%F).sql.gz
find /backups -name "backup-*.sql.gz" -mtime +7 -delete
sleep 86400
done'
depends_on:
postgres:
condition: service_healthy
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data # certificates live here, keep this volume
- caddy_config:/config
deploy: { resources: { limits: { memory: 256M } } }
# Caddyfile (2 lines, automatic HTTPS):
# yourdomain.com {
# reverse_proxy app:3000
# }
volumes:
pgdata:
caddy_data:
caddy_config:
Put these in .env beside the file: POSTGRES_USER=app POSTGRES_PASSWORD= POSTGRES_DB=app
Want this running on your server by Friday?
Ship-It puts your app on your own server for a fixed $297. HTTPS, deploys on every push, backups that get restore-tested, alerts that reach your phone first.
Tell us what eats your week.
A half-hour conversation, no obligation. If we can help, we tell you how. If we can’t, we say so.
