Skip to content

Docker Compose

calit ships a docker-compose.yml with two services: db (Postgres 18) and app (the calit server). The app is stateless — all shared state lives in Postgres — so the same file works for a single node or a scaled-out cluster.

services:
db:
image: postgres:18
environment:
POSTGRES_DB: ${DB_NAME:-calit}
POSTGRES_USER: ${DB_USER:-calit}
POSTGRES_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in .env}
volumes:
# postgres:18 default PGDATA is /var/lib/postgresql/18/docker — mount the parent so data persists
- calit-db:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-calit} -d ${DB_NAME:-calit}"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
app:
build: .
depends_on:
db:
condition: service_healthy
env_file:
- path: .env
required: false
environment:
DB_URL: jdbc:postgresql://db:5432/${DB_NAME:-calit}
DB_USER: ${DB_USER:-calit}
DB_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in .env}
ports:
- "${APP_PORT:-8080}:8080"
restart: unless-stopped
volumes:
calit-db:
WhatWhy it matters
build: .Builds from the local Dockerfile (Liberica JDK 26). See the prebuilt image variant below to skip the build step.
depends_on: condition: service_healthyThe app starts only after Postgres passes its pg_isready healthcheck, so Flyway migrations never race a cold DB.
env_file: .envAll secrets are loaded from .env. Marked required: false so docker compose config works on a fresh checkout without an .env file present.
DB_URL (derived)jdbc:postgresql://db:5432/${DB_NAME:-calit} is injected automatically — your .env only needs to carry DB_PASSWORD.
${APP_PORT:-8080}:8080The container always listens on 8080. Set APP_PORT in .env to expose a different host port.
Volume mount: /var/lib/postgresqlPostgres 18 changed its default PGDATA to /var/lib/postgresql/18/docker. Mounting the parent directory (/var/lib/postgresql) ensures data persists across container restarts regardless of the exact subdirectory used.

To use the published image from GitHub Container Registry instead of building locally, replace build: . in the app service:

app:
image: ghcr.io/asm0dey/calit:latest
depends_on:
db:
condition: service_healthy
env_file:
- path: .env
required: false
environment:
DB_URL: jdbc:postgresql://db:5432/${DB_NAME:-calit}
DB_USER: ${DB_USER:-calit}
DB_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in .env}
ports:
- "${APP_PORT:-8080}:8080"
restart: unless-stopped

calit is stateless — scale the app service horizontally behind your own load balancer:

Terminal window
docker compose up -d --scale app=3

Postgres is the single shared state store; no additional coordination is needed between replicas.

  1. Copy .env.example to .env and fill in your values — see the Configuration page for every variable.
  2. Start the stack:
Terminal window
docker compose up --build -d

On first boot, Flyway applies all database migrations automatically. Navigate to your APP_BASE_URL — if no users exist yet, you will be redirected to /setup to create the first admin account.