Skip to content
solyxlabs
Free tool, no signup

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.

Your app
Add-ons

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.

See Ship-It deployment

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.

We read every one ourselves and reply within a day. Prefer email? hello@solyxlabs.com.