Skip to content
ABRQ DATADocs Abrq DIP · latest
Product page Request a trial
On this page

Docker Compose Deployment

Two compose files ship in the repository root:

  • docker-compose.prod.yml — a production-shaped single-host stack: PostgreSQL, Redis, a one-shot migrator, the API, Celery workers, Celery beat, and the SPA behind nginx.
  • docker-compose.dev.yml — the development stack for working on Abrq DIP itself.

For offline installs from the vendor-shipped bundle (pre-built image tarballs, no build step), see air-gapped installation — it is the offline variant of this path.

Dev vs prod at a glance#

Aspect docker-compose.dev.yml docker-compose.prod.yml
ABRQ_ENV dev (license check bypassed, relaxed guards) prod (license verified at startup, HSTS on)
Images Dev images with the backend source bind-mounted; hot reload Production multi-stage images built from backend/Dockerfile and frontend/Dockerfile
Migrations Backend container runs alembic upgrade head inline before starting uvicorn Dedicated one-shot migrator service; app services wait for its successful completion
PostgreSQL Port 5432 published to the host; init scripts also create a source_demo fixture database No published port; data on a named volume only
Redis Loopback-only published port (127.0.0.1:6379), no auth No published port, --requirepass enforced (REDIS_PASSWORD required), AOF persistence
Secrets Baked-in dev defaults (master key, JWT secret, DB password) Must come from .env; several have fail-fast guards
Worker One worker, concurrency 2 ${ABRQ_WORKER_REPLICAS:-2} replicas, concurrency ${ABRQ_CELERY_CONCURRENCY:-4}, 60s stop grace
Beat schedule state Throwaway (/tmp) beat_state named volume; replicas: 1 pinned
Frontend Vite dev server on port 5173 nginx on ${ABRQ_FRONTEND_PORT:-8080}:80
Backups dir init backup_dir_init one-shot fixes ownership of the backups bind-mount

Both stacks bind-mount ./backups (override with ABRQ_BACKUP_HOST_DIR in prod) into the containers at /var/abrq-dip/backups — a host bind-mount, not a named volume, precisely so docker compose down -v cannot wipe your backups.

Note. In both compose files the datastore database (CDC mirror landings) is named datastore, created by the init scripts in docker/postgres-init/. The Helm chart names the same database abrq_dip_datastore — the two paths are not drop-in interchangeable at the database level.

Production walkthrough#

1. Prepare .env#

Compose interpolates variables from a .env file next to the compose file. Required — the stack fails fast with a named error if a guarded variable is unset:

Variable Guarded Purpose
POSTGRES_PASSWORD no guard — do not leave unset Password for the bundled PostgreSQL and the app connection URLs.
REDIS_PASSWORD yes: set REDIS_PASSWORD in your .env — the prod broker must require auth Redis --requirepass value, wired into ABRQ_REDIS_URL.
ABRQ_MASTER_KEY no guard — required by the backend at startup Fernet master key.
ABRQ_JWT_SECRET no guard — required by the backend at startup Session-token signing secret.
ABRQ_INITIAL_ADMIN_PASSWORD yes: override the default admin password First-boot admin seed; production refuses the literal default.
ABRQ_CORS_ALLOWED_ORIGINS yes: set the SPA origin(s) for CORS Exact UI origin(s), comma-separated.

Optional knobs: ABRQ_GUNICORN_WORKERS (default 2), ABRQ_CELERY_CONCURRENCY (default 4), ABRQ_WORKER_REPLICAS (default 2), ABRQ_FRONTEND_PORT (default 8080), ABRQ_BACKUP_HOST_DIR (default ./backups). Generation commands for the secrets are in choosing a deployment path.

2. Place the license file#

Production startup verifies the vendor-signed license. Make license.json available at ABRQ_LICENSE_FILE (default /var/abrq-dip/license.json) inside the backend, worker, and beat containers — see installing a license. (The vendor release bundle's compose file wires this mount for you; see air-gapped installation.)

3. Build and start#

docker compose -f docker-compose.prod.yml up -d --build

Startup order is dependency-driven: PostgreSQL and Redis become healthy; the one-shot migrator applies alembic upgrade head and exits 0; the one-shot backup_dir_init fixes ownership of the backups directory (Docker auto-creates missing bind-mount directories as root, but the app runs as uid 1000 — without this fix, the default-on auto-backup would fail with a permission error on every fresh install); then backend, workers, beat, and frontend start.

docker compose -f docker-compose.prod.yml ps
docker compose -f docker-compose.prod.yml logs -f backend

4. Retrieve the initial admin password file#

On first boot against an empty users table, the backend seeds the initial admin user and writes the password to a file (mode 0600) at ABRQ_INITIAL_PASSWORD_FILE (default /var/abrq-dip/initial-password.txt, on the initial_password named volume):

docker compose -f docker-compose.prod.yml exec backend \
  cat /var/abrq-dip/initial-password.txt

Open http://<HOST>:8080 (or your ABRQ_FRONTEND_PORT), log in, and complete the forced password change.

Health checks#

Every long-running service carries a compose healthcheck; depends_on conditions chain them so the stack comes up in order.

Service Check Notes
framework_db pg_isready 5s interval.
redis authenticated redis-cli ping Uses REDIS_PASSWORD.
backend curl -fsS http://localhost:8000/health /health requires the framework DB and Redis to answer; 200 ok, 503 degraded.
worker celery inspect ping against the container's own worker Proves broker connectivity, not just a live process.
beat pgrep for the beat process Beat is a scheduler, not a consumer — there is no broker-side ping for it.
frontend none (prod) nginx serves static files and proxies /api to the backend service.

Failure modes#

Symptom Likely cause Fix
docker compose up aborts naming REDIS_PASSWORD, the admin password, or CORS A guarded variable is unset Fill in .env (see the table above) and re-run.
Backend exits immediately; logs show startup_config_error Missing/invalid ABRQ_MASTER_KEY or ABRQ_JWT_SECRET, or the admin password left at the literal default Set real values in .env; the log lists every problem found.
Backend exits; logs mention license_check_failed License file missing at /var/abrq-dip/license.json, invalid signature, or expired Place a valid license.json mount; see installing a license.
migrator exits non-zero Schema mismatch from a previous half-applied upgrade docker compose -f docker-compose.prod.yml logs migrator for the alembic error; see upgrade and rollback for the recovery path.
framework_db refuses connections after a re-install Old data volume initialized with a different POSTGRES_PASSWORD Either restore the old password, or docker compose down -v (destroys the database) and start fresh.
Auto-backup shows last_status=error in Settings Backups directory not writable by uid 1000 Confirm backup_dir_init ran (docker compose ps -a); fix ownership of ABRQ_BACKUP_HOST_DIR.
UI loads but API calls fail in the browser ABRQ_CORS_ALLOWED_ORIGINS does not exactly match the origin in the address bar Set the exact scheme, host, and port your users hit.

Development stack#

For contributors:

docker compose -f docker-compose.dev.yml up -d

Backend API on port 8000 with auto-reload, Vite frontend on port 5173, PostgreSQL exposed on 5432, Redis on loopback 6379. The postgres init scripts create the datastore database and a source_demo fixture database for trying CDC locally. Dev credentials are insecure by design; never expose this stack beyond your machine.