# Production stack for MealQuest on 10.60.1.14 (D-018). Build and start on # the host with: # # docker compose -f deploy/compose.yaml up -d --build # # Configuration comes from deploy/.env (copy deploy/.env.example) and secrets # from deploy/secrets/; neither is committed. Compose bind-mounts file secrets # with their host owner and mode, so each file in deploy/secrets/ must be # owned by the container user 10001:10001 with mode 0600. name: mealquest services: mealquest: build: context: .. dockerfile: Dockerfile user: "10001:10001" restart: unless-stopped env_file: - path: .env required: true # Fixed by this file's container shape (listen port, volume, secret # mounts); deploy/.env must not set them. environment: MEALQUEST_HTTP_ADDR: ":8080" MEALQUEST_DATA_DIR: /data MEALQUEST_SECRET_KEY_FILE: /run/secrets/secret_key MEALQUEST_OIDC_CLIENT_SECRET_FILE: /run/secrets/oidc_client_secret secrets: - secret_key - oidc_client_secret volumes: - mealquest-data:/data ports: - "${MEALQUEST_BIND_ADDRESS:?set MEALQUEST_BIND_ADDRESS in deploy/.env}:8090:8080" networks: - mealquest healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8080/health"] interval: 30s timeout: 3s start_period: 10s retries: 3 security_opt: - no-new-privileges:true cap_drop: - ALL # Litestream streams the database to the Synology NAS over SFTP # (config: deploy/litestream.yml). The SFTP private key # deploy/secrets/litestream_key is a dedicated keypair, owned by # 10001:10001 with mode 0600 like the other secrets. # # The data volume is mounted read-write on purpose: Litestream writes its # tracking tables into the database and checkpoints the WAL. It runs as # the app's own user (owner of the volume) with a read-only root # filesystem, no privilege escalation and no Linux capabilities. # # Restore (app stopped; --no-deps so the app does not start and create a # fresh database first): # docker compose -f deploy/compose.yaml run --rm --no-deps litestream \ # restore -config /etc/litestream.yml -o /data/mealquest.db /data/mealquest.db litestream: image: litestream/litestream:0.5.17 user: "10001:10001" restart: unless-stopped command: ["replicate", "-config", "/etc/litestream.yml"] depends_on: mealquest: condition: service_healthy volumes: - mealquest-data:/data - ./litestream.yml:/etc/litestream.yml:ro - ./secrets/litestream_key:/etc/litestream/sftp_key:ro networks: - mealquest read_only: true tmpfs: - /tmp security_opt: - no-new-privileges:true cap_drop: - ALL secrets: secret_key: file: ./secrets/secret_key oidc_client_secret: file: ./secrets/oidc_client_secret volumes: mealquest-data: name: mealquest-data networks: mealquest: name: mealquest