Avnology ID
Self-Hosting

Docker Compose Deploy

Step-by-step walkthrough for `docker compose -f docker-compose.traefik.yml up -d`.

Docker Compose Deploy

The production compose file lives at the repo root: docker-compose.traefik.yml. It wires up 19 services behind Traefik, exposes only 80/443 on the host, and sources every secret from the environment.

Prerequisites

  • Docker Engine 25+ with the Compose V2 plugin.
  • A host with at least 4 vCPU / 8 GiB RAM (see Overview).
  • Public DNS records in place (see DNS setup).
  • Outbound network to ghcr.io for images, acme-v02.api.letsencrypt.org for TLS.

Step 1: Clone the repo (or pull the release tarball)

git

Only docker-compose.traefik.yml and deploy/docker/ are needed at runtime -- the services/, apps/, packages/ source trees ship inside the container images.

Step 2: Copy the env template

cp .env.example .env.production
$EDITOR .env.production

At minimum you must set:

  • DOMAIN_API, DOMAIN_WEB, DOMAIN_DOCS, DOMAIN_POLIS, DOMAIN_SAML, DOMAIN_GRAFANA, DOMAIN_MINIO
  • POSTGRES_PASSWORD + the four per-service Postgres passwords
  • HYDRA_SYSTEM_SECRET, KRATOS_COOKIE_SECRET, KRATOS_CIPHER_SECRET
  • VALKEY_PASSWORD, MINIO_ROOT_USER, MINIO_ROOT_PASSWORD
  • SMTP_CONNECTION_URI, SMTP_FROM_ADDRESS

See Environment variables for the full reference.

Step 3: Bring the stack up

docker compose -f docker-compose.traefik.yml --env-file .env.production up -d

First boot takes ~2 minutes. docker compose ps should show every service healthy:

NAME                           STATUS
avnology-postgres              Up (healthy)
avnology-valkey                Up (healthy)
avnology-nats                  Up (healthy)
avnology-minio                 Up (healthy)
avnology-pgbouncer             Up (healthy)
avnology-kratos                Up (healthy)
avnology-hydra                 Up (healthy)
avnology-keto                  Up (healthy)
avnology-oathkeeper            Up (healthy)
avnology-polis                 Up (healthy)
avnology-gateway               Up (healthy)
avnology-audit                 Up (healthy)
avnology-risk                  Up (healthy)
avnology-webhook               Up (healthy)
avnology-saml                  Up (healthy)
avnology-web                   Up (healthy)
avnology-docs                  Up (healthy)

Step 4: Verify the public endpoints

curl -I https://$DOMAIN_API/healthz         # gateway
curl -I https://$DOMAIN_WEB/                # web dashboard
curl -I https://$DOMAIN_DOCS/               # docs

All three should return 200 OK with valid TLS.

Step 5: Create the first admin user

Use the built-in admin bootstrap endpoint (only runs when zero identities exist):

curl -X POST "https://$DOMAIN_API/v1/admin/bootstrap" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "..."
  }'

Once the first identity exists the bootstrap endpoint is disabled.

Next steps