Skip to content

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 ​

ItemMinimum
Docker Engine24 or newer, daemon reachable by the installing user
Docker Composev2 plugin (docker compose version)
CPU / memory (as seen by Docker)2 CPUs, 4 GiB (warning below)
Free disk on the installation directory20 GiB (warning below)
Tools on the hostPOSIX sh, openssl (or /dev/urandom with od, dd, base64), curl for the clock check, ss, lsof or nc for the port check
NetworkInbound on the published HTTP/HTTPS ports; outbound HTTPS to GitHub (github.com or your GHES host)
ClockSynchronised (NTP). GitHub rejects app JWTs from hosts whose clock is off

Quick start ​

sh
git clone <quavon-repository-url> quavon && cd quavon
./deploy/compose/quavon install --domain quavon.example.com --email ops@example.com

Without 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/.

OptionMeaning
--domain NAMEPublic host name. PUBLIC_URL becomes https://NAME (plus :PORT if --https-port is not 443)
--tls acme|provided|internalTLS mode, default acme
--email ADDRESSACME account contact, required for acme
--cert FILE, --key FILEPEM certificate chain and key, required for provided
--http-port PORT, --https-port PORTPublished ports, default 80 and 443
--github-url URLhttps://github.com (default) or the origin of a GitHub Enterprise Server
--sandboxEnable the sandbox runner for deterministic checks; needs gVisor runsc registered with Docker (see sandbox.md)
--yesNon-interactive

What the installer does:

  1. Preflight: Docker and Compose versions, free ports (skipped while the stack's caddy is 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's Date header (warning above 30 s). Every failed requirement is listed with a fix before the installer stops; nothing is changed until all requirements pass.
  2. Secrets: creates deploy/compose/secrets/ (mode 0700) and every missing secret file (mode 0644). Existing files are never overwritten.
  3. 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.
  4. Start: docker compose up -d --build, then waits (up to 600 s, QUAVON_WAIT_TIMEOUT overrides) until postgres, valkey, api, worker and caddy are healthy and the one-shot init service (roles and migrations) has completed.
  5. 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-token when 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 &ZeroWidthSpace;

ModeUseNotes
acmePublic serversCaddy obtains and renews certificates automatically. The domain must resolve to this host and ports 80 and 443 must be reachable from the internet.
providedCertificates from your own CATLS_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.
internalEvaluation, local networksCaddy'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 &ZeroWidthSpace;

Only caddy publishes ports (HTTP_PORT, HTTPS_PORT). PostgreSQL and Valkey are only reachable on the internal Compose network.

Secrets and backups &ZeroWidthSpace;

deploy/compose/secrets/ contains:

FileContent
postgres_superuser_passwordPostgreSQL superuser password (hex)
quavon_migrator_password, quavon_app_password, quavon_system_passwordRole passwords (hex)
database_admin_url, database_migrator_url, database_url, database_system_urlConnection URLs built from the passwords
valkey_password, valkey_urlValkey password and URL
encryption_key32-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_secretOptional 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) &ZeroWidthSpace;

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:

yaml
# 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_password

Write 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 &ZeroWidthSpace;

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.

  1. 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.
  2. 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.
  3. Sign in with GitHub. The first login with the setup session becomes instance admin.
  4. Run ./deploy/compose/quavon doctor. Remaining warnings are explained in doctor.md and troubleshooting.md.

Upgrading &ZeroWidthSpace;

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 &ZeroWidthSpace;

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):

The open core is released under the Apache License 2.0.