Deployment
Deploy Bifrost: topologies, the Docker Compose stack, and per-platform guides.
Run the gateway with Postgres and Redis. The repository provides a Docker Compose stack for local hosts, Linux servers, Coolify, Portainer, and Dokploy. The dashboard and docs are separate services that can be deployed independently.
Pick your platform
- Local — run it on your machine for development.
- Coolify — deploy the Compose stack on Coolify.
- Portainer — deploy the Compose stack on Portainer.
- Dokploy — deploy the Compose stack on Dokploy.
- Docker on a Linux VPS — plain
docker composeon any host.
Topologies
How the gateway reaches Postgres/Redis decides whether you need TLS — and, because the gateway runs on Bun, whether you hit the self-signed TLS issue.
| Topology | Connection | TLS | Works on Bun |
|---|---|---|---|
| Compose (all-in-one) — gateway + Postgres + Redis together | internal Docker network | none (plaintext) | ✅ recommended |
| Managed database (Neon / Aiven / Upstash …) | internet | public-CA | ✅ |
| Self-signed database exposed publicly (raw Coolify/Dokploy port) | internet | self-signed | ⚠️ may fail — see Troubleshooting |
The first row is the default for every recipe here: the gateway talks to Postgres/Redis over the private Compose network in plaintext, which is both safe (network isolation) and immune to the Bun TLS issue.
Compose files and naming
docker/compose.yamlis the production base. It exposes services to the private network without publishing host ports.docker/compose.local.yamladds loopback-only host mappings for local development or a host reverse proxy. Load it explicitly; do not add it to a production PaaS deployment.
The Compose stack
The repository ships a docker/compose.yaml that brings up the whole stack:
- postgres (
postgres:18-alpine) and redis (redis:8-alpine), with health checks and named volumes (pgdata,redisdata). - migrate — a one-off job that applies SQL migrations and exits; the gateway waits for it to finish. PaaS dashboards may list it as a domain candidate; leave its domain empty.
- gateway (
:4000internally) — built fromapps/gateway/Dockerfile. - dashboard (
:3001internally) — the optional operator UI, off unlessDASH_ENABLEDis true. It is an independent deployment with its own domain, and it needs one setting —GATEWAY_URL. The gateway needs nothing, and does not have to be public. See Operator dashboard → Serving it. - docs (
:3000internally) — this documentation site.
Coolify and Dokploy deploy only docker/compose.yaml and attach their proxy to the private network.
For a local machine or a host-level reverse proxy, merge the local override explicitly:
git clone https://github.com/boelabs/bifrost.git && cd bifrost
MASTER_KEY=$(openssl rand -base64 48) \
ENCRYPTION_KEY_HEX=$(openssl rand -hex 32) \
docker compose -f docker/compose.yaml -f docker/compose.local.yaml up -ddocker/compose.local.yaml supplies known development-only defaults. The production base intentionally
leaves both secrets empty, and the gateway refuses to start until they are configured. In
Coolify/Portainer/Dokploy, set them in the UI. DATABASE_URL and REDIS_URL default to the internal
postgres/redis services over plaintext and only need overriding if you point at managed instances
— see Setup.
Assign domains only to the gateway, dashboard, and docs services you want to expose. Keep
Postgres, Redis, and the one-off migrate job internal. The production Compose base enforces this
by publishing no host ports.