# Pad — production Docker Compose override # Usage: docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d # # Extends the base docker-compose.yml with: # - Resource limits # - Secure cookie settings # - CORS configuration # - Email (Maileroo) support # - Named network for reverse proxy integration services: pad: environment: PAD_SECURE_COOKIES: "true" # Override Redis URL to include password when REDIS_PASSWORD is set. # Without this, the pad container inherits the passwordless URL from # docker-compose.yml and fails to connect when Redis AUTH is enabled. PAD_REDIS_URL: "redis://:${REDIS_PASSWORD:-}@redis:6379" # Set your public-facing URL for correct invitation links: # PAD_URL: "https://pad.example.com" # CORS origins (comma-separated): # PAD_CORS_ORIGINS: "https://pad.example.com" # Email (Maileroo): # PAD_MAILEROO_API_KEY: "your-sending-key" # PAD_EMAIL_FROM: "noreply@example.com" # PAD_EMAIL_FROM_NAME: "Pad" # SSE limits: # PAD_SSE_MAX_CONNECTIONS covers BOTH SSE endpoints (BUG-2726). # PAD_SSE_MAX_CONNECTIONS: "1000" # PAD_SSE_MAX_PER_WORKSPACE: "100" # PAD_SSE_MAX_PER_USER: "50" # Set only when this Redis is shared with another Pad installation. # PAD_REDIS_NAMESPACE: "prod" deploy: resources: limits: cpus: "2.0" memory: 512M reservations: cpus: "0.5" memory: 128M networks: - pad-net - default postgres: environment: # Base compose already requires POSTGRES_PASSWORD. We keep the same # required-reference here (no placeholder default) so a production # deploy can never silently boot with a known-weak credential. POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required — see .env.example}" deploy: resources: limits: cpus: "2.0" memory: 1G reservations: cpus: "0.25" memory: 256M # In production, consider using a managed PostgreSQL service instead. redis: # noeviction, NOT allkeys-lru (BUG-2698). Pad's Redis holds the # session-presence registry as well as pub/sub, and evicting a live # session's entry is indistinguishable from its TTL lapsing: the # session disappears from the "push to agent" picker and a push # targeted at it reports delivered_sessions: 0 while it is still # connected. It self-repairs on the next 30s renewal, but the # keyspace is small — a few hundred bytes per connected session plus # two counters — so there is nothing to gain by evicting it. See # docs/deployment.md's Redis configuration notes. command: redis-server --maxmemory 128mb --maxmemory-policy noeviction --requirepass "${REDIS_PASSWORD:-}" healthcheck: # Override the base healthcheck to authenticate when REDIS_PASSWORD is set. # redis-cli reads REDISCLI_AUTH automatically for authentication. test: ["CMD-SHELL", "REDISCLI_AUTH=$${REDIS_PASSWORD:-} redis-cli ping | grep -q PONG"] interval: 5s timeout: 3s retries: 5 environment: REDIS_PASSWORD: "${REDIS_PASSWORD:-}" deploy: resources: limits: cpus: "1.0" memory: 256M reservations: cpus: "0.1" memory: 64M networks: pad-net: name: pad-net # Attach your reverse proxy (Caddy, nginx) to this network.