Docker deployment
Compose (full stack)
docker/docker-compose.yml brings up Postgres, Redis, ClickHouse, and the rolter gateway + control services.
cp .env.example .env # set OPENAI_API_KEY etc.
docker compose -f docker/docker-compose.yml up -d
docker compose -f docker/docker-compose.yml logs -f gateway
- Gateway: http://localhost:4000
- Control + UI: http://localhost:4001
- Postgres
5432, Redis6379, ClickHouse8123/9000
DB schemas auto-apply on first start, by two different routes. The Postgres
schema is owned by sqlx::migrate!, which rolter-control and rolter-seed
both run on startup; Compose deliberately does not mount migrations/ into
the container’s docker-entrypoint-initdb.d, because letting Postgres apply
those files itself would bypass sqlx’s _sqlx_migrations bookkeeping and make
the next startup replay every migration against a populated database (#499).
ClickHouse has no such runner, so clickhouse/ is mounted into its initdb
directory and is that schema’s only provisioning path.
Image
The multi-stage docker/Dockerfile produces a slim Debian runtime with both
binaries and the built UI at /app/ui/dist. Its default command is rolter easy-up, so one image serves the gateway and dashboard with the built-in
fake-llm model — no compose file, provider key, or config mount required.
docker build -f docker/Dockerfile -t rolter:dev .
docker run --rm -p 4000:4000 -p 4001:4001 rolter:dev
Then open http://localhost:4001 and verify the data plane with:
curl -s http://localhost:4000/v1/chat/completions \
-H 'Authorization: Bearer sk-rolter-dev' \
-H 'Content-Type: application/json' \
-d '{"model":"fake-llm","messages":[{"role":"user","content":"hello"}]}'
Override the command to run just the gateway or control plane:
docker run --rm -p 4000:4000 rolter:dev rolter-gateway --config /app/rolter.toml
docker run --rm -p 4001:4001 rolter:dev rolter-control
Published images
Release tags publish an image to GHCR (and, when configured, Docker Hub) under the same repo name and tags. Each release is tagged with its version and latest:
docker pull ghcr.io/<owner>/rolter:latest
docker pull ghcr.io/<owner>/rolter:0.0.4
Publishing is fail-closed and opt-in, mirroring the PyPI flow. The publish-docker job in .github/workflows/release.yml runs only when:
- repo variable
DOCKER_PUBLISH_ENABLED=true, and - the verify + external-check gates pass for the tagged commit.
GHCR always publishes via the built-in GITHUB_TOKEN. To also push to Docker Hub, set repo variable DOCKERHUB_IMAGE (e.g. docker.io/acme/rolter) and secrets DOCKERHUB_USERNAME / DOCKERHUB_TOKEN; the same tag set is applied to both registries. (Multi-arch images are a separate roadmap item — releases currently ship linux/amd64.)
Production notes
- Put the gateway behind TLS (ingress/load balancer); keep the control plane private.
- Set a strong
ROLTER_KEK; provide DB/Redis/ClickHouse URLs via env or a secrets manager. - Scale
gatewayhorizontally; all replicas hot-reload config from Redis. ClickHouse and Postgres are shared. - Kubernetes deployments are supported through the rolter Helm chart.
Air-gapped
Running fully offline behind an internal mirror (Nexus/Artifactory/Harbor)? See Air-gapped install & operation.