# Production stack for one VPS: Postgres + the app + the worker + Caddy (automatic HTTPS from Let's Encrypt). # Usage: cp .env.example .env (fill in the production section) then docker compose up -d --build # If the VPS already runs Nginx on 80/443, use docker-compose.nginx.yml instead of Caddy (see that file). x-app-env: &app-env NODE_ENV: production PORT: 3000 DATABASE_URL: postgresql://datewise:${POSTGRES_PASSWORD}@db:5432/datewise?schema=public SHOPIFY_API_KEY: ${SHOPIFY_API_KEY:?set SHOPIFY_API_KEY in .env} SHOPIFY_API_SECRET: ${SHOPIFY_API_SECRET:?set SHOPIFY_API_SECRET in .env} SHOPIFY_APP_URL: https://${APP_DOMAIN:?set APP_DOMAIN in .env} SCOPES: read_products,write_products,write_publications,read_orders,write_orders,read_customers,read_locations,read_inventory,write_validations,write_delivery_customizations,write_payment_customizations APP_ENCRYPTION_KEY: ${APP_ENCRYPTION_KEY:?set APP_ENCRYPTION_KEY in .env (openssl rand -base64 32)} GOOGLE_MAPS_API_KEY: ${GOOGLE_MAPS_API_KEY:-} RESEND_API_KEY: ${RESEND_API_KEY:-} EMAIL_FROM_DOMAIN: ${EMAIL_FROM_DOMAIN:-} services: db: image: postgres:17-alpine restart: unless-stopped environment: POSTGRES_DB: datewise POSTGRES_USER: datewise POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U datewise -d datewise"] interval: 5s retries: 10 app: build: . image: datewise:latest restart: unless-stopped depends_on: db: condition: service_healthy environment: *app-env expose: - "3000" # Sweeps expired holds, sends reminders, offers freed places to the waitlist, reconciles missed orders. worker: image: datewise:latest restart: unless-stopped depends_on: app: condition: service_healthy # the app has applied migrations environment: *app-env command: ["node", "build/worker.mjs"] healthcheck: disable: true caddy: image: caddy:2-alpine restart: unless-stopped depends_on: [app] ports: - "80:80" - "443:443" environment: APP_DOMAIN: ${APP_DOMAIN} volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config volumes: pgdata: caddy_data: caddy_config: