# Self-hosted Authentik IdP stack pinned at 2026.2.3 (see UPSTREAM.md). # # Four services on an internal `authentik-net` network, with the `server` # service additionally attached to the Coolify-managed `coolify` external # network so Traefik can route inbound HTTPS to it (see traefik.labels.yml # for the Traefik label-set — those labels are applied at the operator's # Coolify-service level rather than inline here, so this file stays portable # between staging and any future dedicated-host deployment). # # Postgres + Redis are strictly Authentik-internal — never share with the # boilerplate app's databases. No `ports:` mappings anywhere; ingress is # Traefik-only. # # Volume convention: named volumes are managed by Docker; on staging Coolify # binds them under /var/lib/docker/volumes/authentik_*. The backup container # (see infra/authentik/backup/) reads from the same network. version: "3.8" # ---------------------------------------------------------------------------- # Networks # ---------------------------------------------------------------------------- networks: authentik-net: name: authentik-net driver: bridge coolify: external: true # ---------------------------------------------------------------------------- # Volumes # ---------------------------------------------------------------------------- volumes: authentik-pg-data: name: authentik-pg-data authentik-redis-data: name: authentik-redis-data authentik-media: name: authentik-media authentik-certs: name: authentik-certs authentik-templates: name: authentik-templates # ---------------------------------------------------------------------------- # Services # ---------------------------------------------------------------------------- services: # --- Postgres 16 --------------------------------------------------------- postgresql: image: postgres:16-alpine restart: unless-stopped networks: - authentik-net healthcheck: test: ["CMD-SHELL", "pg_isready -U ${AUTHENTIK_POSTGRESQL__USER:-authentik} -d ${AUTHENTIK_POSTGRESQL__NAME:-authentik}"] start_period: 20s interval: 30s retries: 5 timeout: 5s volumes: - authentik-pg-data:/var/lib/postgresql/data environment: POSTGRES_USER: ${AUTHENTIK_POSTGRESQL__USER:-authentik} POSTGRES_PASSWORD: ${AUTHENTIK_POSTGRESQL__PASSWORD:?must be set in .env} POSTGRES_DB: ${AUTHENTIK_POSTGRESQL__NAME:-authentik} # --- Redis 7 ------------------------------------------------------------- redis: image: redis:7-alpine command: --save 60 1 --loglevel warning restart: unless-stopped networks: - authentik-net healthcheck: test: ["CMD-SHELL", "redis-cli ping | grep PONG"] start_period: 10s interval: 30s retries: 5 timeout: 3s volumes: - authentik-redis-data:/data # --- Authentik server (web/api/HTTP) ------------------------------------ server: image: ghcr.io/goauthentik/server:2026.2.3 restart: unless-stopped command: server networks: - authentik-net - coolify healthcheck: # Authentik exposes /-/health/live/ + /-/health/ready/ on port 9000. # We use `wget` (image ships busybox-wget); fallback to curl if wget is # missing in a future image. test: - "CMD-SHELL" - "wget -qO- http://localhost:9000/-/health/live/ >/dev/null 2>&1 || curl -fsS http://localhost:9000/-/health/live/ >/dev/null 2>&1 || exit 1" start_period: 60s interval: 30s retries: 5 timeout: 10s environment: AUTHENTIK_REDIS__HOST: redis AUTHENTIK_POSTGRESQL__HOST: postgresql AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRESQL__USER:-authentik} AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRESQL__NAME:-authentik} AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRESQL__PASSWORD:?must be set in .env} AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?must be set in .env} AUTHENTIK_ERROR_REPORTING__ENABLED: ${AUTHENTIK_ERROR_REPORTING__ENABLED:-false} AUTHENTIK_LOG_LEVEL: ${AUTHENTIK_LOG_LEVEL:-info} AUTHENTIK_DISABLE_UPDATE_CHECK: ${AUTHENTIK_DISABLE_UPDATE_CHECK:-true} AUTHENTIK_DISABLE_STARTUP_ANALYTICS: ${AUTHENTIK_DISABLE_STARTUP_ANALYTICS:-true} AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD:-} AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL:-} AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN:-} AUTHENTIK_COOKIE_DOMAIN: ${AUTHENTIK_COOKIE_DOMAIN:-} # Internal SSL OFF — TLS is terminated by Traefik in front. AUTHENTIK_LISTEN__HTTP: 0.0.0.0:9000 AUTHENTIK_LISTEN__HTTPS: 0.0.0.0:9443 # Optional Sentry integration (Phase 02 #29 DSN goes here). AUTHENTIK_SENTRY__DSN: ${AUTHENTIK_SENTRY__DSN:-} AUTHENTIK_SENTRY__ENVIRONMENT: ${AUTHENTIK_SENTRY__ENVIRONMENT:-staging} # Optional SMTP for recovery mails. AUTHENTIK_EMAIL__HOST: ${AUTHENTIK_EMAIL__HOST:-} AUTHENTIK_EMAIL__PORT: ${AUTHENTIK_EMAIL__PORT:-587} AUTHENTIK_EMAIL__USERNAME: ${AUTHENTIK_EMAIL__USERNAME:-} AUTHENTIK_EMAIL__PASSWORD: ${AUTHENTIK_EMAIL__PASSWORD:-} AUTHENTIK_EMAIL__USE_TLS: ${AUTHENTIK_EMAIL__USE_TLS:-true} AUTHENTIK_EMAIL__USE_SSL: ${AUTHENTIK_EMAIL__USE_SSL:-false} AUTHENTIK_EMAIL__TIMEOUT: ${AUTHENTIK_EMAIL__TIMEOUT:-10} AUTHENTIK_EMAIL__FROM: ${AUTHENTIK_EMAIL__FROM:-authentik@boiler.saas-ctrl.com} volumes: - authentik-media:/media - authentik-certs:/certs - authentik-templates:/templates # Blueprints baked into the image are loaded automatically. Operator # mounts the project blueprints over the default path during bootstrap # (see infra/authentik/bootstrap/bootstrap.sh). - ./bootstrap/blueprints:/blueprints/toolctrl:ro depends_on: postgresql: condition: service_healthy redis: condition: service_healthy # NO `ports:` — Traefik routes inbound on the `coolify` network. # --- Authentik worker (background jobs, blueprint apply, email) --------- worker: image: ghcr.io/goauthentik/server:2026.2.3 restart: unless-stopped command: worker networks: - authentik-net healthcheck: test: ["CMD-SHELL", "ak healthcheck"] start_period: 60s interval: 30s retries: 5 timeout: 30s # Worker needs the docker socket only if you intend to manage Outposts # via Docker. We don't ship Outposts in this phase, so the socket is # intentionally NOT mounted. If a future phase enables Outposts, mount # /var/run/docker.sock:/var/run/docker.sock:ro then. environment: AUTHENTIK_REDIS__HOST: redis AUTHENTIK_POSTGRESQL__HOST: postgresql AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRESQL__USER:-authentik} AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRESQL__NAME:-authentik} AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRESQL__PASSWORD:?must be set in .env} AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?must be set in .env} AUTHENTIK_ERROR_REPORTING__ENABLED: ${AUTHENTIK_ERROR_REPORTING__ENABLED:-false} AUTHENTIK_LOG_LEVEL: ${AUTHENTIK_LOG_LEVEL:-info} AUTHENTIK_DISABLE_UPDATE_CHECK: ${AUTHENTIK_DISABLE_UPDATE_CHECK:-true} AUTHENTIK_DISABLE_STARTUP_ANALYTICS: ${AUTHENTIK_DISABLE_STARTUP_ANALYTICS:-true} AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD:-} AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL:-} AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN:-} AUTHENTIK_SENTRY__DSN: ${AUTHENTIK_SENTRY__DSN:-} AUTHENTIK_SENTRY__ENVIRONMENT: ${AUTHENTIK_SENTRY__ENVIRONMENT:-staging} AUTHENTIK_EMAIL__HOST: ${AUTHENTIK_EMAIL__HOST:-} AUTHENTIK_EMAIL__PORT: ${AUTHENTIK_EMAIL__PORT:-587} AUTHENTIK_EMAIL__USERNAME: ${AUTHENTIK_EMAIL__USERNAME:-} AUTHENTIK_EMAIL__PASSWORD: ${AUTHENTIK_EMAIL__PASSWORD:-} AUTHENTIK_EMAIL__USE_TLS: ${AUTHENTIK_EMAIL__USE_TLS:-true} AUTHENTIK_EMAIL__USE_SSL: ${AUTHENTIK_EMAIL__USE_SSL:-false} AUTHENTIK_EMAIL__TIMEOUT: ${AUTHENTIK_EMAIL__TIMEOUT:-10} AUTHENTIK_EMAIL__FROM: ${AUTHENTIK_EMAIL__FROM:-authentik@boiler.saas-ctrl.com} volumes: - authentik-media:/media - authentik-certs:/certs - authentik-templates:/templates - ./bootstrap/blueprints:/blueprints/toolctrl:ro depends_on: postgresql: condition: service_healthy redis: condition: service_healthy