# Production stack for one VPS: Postgres + the app + Caddy (automatic HTTPS from Let's Encrypt). # Usage: cp .env.example .env (fill it in) then docker compose up -d --build services: db: image: postgres:17-alpine restart: unless-stopped environment: POSTGRES_DB: bundle_offers POSTGRES_USER: bundle_offers POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U bundle_offers -d bundle_offers"] interval: 5s retries: 10 app: build: . restart: unless-stopped depends_on: db: condition: service_healthy environment: NODE_ENV: production PORT: 3000 DATABASE_URL: postgresql://bundle_offers:${POSTGRES_PASSWORD}@db:5432/bundle_offers?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} SHOPIFY_APP_HANDLE: ${SHOPIFY_APP_HANDLE:-offerlyst} DATA_ENCRYPTION_KEY: ${DATA_ENCRYPTION_KEY:?set DATA_ENCRYPTION_KEY in .env (openssl rand -hex 32)} SCOPES: read_products,write_discounts,read_discounts,read_orders,write_files,read_themes,write_app_proxy expose: - "3000" 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: