Installing CodeLotse with Docker Compose ​
CodeLotse runs as one Docker Compose project (quavon) defined in deploy/compose/docker-compose.yml. The installer generates all secrets, writes the non-secret settings, builds the application image, starts the stack and prints a one-time setup link. The deployment contract is described in ADR-0009.
Requirements ​
| Item | Minimum |
|---|---|
| Docker Engine | 24 or newer, daemon reachable by the installing user |
| Docker Compose | v2 plugin (docker compose version) |
| CPU / memory (as seen by Docker) | 2 CPUs, 4 GiB (warning below) |
| Free disk on the installation directory | 20 GiB (warning below) |
| Tools on the host | POSIX sh, openssl (or /dev/urandom with od, dd, base64), curl for the clock check, ss, lsof or nc for the port check |
| Network | Inbound on the published HTTP/HTTPS ports; outbound HTTPS to GitHub (github.com or your GHES host) |
| Clock | Synchronised (NTP). GitHub rejects app JWTs from hosts whose clock is off |
Quick start ​
git clone <quavon-repository-url> quavon && cd quavon
./deploy/compose/quavon install --domain quavon.example.com --email ops@example.comWithout flags the installer asks for the missing values. With --yes it never asks and accepts every change (use it for automation). The script can be started from any directory; it always operates on deploy/compose/.
| Option | Meaning |
|---|---|
--domain NAME | Public host name. PUBLIC_URL becomes https://NAME (plus :PORT if --https-port is not 443) |
--tls acme|provided|internal | TLS mode, default acme |
--email ADDRESS | ACME account contact, required for acme |
--cert FILE, --key FILE | PEM certificate chain and key, required for provided |
--http-port PORT, --https-port PORT | Published ports, default 80 and 443 |
--github-url URL | https://github.com (default) or the origin of a GitHub Enterprise Server |
--sandbox | Enable the sandbox runner for deterministic checks; needs gVisor runsc registered with Docker (see sandbox.md) |
--yes | Non-interactive |
What the installer does:
- Preflight: Docker and Compose versions, free ports (skipped while the stack's
caddyis running), CPU, memory and disk (warnings), a random source, TLS inputs (acme: e-mail, DNS of the domain, ports 80/443;provided: readable PEM files) and the clock against GitHub'sDateheader (warning above 30 s). Every failed requirement is listed with a fix before the installer stops; nothing is changed until all requirements pass. - Secrets: creates
deploy/compose/secrets/(mode 0700) and every missing secret file (mode 0644). Existing files are never overwritten. - Settings: shows the changes to
deploy/compose/.env, asks for confirmation, backs up the previous file to.env.bak.<UTC timestamp>and writes the new one. Keys that the installer does not manage are kept. - Start:
docker compose up -d --build, then waits (up to 600 s,QUAVON_WAIT_TIMEOUToverrides) untilpostgres,valkey,api,workerandcaddyare healthy and the one-shotinitservice (roles and migrations) has completed. - Setup link: on the first installation it creates a setup token and prints the setup URL. Re-runs keep everything and print no new link; use
./deploy/compose/quavon setup-tokenwhen you need one.
Re-running the installer is safe: it keeps secrets, only rewrites .env when a setting changes and rebuilds the image.
TLS modes ​
| Mode | Use | Notes |
|---|---|---|
acme | Public servers | Caddy obtains and renews certificates automatically. The domain must resolve to this host and ports 80 and 443 must be reachable from the internet. |
provided | Certificates from your own CA | TLS_CERT_FILE and TLS_KEY_FILE are stored in .env as absolute paths. You renew the files yourself and restart caddy. The files must be readable by the container user. |
internal | Evaluation, local networks | Caddy's internal CA signs the certificate. Browsers and GitHub do not trust it, so webhooks from github.com will not be delivered. |
PUBLIC_URL is always https; the API refuses to start in production with an http URL.
Ports ​
Only caddy publishes ports (HTTP_PORT, HTTPS_PORT). PostgreSQL and Valkey are only reachable on the internal Compose network.
Secrets and backups ​
deploy/compose/secrets/ contains:
| File | Content |
|---|---|
postgres_superuser_password | PostgreSQL superuser password (hex) |
quavon_migrator_password, quavon_app_password, quavon_system_password | Role passwords (hex) |
database_admin_url, database_migrator_url, database_url, database_system_url | Connection URLs built from the passwords |
valkey_password, valkey_url | Valkey password and URL |
encryption_key | 32-byte key (base64) that encrypts GitHub App credentials, LLM keys and session tokens |
sandbox_signing_key, valkey_sandbox_*, valkey_egress_* | Sandbox runner signing key and Valkey ACL users (see sandbox.md) |
dex_client_secret, dex_ldap_bind_password, dex_oidc_client_secret | Optional Dex broker: client secret generated by the installer; the two connector secrets stay empty until you fill them (see oidc.md) |
The directory is mode 0700 so only the installing user can list it; the files are 0644 because Compose mounts them into non-root containers. Keep the host account restricted.
Back up deploy/compose/secrets/ and deploy/compose/.env together with the database, and store the backup encrypted and off the host. Commands and the restore procedure are in backup.md. Without encryption_key the encrypted data cannot be recovered; without the passwords the existing database volume cannot be opened. Never delete a single secret file: the installer refuses to regenerate a missing password or key while other secrets exist.
E-mail (SMTP) ​
E-mail notifications need an SMTP server; without one, e-mail channels are unavailable and the other channels still work. The installer does not manage these settings. Add them to api and worker with a Compose override file next to docker-compose.yml, and keep the password in a secret file:
# deploy/compose/docker-compose.override.yml
services:
api: &smtp
environment:
QUAVON_SMTP_HOST: smtp.<your-domain>
QUAVON_SMTP_PORT: '587'
QUAVON_SMTP_SECURITY: starttls
QUAVON_SMTP_FROM: codelotse@<your-domain>
QUAVON_SMTP_USERNAME: <smtp-user>
QUAVON_SMTP_PASSWORD_FILE: /run/secrets/smtp_password
secrets: [smtp_password]
worker: *smtp
secrets:
smtp_password:
file: ./secrets/smtp_passwordWrite the password to secrets/smtp_password (<smtp-password>, mode 0644 like the other secret files) and restart with docker compose -p quavon up -d from deploy/compose. The variables are described in notifications.md.
First login ​
Until setup is done, the base URL shows a Finish setup screen instead of the sign-in. It shows the commands that create a setup link; the screen itself cannot start the setup. Once a sign-in option exists (the GitHub App or an OIDC provider) or an instance admin exists, the base URL shows the sign-in.
- Open the setup link printed by the installer (or create a new one with
quavon setup-token; on Kubernetes see kubernetes.md). The link is valid for one hour and works once. - Create the GitHub App from the manifest (it is named
CodeLotse; GitHub lets you change the name if it is taken) and install it on your organisation. - Sign in with GitHub. The first login with the setup session becomes instance admin.
- Run
./deploy/compose/quavon doctor. Remaining warnings are explained in doctor.md and troubleshooting.md.
Upgrading ​
Re-run the installer from a newer checkout after taking a backup. The full procedure, the migration policy, the supported upgrade paths and the notes for releases that still used the Quavon name are in upgrade.md.
Operations ​
See operations.md for break-glass access, key rotation and logs, sandbox.md for the sandbox runner, and assignment.md for reviewer and assignee suggestions.
More guides (index: docs/README.md):
- upgrade.md and backup.md: upgrades, backup and restore
- troubleshooting.md: symptoms and doctor codes
- ghes.md: GitHub Enterprise Server
- models.md: model credentials, endpoint presets and model routing
- air-gap.md: air-gapped and restricted networks, private model endpoints
- oidc.md: sign-in with a generic OIDC provider or the bundled Dex broker
- kubernetes.md: Helm chart, air-gapped installs and the Kubernetes sandbox backend
- observability.md: metrics, traces, dashboards and alerts
- telemetry.md: optional product telemetry (off by default)
- analytics.md: team analytics, costs and budget alerts
- dsar.md: exporting and deleting personal data
- providers.md: GitLab and Azure DevOps connections; the feature parity matrix lists what each code host supports
- trackers.md: work trackers: Jira, Linear, Azure Boards
- notifications.md: Slack, Microsoft Teams, e-mail and webhook notifications
- code-index.md: the persistent code index, pgvector and its limits