# Production Docker Compose for quicprochat # # Usage: # 1. Copy .env.example to .env and fill in secrets # 2. Place TLS certificates in ./certs/ # 3. docker compose -f docker-compose.prod.yml up -d # # Prerequisites: # - TLS certificate and key in DER format (no auto-generation in production) # - Strong auth token (>= 16 characters) # - Database encryption key networks: qpc: driver: bridge volumes: qpc-data: prometheus-data: grafana-data: services: # ── quicprochat server ──────────────────────────────────────────────────────── server: build: context: . dockerfile: docker/Dockerfile restart: unless-stopped ports: - "${QPC_LISTEN_PORT:-7000}:7000/udp" # QUIC - "${QPC_WS_PORT:-9000}:9000" # WebSocket bridge (optional) environment: RUST_LOG: info QPC_PRODUCTION: "true" QPC_LISTEN: "0.0.0.0:7000" QPC_DATA_DIR: /var/lib/quicprochat QPC_TLS_CERT: /var/lib/quicprochat/certs/server-cert.der QPC_TLS_KEY: /var/lib/quicprochat/certs/server-key.der QPC_AUTH_TOKEN: "${QPC_AUTH_TOKEN}" QPC_STORE_BACKEND: sql QPC_DB_PATH: /var/lib/quicprochat/qpc.db QPC_DB_KEY: "${QPC_DB_KEY}" QPC_METRICS_LISTEN: "0.0.0.0:9090" QPC_METRICS_ENABLED: "true" QPC_SEALED_SENDER: "${QPC_SEALED_SENDER:-false}" QPC_REDACT_LOGS: "${QPC_REDACT_LOGS:-true}" QPC_WS_LISTEN: "${QPC_WS_LISTEN:-}" volumes: - qpc-data:/var/lib/quicprochat - ./certs:/var/lib/quicprochat/certs:ro networks: - qpc deploy: resources: limits: cpus: '4' memory: 4G reservations: cpus: '2' memory: 1G ulimits: nofile: soft: 65536 hard: 65536 healthcheck: test: ["CMD", "test", "-f", "/var/lib/quicprochat/certs/server-cert.der"] interval: 30s timeout: 5s retries: 3 start_period: 10s logging: driver: json-file options: max-size: "50m" max-file: "5" # ── Prometheus ─────────────────────────────────────────────────────────────── prometheus: image: prom/prometheus:latest restart: unless-stopped ports: - "127.0.0.1:9091:9090" volumes: - prometheus-data:/prometheus - ./docs/operations/prometheus.yml:/etc/prometheus/prometheus.yml:ro - ./docs/operations/prometheus-alerts.yml:/etc/prometheus/alerts.yml:ro command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--storage.tsdb.retention.time=30d' - '--web.enable-lifecycle' networks: - qpc depends_on: - server # ── Grafana ────────────────────────────────────────────────────────────────── grafana: image: grafana/grafana:latest restart: unless-stopped ports: - "127.0.0.1:3000:3000" environment: GF_SECURITY_ADMIN_PASSWORD: "${GRAFANA_ADMIN_PASSWORD:?Set GRAFANA_ADMIN_PASSWORD in .env}" GF_USERS_ALLOW_SIGN_UP: "false" volumes: - grafana-data:/var/lib/grafana - ./docs/operations/dashboards:/var/lib/grafana/dashboards:ro - ./docs/operations/grafana-provisioning:/etc/grafana/provisioning:ro networks: - qpc depends_on: - prometheus