Compose reference
The release bundle ships deploy/compose.yml and deploy/.env.example. As shipped, compose.yml is the evaluation stack: it includes three evaluation fixtures and publishes the database and api ports next to the UI. A production install layers an override file on top that publishes app-ui only (see Overrides).
Services
Section titled “Services”| Service | Image | Depends on | Health check | Restart |
|---|---|---|---|---|
db |
postgres:16-alpine |
none | pg_isready |
unless-stopped |
migrator |
bookend/migrator |
db healthy |
none; exits 0 when every script is applied | no |
api |
bookend/api |
migrator completed successfully; inference healthy (and, as shipped, the three evaluation fixtures healthy) |
GET /readyz (database and schema) |
unless-stopped |
inference |
bookend/inference |
none | GET /healthz |
unless-stopped |
app-ui |
bookend/app-ui |
api healthy |
GET /nginx-health |
unless-stopped |
jxchange-mock, metering-mock |
bookend/jxchange-mock |
none | GET /healthz |
unless-stopped |
mailhog |
mailhog/mailhog:v1.0.1 |
none | MailHog API | unless-stopped |
jxchange-mock (a stand-in core), metering-mock (an in-stack heartbeat receiver) and mailhog (an SMTP server with a web mailbox) exist for evaluation. A production install keeps them from starting with the override below. Image tags come from BOOKEND_VERSION.
Environment (deploy/.env)
Section titled “Environment (deploy/.env)”| Variable | Meaning |
|---|---|
DB__PROVIDER |
postgres (default) or sqlserver |
POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD |
bundled database name and owner principal (the migrator runs as it); the password is required |
DB_APP_USER, DB_APP_PASSWORD |
least-privilege application principal, created by the migrator with exactly this password; the password is required |
DB__CONNECTION, DB__MIGRATOR_CONNECTION |
connection strings for an external database. With the bundled database compose.yml builds both itself (host db); an external database needs the override below |
BOOKEND_MASTER_KEY |
base64 of 32 random bytes; encrypts secrets in settings. Keep it in your vault; never use the example value |
BOOKEND_VERSION |
image tag: the release version you loaded (defaults to dev) |
BOOKEND_SKIP_SCRIPTS |
908_seed_demo_users.sql on a production install, so the two evaluation user accounts are never created |
BOOKEND_UI_PORT (8081), BOOKEND_API_PORT (8080), BOOKEND_DB_PORT (5432), BOOKEND_MAILHOG_PORT (8025) |
host ports; only the UI port is published in production |
BOOKEND_LOGIN_ATTEMPTS_PER_MINUTE |
per-address login limit as compose.yml sets it (60 for automated test runs); the production override sets 10 |
Proxy__TrustedNetworks |
comma-separated networks whose X-Forwarded-For / X-Forwarded-Proto the api honors (default: the private ranges and loopback) |
A value a compose file sets under a service’s environment: wins over the same name in .env, which is why connection strings and the login limit are changed in override files rather than in .env.
Everything else (SMTP, core adapter, tolerances, reason codes, retention, metering) lives in the settings table and is configured through the wizard or Settings.
Volumes
Section titled “Volumes”dbdata (bundled Postgres), documents (content-addressed files, rendered pages), exports (boarding files, wire requests), watch (watch-folder intake), modelcache (inference scratch). Compose prefixes them with the project name: bookend_documents, and so on.
Overrides
Section titled “Overrides”The Installation Guide gives both files in full.
compose.production.yml: withdraws thedbandapihost ports (ports: !reset []), movesjxchange-mock,metering-mockandmailhoginto anevaluationprofile and drops them from the api’s start conditions (depends_on: !override), setsRateLimiting__LoginAttemptsPerMinuteto 10, and mounts the license public key forLicensing__PublicKeyPath. Requires Compose v2.24.4 or later.compose.external-db.yml: movesdbinto a profile so it does not start, removes the migrator’s dependency on it, and passesDB__CONNECTION/DB__MIGRATOR_CONNECTIONfrom.envto the migrator and api. For SQL Server also setDB__PROVIDER=sqlserver.
Air-gapped operation needs no override: it is a setting (metering.air_gapped), see Air-gapped operations.
Commands
Section titled “Commands”DC="docker compose -f deploy/compose.yml -f deploy/compose.production.yml"$DC up -d --wait # start everything, wait for healthy$DC ps -a # state per service (the migrator shows Exited (0))$DC logs --since 30m api # structured logs$DC cp validation-pack/golden-packages/BK-DEMO-001 api:/data/watch/ # watch-folder intake from the bundle root,$DC exec -u root api chown -R app:app /data/watch # then hand the copy to the api's user$DC down # stop; volumes are kept (never add -v on a live install)