# Production stack for a single DigitalOcean Droplet. The database is Neon (DATABASE_URL in .env.prod). # cd /opt/notestack/deploy && docker compose --env-file .env.prod -f docker-compose.prod.yml up -d --build # The API listens on 127.0.0.1:API_PORT (default 8010) for the reverse proxy already on this host (Nginx, # Caddy...). On a Droplet with nothing else on ports 80/443, start the bundled Caddy with --profile caddy. services: api: build: ../backend restart: unless-stopped env_file: .env.prod # Migrations are NOT applied on start. Run them by hand: docker compose --env-file .env.prod -f docker-compose.prod.yml run --rm api alembic upgrade head # Proxy headers let the API see the real client IP and https scheme behind Caddy. command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips='*' ports: - "127.0.0.1:${API_PORT:-8010}:8000" # local only: the host proxy forwards API_DOMAIN here volumes: - appdata:/data healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health')"] interval: 30s timeout: 5s retries: 3 start_period: 40s worker: build: ../backend restart: unless-stopped env_file: .env.prod command: python -m app.worker volumes: - appdata:/data # same volume as the API, so both see the same stored files and corpus cache depends_on: api: condition: service_healthy # the API has applied migrations by the time it is healthy renderer: build: ../renderer restart: unless-stopped environment: INTERNAL_TOKEN: ${INTERNAL_TOKEN} # must match the API's profiles: ["render"] # optional: start with --profile render (needs about 2 GB of free RAM) caddy: # only on a Droplet with no other web server: --profile caddy image: caddy:2 restart: unless-stopped profiles: ["caddy"] ports: - "80:80" - "443:443" - "443:443/udp" environment: # only what the Caddyfile needs, not the app secrets API_DOMAIN: ${API_DOMAIN} ACME_EMAIL: ${ACME_EMAIL} volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config depends_on: - api volumes: appdata: {} caddy_data: {} caddy_config: {}