Skip to content

0008. Authelia for single sign-on on admin pages

Status: accepted ยท Date: 2026-10-25

Context

Every admin app had its own login, or none: Dozzle, which can read the Docker socket, was open to anyone on the Wi-Fi at its port. The goal was one secure login for everything.

The two candidates were Authelia and Authentik:

  • Authelia: a single container with SQLite, configured from a YAML file.
  • Authentik: a server, a worker, PostgreSQL and Redis, mostly configured in its UI. It's more capable (a full identity provider), but heavier, and harder to keep as code.

Decision

  • Authelia 4.39 in its own stack. It's in front of admin routes through Traefik forward auth.
  • Two-factor for everyone. default_policy: deny, then two_factor for the admins group on *.domain.
  • One session cookie on the apex domain, so one login covers every subdomain.
  • Config is a template rendered from the vault. The password hash is argon2id, generated by Authelia's own CLI.
  • Admin ports bind to 127.0.0.1, so the LAN can't go around Authelia by using the port.
  • Fewer second logins. Sonarr, Radarr and Prowlarr use External authentication, and qBittorrent trusts Traefik's static IP only.
  • Jellyfin, Seerr and Audiobookshelf stay outside it. Their TV and phone apps call the API directly.

Consequences

  • Fails closed. If Authelia is down, Traefik can't find the middleware and admin routes return 404.
  • Without Authelia there is no login on those apps. The *arr apps' "External" mode trusts whatever reaches them. That's safe only because their ports are loopback-only and their routes go through Authelia. Their APIs still require keys.
  • Sessions live in memory. Restarting Authelia (for example after make env changes its config) logs everyone out.
  • No email server. Two-factor enrolment links are read from /data/notification.txt.
  • Some apps still log in twice. Portainer, Semaphore, AdGuard and Uptime Kuma keep their own logins as a second factor of control. That's deliberate for Portainer, which controls the Docker host.