# Production stack: app + Postgres + Caddy (automatic HTTPS). # cp .env.example .env # set DOMAIN, BASE_URL=https://, POSTGRES_PASSWORD, ... # docker compose up -d --build # # To run on SQLite instead, set DB_DRIVER=sqlite in the app service and # remove the db service; the database file lives in the app-data volume. name: skeleton services: app: build: . restart: unless-stopped env_file: .env environment: ENVIRONMENT: production DB_DRIVER: postgres DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?sslmode=disable volumes: - app-data:/app/data depends_on: db: condition: service_healthy # Only reachable through Caddy; never publish this port directly. expose: - "8000" deploy: resources: limits: cpus: "1" memory: 512M db: image: postgres:18-alpine restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} volumes: - db-data:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 5 caddy: image: caddy:2-alpine restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" environment: DOMAIN: ${DOMAIN} volumes: - ./deploy/Caddyfile:/etc/caddy/Caddyfile:ro - caddy-data:/data - caddy-config:/config depends_on: - app volumes: app-data: db-data: caddy-data: caddy-config: