Bifrost

Production checklist

What to verify before pointing real traffic at a deployment.

A condensed checklist. Each item links to the page with the full explanation.

Secrets

  • MASTER_KEY and every ENCRYPTION_KEYRING value are strong, unique per environment, and live in a secret manager — not in the image, not in git, not in the Compose file's defaults. docker/compose.local.yaml's secrets are development-only; the production docker/compose.yaml base ships both empty and refuses to start until you set them. See Security.
  • You have a rotation plan for both, and know the leaked-secret procedure — Operations → Secrets.

Network and TLS

  • Postgres and Redis connections use a public-CA certificate, or a private network without TLS. Bun's TLS implementation rejects self-signed certificates — a raw Coolify/Dokploy-exposed port commonly hits this. See Known errors.
  • Only the gateway (and optionally the docs site) is exposed through your reverse proxy; Postgres and Redis stay on the internal network. See Deployment.

Health and scaling

  • Liveness probe → GET /health/live (no dependency checks — never point liveness at a dependency-aware endpoint, or a Postgres/Redis blip restarts every replica at once).
  • Readiness probe → GET /health/ready (pulls an unhealthy instance from the load balancer without restarting it).
  • Your orchestrator gives the container more than DRAIN_DELAY_MS + SHUTDOWN_TIMEOUT_MS before SIGKILL (stop_grace_period in Compose, Stop Grace Period in Coolify). Docker's default is 10 seconds, which is shorter than the drain — the process is killed mid-sequence and every in-flight stream dies with it. See Rollouts.
  • The proxy in front of the gateway polls /health/ready and acts on it. Without that, the drain delay announces a departure nothing is listening for.
  • Replicas are safe to scale horizontally; shared quotas/circuits are in Redis and maintenance work is idempotent or transactionally claimed. See Operations.

Data lifecycle

  • Migrations are applied at boot (MIGRATE_ON_BOOT, the default), or you run them as your own step — and either way every migration works against the version it replaces, because a rollout has both live at once. See Rollouts.
  • OBSERVABILITY_METADATA_RETENTION_DAYS, OBSERVABILITY_PAYLOAD_RETENTION_DAYS, and RESPONSES_STATE_RETENTION_DAYS match your actual compliance/storage requirements. Every finished request keeps one encrypted payload sample, so the payload window is both the disk bill and the exposure window.
  • OBSERVABILITY_PAYLOAD_ACCESS is a decision, not a default: sealed keeps capturing samples and lets nobody read them, which is what a deployment handling regulated content wants.
  • You have a Postgres backup schedule. Redis needs none (fully rebuildable ephemeral state). See Operations → Backups.

Observability

  • OTEL_ENABLED=true with a real OTEL_EXPORTER_OTLP_ENDPOINT if you want traces/metrics — disabled by default.
  • The encryption keyring is backed up and its rotation procedure is rehearsed; the gateway never emits payload bodies to OTel. See Security.
  • Logs (structured JSON on stdout) are shipped to a collector.

Routing and resilience

  • PUT /admin/router-settings reflects real choices, not silent defaults — especially unsupportedParameterStrategy (default drop, which silently strips parameters; error may be safer for a strict client). See Routing and Parameter policy.
  • Every Public Model you rely on has more than one deployment, or an explicit acceptance that it has none. See Fallbacks for pool-exhaustion behavior.

Dependencies

  • bun audit --production is clean (CI enforces this at --audit-level=high, but re-check after adding any runtime extension dependency).

Next steps

  • Upgrades — what changes between releases and how to roll one out safely.
  • Operations — the full runbook behind this checklist.

On this page