# Authentik — the homelab's SSO / OIDC provider Authentik is the single sign-on (SSO) and OpenID Connect (OIDC) provider for the homelab. It fronts the Caddy vhosts that do not carry their own application-level authentication. Apps that have their own login (Grafana, Gitea, OpenWebUI, Jellyfin, the *arr stack, Pi-hole) are not wrapped in forward_auth — they handle their own session. - **Version:** `2026.8.0` (pinned in `dankclaw/compose.yaml`) - **Host:** dankclaw (`192.168.0.143`) - **Name:** `auth.franksdank.cloud` - **Stack:** 3 compose services — `authentik-postgres`, `authentik-server`, `authentik-worker` (see [Pi-hole](Pi-hole.md) for the LAN-DNS pattern) ## Why Authentik The comparison that chose it (against Authelia, Keycloak, Zitadel, Ory) is in `.docaudit/research/auth.md`. In short: full OIDC with single-logout, a web GUI for all configuration, a native Caddy `forward_auth` outpost, and a footprint that fits on a 3-user homelab (~1–1.5 GB idle). Redis was removed in 2025.10, so the stack is 3 services, not 4. ## Architecture ```mermaid graph LR subgraph Browser U[User] end subgraph Caddy [Caddy - auth gate] FA[forward_auth] end subgraph AK [Authentik] SRV[server :9000] WKR[worker] PG[(postgres)] OUT[outpost /auth/caddy] end subgraph App [Target app] A1[SearXNG / Hermes / Prometheus
RomM / Copyparty / homepage] end U -->|1. GET /| FA FA -->|2. GET /outpost.../auth/caddy| OUT OUT -->|3. no session: 302 login| U U -->|4. login at auth.franksdank.cloud| SRV SRV --> PG WKR --> PG SRV -->|5. 2xx: session valid| FA FA -->|6. proxy with headers| A1 ``` 1. The browser hits a protected vhost (e.g. `search.franksdank.cloud`). 2. Caddy `forward_auth` clones the request to the Authentik outpost (`/outpost.goauthentik.io/auth/caddy`). 3. With no valid session, the outpost returns a `302` to the Authentik login page (`auth.franksdank.cloud`). 4. The user logs in at Authentik (email + password, TOTP/WebAuthn MFA, or an upstream provider). 5. On the next request the outpost returns `2xx`; Caddy copies the `X-Authentik-*` headers and proxies to the app. ## The three compose services | Service | Role | Image | |---|---|---| | `authentik-postgres` | PostgreSQL 16 (users, flows, sessions, events) | `docker.io/library/postgres:16-alpine` | | `authentik-server` | Core + admin API + the embedded Caddy outpost (port 9000) | `ghcr.io/goauthentik/server:2026.8.0` | | `authentik-worker` | Background tasks (event processing, provider sync, flows) | `ghcr.io/goauthentik/server:2026.8.0` | - **Postgres** is the only stateful store. Sessions, caching, and WebSockets moved to PostgreSQL in 2025.10 (Redis removed). - **Server** and **worker** run the same image; the `command` selects the role (`server` / `worker`). - The worker runs as `0:0` (rootless: container root maps to the host user that owns the data dir). - Data persists under `/home/dank/authentik/` (bind mounts, repo policy — no named volumes). ## Caddy integration The Caddyfile wraps the no-auth vhosts in a `route` block. The pattern (one example; the others are identical): ```caddyfile search.franksdank.cloud { route { # 1. The outpost path is proxied to Authentik (login UI + session). reverse_proxy /outpost.goauthentik.io/* authentik-server:9000 # 2. forward_auth checks the session before serving the app. forward_auth authentik-server:9000 { uri /outpost.goauthentik.io/auth/caddy copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name trusted_proxies private_ranges } # 3. The app. reverse_proxy 192.168.0.143:8081 } } ``` Vhosts protected by forward_auth: the homepage (`franksdank.cloud`, `www.franksdank.cloud`), SearXNG, Hermes, Prometheus, RomM, Copyparty. The `auth.franksdank.cloud` vhost proxies to the server directly (no forward_auth — it *is* the login). ## Configuration (secrets) Two secrets live in the host `.env` (git-ignored; placeholders in `.env.example`): - `AUTHENTIK_PG_PASS` — the PostgreSQL password. Generate: `openssl rand -base64 32`. - `AUTHENTIK_SECRET_KEY` — the server's signing key. Generate: `openssl rand -base64 48`. ## First-time setup 1. `./scripts/deploy.sh dankclaw` — pulls, starts the 3 services (postgres health-gated), reloads Caddy. 2. Open `https://auth.franksdank.cloud` — the initial setup wizard runs. It creates the superuser (email + password) and generates the DB schema. 3. In the admin interface: **Directory → Applications** → add a **Proxy** application (or an **OAuth2/OpenID Connect** provider) for each vhost you protect. The Caddy outpost reads the application's policy. 4. For apps with native OIDC (Grafana, Gitea, OpenWebUI): add an **OAuth2/OpenID Connect** provider, create the app with the correct redirect URI, and paste the `client_id` / `client_secret` into the app's SSO settings. ## Operations - **Health:** `https://auth.franksdank.cloud/-/health/` (the server healthcheck probes this). - **Logs:** `podman logs authentik-server` / `podman logs authentik-worker`. - **Backups:** `pg_dump` the `authentik-postgres` database (the single source of truth). The `/home/dank/authentik/` dir holds media + static files. - **Upgrades:** bump the image tag in `dankclaw/compose.yaml`, run `./scripts/deploy.sh dankclaw`. Authentik migrates the schema on startup. ## Failure modes | Symptom | Cause | Fix | |---|---|---| | Every vhost 502s at the outpost | `authentik-server` down | `podman logs authentik-server`; check postgres health | | Login loops (302 → login → 302) | `trusted_proxies` / `X-Forwarded-*` mismatch | Confirm Caddy sets `X-Forwarded-For`; the outpost trusts `private_ranges` | | "Invalid signature" on the outpost | `AUTHENTIK_SECRET_KEY` differs between server and worker | Both services read the same `.env` var; re-deploy | | Postgres "password authentication failed" | `AUTHENTIK_PG_PASS` changed after first init | Reset via `pg_ctl` or re-init the data dir | ## Cross-references - [Caddy](Caddy.md) — the reverse proxy that carries the forward_auth directives - [Pi-hole](Pi-hole.md) — the LAN DNS that resolves `auth.franksdank.cloud` - [Network Architecture](../Architecture/Network%20Architecture.md) — the flat naming scheme - Research: `.docaudit/research/auth.md` — the full provider comparison