Docker
The official image is z4jdev/z4j on Docker Hub. Multi-arch: linux/amd64 and linux/arm64. Pin to :{pkg.latest} for reproducible deploys; use :latest for “always the newest stable”.
Sources
- Docker Hub: https://hub.docker.com/r/z4jdev/z4j
- GitHub (compose files +
.env.example): https://github.com/z4jdev/z4j - Current release: v1.6.5 (released 2026-05-27)
Three compose recipes
Section titled “Three compose recipes”The z4jdev/z4j GitHub repo ships three compose files in the root. They use the same image - the runtime mode is selected by env vars, not by tag. Pick one:
| Compose file | Database | TLS | Use case |
|---|---|---|---|
docker-compose.yml | SQLite (bundled in image, persisted to volume) | none | Evaluation, homelab, single-team installs |
docker-compose.postgres.yml | PostgreSQL 18 (sidecar) | none | Production self-host - small to large teams |
docker-compose.caddy.yml | (overlay, layer on either of the above) | Caddy auto-HTTPS | Public-facing - get a real cert via Let’s Encrypt |
Recipe 1 - Evaluation (SQLite)
Section titled “Recipe 1 - Evaluation (SQLite)”git clone https://github.com/z4jdev/z4j.gitcd z4jcp .env.example .env # fill Z4J_SECRET, Z4J_SESSION_SECRETdocker compose up -ddocker compose logs -f z4j-brain # capture the first-boot setup URLThat’s it. The brain auto-creates ~/.z4j/z4j.db inside the image’s volume, runs alembic to head, and prints the setup URL.
Recipe 2 - Production self-host (PostgreSQL)
Section titled “Recipe 2 - Production self-host (PostgreSQL)”git clone https://github.com/z4jdev/z4j.gitcd z4jcp .env.example .env # fill POSTGRES_PASSWORD + Z4J_SECRET, Z4J_SESSION_SECRET, Z4J_PUBLIC_URL, Z4J_ALLOWED_HOSTSdocker compose -f docker-compose.postgres.yml up -ddocker compose -f docker-compose.postgres.yml logs -f z4j-brainThe PostgreSQL sidecar persists data to the z4j-postgres-data named volume. Take regular pg_dump snapshots; see backups.
Recipe 3 - Add auto-HTTPS (Caddy overlay)
Section titled “Recipe 3 - Add auto-HTTPS (Caddy overlay)”Layer the Caddy file on top of either compose stack:
docker compose -f docker-compose.yml -f docker-compose.caddy.yml up -d# or:docker compose -f docker-compose.postgres.yml -f docker-compose.caddy.yml up -dCaddy reads your domain from Z4J_PUBLIC_URL and provisions a Let’s Encrypt cert automatically. DNS A/AAAA records must point at the host first.
Single-container (no compose)
Section titled “Single-container (no compose)”Quick smoke test on a VM with no compose installed:
docker run -d --name z4j-brain \
-p 7700:7700 \
-v z4j-data:/root/.z4j \
-e Z4J_SECRET=$(openssl rand -hex 32) \
-e Z4J_SESSION_SECRET=$(openssl rand -hex 32) \
z4jdev/z4j:1.6.5
docker logs -f z4j-brain # capture setup URL
For Postgres add:
-e Z4J_DATABASE_URL=postgresql+asyncpg://z4j:pw@db:5432/z4j \For TLS, set Z4J_PUBLIC_URL=https://... and put a reverse proxy in front (Caddy, nginx, Cloudflare Tunnel, Traefik). The brain speaks plain HTTP internally; X-Forwarded-Proto is respected.
Image layout
Section titled “Image layout”- Base:
python:3.14-slim-trixie(Debian 13). - Multi-arch:
linux/amd64,linux/arm64. Built on GitHub Actions native runners (no QEMU emulation). - Size: ~63 MiB compressed, ~250 MiB uncompressed.
- Entry point:
z4j serve(FastAPI via Uvicorn). - Signal handling:
SIGTERMtriggers graceful shutdown.
Running migrations
Section titled “Running migrations”Migrations run automatically on container start (idempotent; safe on every boot). To run them manually:
docker exec -it z4j-brain z4j migrate upgrade headHealthcheck
Section titled “Healthcheck”healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:7700/api/v1/health"] interval: 30s timeout: 5s retries: 3Structured JSON to stdout (one event per line). Aggregate with your log shipper (Loki, Vector, Fluentd, CloudWatch).
First boot
Section titled “First boot”Watch stdout on first boot to capture the setup banner:
docker compose logs -f z4j-brain | grep -A 10 "first-boot setup"Or skip the interactive setup entirely with bootstrap env vars:
Z4J_BOOTSTRAP_ADMIN_PASSWORD=<long random>The brain provisions the admin and the setup banner is suppressed.
Upgrades
Section titled “Upgrades”In-place. Bump the image tag, redeploy, restart. Migrations auto-run on boot.
docker compose pulldocker compose up -dTo roll back, redeploy the previous version tag. Schema changes are forward-compatible across patch versions but always test in staging first.