# Authelia – SSO mit Passkey-Unterstützung **Zusammenfassung**: Authelia als ForwardAuth-Provider für Traefik. Ermöglicht Single Sign-On (SSO) für alle Dienste hinter Traefik – mit Passwort, Passkey (WebAuthn/FIDO2) oder beidem. **Status**: ✅ aktiv – Gitea-Login via OIDC funktioniert, Passkey-Config aktualisiert **Zuletzt aktualisiert**: 2026-06-19 (Live-Daten 21:30) --- ## Architektur ``` Browser ──HTTPS──▶ Traefik (:443) │ ▼ (ForwardAuth-Middleware) Authelia ───▶ Session-Check │ ┌───────┴──────────┐ ▼ ▼ Unauthenticated Authenticated │ │ Login-Seite Weiterleitung zum (auth.*) eigentlichen Dienst ``` - Authelia läuft als **eigener Docker-Container** im `traefik`-Netzwerk - Traefik fragt bei jedem Request via **ForwardAuth-Middleware** bei Authelia an: - „Ist dieser Benutzer eingeloggt und darf auf diese Domain?“ - Bei **Nein** → Redirect zu `auth.da.home-webserver.de` - Bei **Ja** → Request geht zum eigentlichen Dienst - **Passkeys (WebAuthn)** werden von Authelia nativ unterstützt – als 2FA oder passwordless --- ## Stack: `/opt/compose/authelia/` ### compose.yml ```yaml services: authelia: image: authelia/authelia:latest container_name: authelia restart: unless-stopped networks: - traefik volumes: - ./config:/config environment: - TZ=Europe/Berlin networks: traefik: external: true ``` > **Hinweis**: Authelia wird **ohne** Traefik-Labels betrieben, damit es nicht sich selbst durch die ForwardAuth-Middleware blockiert. Stattdessen bekommt es eine eigene Route im File Provider. --- ## Konfiguration ### `config/configuration.yml` ```yaml ############################################################### # Authelia Konfiguration (v4.39+) ############################################################### # Server-Adresse (ersetzt host + port) server: address: tcp://0.0.0.0:9091 # Logging log: level: info # Speicher – SQLite mit encryption_key (Pflicht seit v4.38) storage: encryption_key: # 32 Byte Hex für SQLite-Verschlüsselung local: path: /config/db.sqlite3 # Authentifizierungs-Backend (file-basiert) authentication_backend: file: path: /config/users.yml password: algorithm: argon2id iterations: 3 salt_length: 16 parallelism: 4 memory: 65536 # KiB = 64 MiB (muss mit CLI-Default übereinstimmen) # Passkey (WebAuthn) – Hauptfeature # Passwordless-Login ist automatisch aktiv, sobald ein Passkey registriert wurde webauthn: enable_passkey_login: true # Neue v4.39-Option attestation_conveyance_preference: 'direct' # Auf direct geändert (19.06.) filtering: prohibit_backup_eligibility: true metadata: enabled: true # Metadata-Validierung aktiv (19.06.) validate_trust_anchor: true validate_entry: true validate_status: true validate_entry_permit_zero_aaguid: false timeout: 60s display_name: RaspiPI5 Authelia # Zugriffsregeln access_control: default_policy: deny rules: - domain: "auth.da.home-webserver.de" policy: bypass - domain: "cloud.da.home-webserver.de" policy: bypass - domain: "office.da.home-webserver.de" policy: bypass - domain: "git.da.home-webserver.de" policy: bypass # Gitea: OIDC - domain: "traefik.da.home-webserver.de" policy: two_factor - domain: "prometheus.da.home-webserver.de" policy: two_factor - domain: "*.da.home-webserver.de" policy: one_factor # Session-Konfiguration session: name: authelia_session secret: expiration: 8h inactivity: 2h remember_me: 30d cookies: - domain: da.home-webserver.de authelia_url: https://auth.da.home-webserver.de # Regulation – Schutz vor Brute-Force regulation: max_retries: 5 find_time: 2m ban_time: 5m # 2FA (TOTP) – optional totp: issuer: RaspiPI5 period: 30 skew: 1 # Notifier (Datei, da kein SMTP) notifier: filesystem: filename: /config/notifications.yml # Passwort-Reset identity_validation: reset_password: jwt_secret: ``` ### `config/users.yml` ```yaml users: dial: password: displayname: "Dial" email: dial-master@gmx.de groups: - admins ``` Passwort-Hash erzeugen: ```bash # Argon2id-Hash generieren (Default-Variante) docker run --rm authelia/authelia:latest authelia crypto hash generate argon2 --password 'DeinPasswort' # Mit expliziter Variante (optional): # docker run --rm authelia/authelia:latest authelia crypto hash generate argon2 --variant argon2id --password 'DeinPasswort' ``` --- ## Traefik File Provider: Middleware ### Neue Datei: `/opt/compose/traefik/conf.d/0020-authelia-middleware.yml` ```yaml http: middlewares: # Standard-Auth-Middleware für alle Dienste chain-authelia: chain: middlewares: - security-headers - authelia-forwardauth authelia-forwardauth: forwardAuth: address: http://authelia:9091/api/verify?rd=https://auth.da.home-webserver.de/ trustForwardHeader: true authResponseHeaders: - Remote-User - Remote-Groups - Remote-Name - Remote-Email ``` > Die Datei heißt `0020-` damit sie zwischen den globalen (`0000-`, `0010-`) und den Service-Routen (`0100-` …) einsortiert wird. --- ## Authelia-Route: `conf.d/0015-authelia-service.yml` Authelia selbst muss erreichbar sein, **ohne** durch ForwardAuth geschützt zu werden: ```yaml http: routers: authelia: rule: "Host(`auth.da.home-webserver.de`)" entryPoints: - websecure service: authelia tls: certResolver: le services: authelia: loadBalancer: servers: - url: "http://authelia:9091" ``` --- ## Bestehende Routen anpassen ### 1. `0100-traefik-dashboard.yml` – Dashboard & Admin-Dienste ```yaml # Vorher: middlewares: - chain-secure-admin # Nachher: middlewares: - chain-authelia ``` ### 2. Standard-App-Routen (`0110-nextcloud.yml`, `0120-paperless.yml`, usw.) In jeder Service-Route wird die Middleware ausgetauscht: | Route-Datei | Vorher | Nachher | | | ---------------------------- | -------------------- | ------------------------------------------------------- | --- | | `0100-traefik-dashboard.yml` | `chain-secure-admin` | `chain-authelia` | | | `0110-nextcloud.yml` | `chain-app-standard` | `chain-nextcloud` *(bleibt – cloud.* ist auf `bypass`)* | | | `0120-paperless.yml` | `chain-app-standard` | `chain-authelia` | | | `0130-immich.yml` | `chain-app-standard` | `chain-authelia` | | | `0140-wikijs.yml` | `chain-app-standard` | `chain-authelia` | | | `0150-stirling.yml` | `chain-app-standard` | `chain-authelia` | | | `0160-plex.yml` | `chain-app-standard` | `chain-authelia` | | | `0170-nginx.yml` | `chain-app-standard` | `chain-authelia` | | | `0500-jenkins.yml` | `chain-jenkins` | `chain-authelia` | | | `0510-gitea.yml` | – *(gar keine)* | `chain-authelia` | | **Beispiel** – vorher in `0120-paperless.yml`: ```yaml middlewares: - chain-app-standard ``` **Nachher**: ```yaml middlewares: - chain-authelia ``` ### Achtung: Nextcloud & Collabora Nextcloud (`cloud.*`) und Collabora (`office.*`) sind in der `access_control`-Regel auf `bypass` gesetzt – sie werden von Authelia **übersprungen**, da Nextcloud seinen eigenen Login hat und Collabora nur als iFrame embedded wird. Trotzdem sollte die Middleware `chain-authelia` in der Route bleiben – Traefik leitet dann einfach durch, weil Authelia `bypass` zurückgibt. --- ## OIDC-Integration (SSO für Apps mit OIDC-Support) Authelia kann als **OpenID Connect (OIDC) Provider** dienen. Dienste wie Immich, Gitea und Wiki.js unterstützen OIDC nativ – dann loggst Du Dich direkt über Authelia in der jeweiligen App ein, ohne separates ForwardAuth. ### Architektur (OIDC vs. ForwardAuth) | ForwardAuth (einfach) | OIDC (für Apps mit Support) | |---|---| | Traefik fragt Authelia bei jedem Request | App (z. B. Immich) leitet zur Anmeldung an Authelia weiter | | Für Dienste **ohne** eigenes Login-System | Für Dienste **mit** OIDC-Support | | Plex, Stirling PDF, Nginx | Immich, Gitea, Wiki.js, Grafana | ### 1. Authelia als OIDC-Provider aktivieren In `/opt/compose/authelia/config/configuration.yml` ergänzen: ```yaml # OIDC-Provider-Konfiguration identity_providers: oidc: hmac_secret: jwks: # ⚠️ In v4.39 heißt der Key `jwks`, NICHT `issuer_private_keys`! - key_id: rpid algorithm: RS256 key: | -----BEGIN PRIVATE KEY----- -----END PRIVATE KEY----- clients: # --------------------------------------------------------------- # Gitea # --------------------------------------------------------------- - id: gitea description: Gitea SSO secret: public: false authorization_policy: one_factor redirect_uris: - https://git.da.home-webserver.de/user/oauth2/authelia/callback - https://git.da.home-webserver.de/user/oauth2/Authelia/callback # Groß-/Kleinschreibung des Gitea-Provider-Namens! scopes: - openid - profile - email consent_mode: pre-configured # Zustimmung vorab erteilt (19.06.) pre_configured_consent_duration: '3 months' # --------------------------------------------------------------- # Immich # --------------------------------------------------------------- - id: immich description: Immich SSO secret: public: false authorization_policy: one_factor redirect_uris: - https://photos.da.home-webserver.de/auth/login - https://photos.da.home-webserver.de/oauth2/callback scopes: - openid - profile - email userinfo_signing_algorithm: RS256 # --------------------------------------------------------------- # Wiki.js # --------------------------------------------------------------- - id: wikijs description: Wiki.js SSO secret: public: false authorization_policy: one_factor redirect_uris: - https://wiki.da.home-webserver.de/login scopes: - openid - profile - email ``` > **RSA-Key erzeugen**: > ```bash > openssl genrsa -out /tmp/private.pem 2048 > # Den Inhalt von /tmp/private.pem in die configuration.yml einfügen > # ACHTUNG: Der Footer muss exakt `-----END PRIVATE KEY-----` (5 Striche) sein, nicht `----` (4 Striche)! > # Sonst kann Authelia den PEM-Block nicht parsen ("no PEM block was supplied or it was malformed"). > ``` > **Breaking Change in v4.39**: > - `issuer_private_keys` → `jwks` (wenn der alte Key verwendet wird, startet OIDC nicht) > - `id` → `client_id` (deprecated) > - `secret` → `client_secret` (deprecated) > - `description` → `client_name` (deprecated) > - Die Deprecation-Warnings sind aktuell noch funktional, werden aber in v5.0 entfernt. > **redirect_uri – Groß-/Kleinschreibung beachten**: > Gitea verwendet den **Namen der Authentication Source** als Teil des Callback-Pfads: > ``` > /user/oauth2//callback > ``` > Wenn der Provider z. B. `Authelia` heißt, ist die Callback-URL: > ``` > https://git.da.home-webserver.de/user/oauth2/Authelia/callback > ``` > → Beide Varianten (`authelia` und `Authelia`) in den `redirect_uris` eintragen! > ✅ **Erledigt** auf dem Pi5 – funktioniert seit 21:10. ### 2. Access-Rules anpassen Dienste mit OIDC brauchen **kein** ForwardAuth mehr – sie werden auf `bypass` gesetzt, weil die Authentifizierung direkt zwischen App und Authelia (OIDC) läuft: ```yaml access_control: default_policy: deny rules: - domain: "auth.da.home-webserver.de" policy: bypass - domain: "cloud.da.home-webserver.de" policy: bypass # Nextcloud: eigener Login - domain: "office.da.home-webserver.de" policy: bypass # Collabora: iFrame - domain: "git.da.home-webserver.de" policy: bypass # Gitea: OIDC ✅ aktiv - domain: "photos.da.home-webserver.de" policy: bypass # Immich: OIDC (geplant) - domain: "wiki.da.home-webserver.de" policy: bypass # Wiki.js: OIDC (geplant) - domain: "traefik.da.home-webserver.de" policy: two_factor # Admin: ForwardAuth (geplant) - domain: "prometheus.da.home-webserver.de" policy: two_factor # Admin: ForwardAuth (geplant) - domain: "*.da.home-webserver.de" policy: one_factor # Rest: ForwardAuth ``` ### 3. App-Seitige Konfiguration #### Immich (`.env`) ```properties # /opt/compose/immich/.env – ergänzen IMMICH_OIDC_ENABLED=true IMMICH_OIDC_ISSUER_URL=https://auth.da.home-webserver.de IMMICH_OIDC_CLIENT_ID=immich IMMICH_OIDC_CLIENT_SECRET= IMMICH_OIDC_SCOPE=openid profile email IMMICH_OIDC_AUTO_REGISTER=true IMMICH_OIDC_SIGNING_ALGORITHM=RS256 ``` Danach `docker compose down && docker compose up -d` auf dem Immich-Stack. #### Gitea (Web-UI) 1. Einstellungen → `https://git.da.home-webserver.de/admin/auths` 2. **"Add Authentication Source"** - Typ: **OAuth2** - Name: `Authelia` - Provider: **OpenID Connect** - Client ID: `gitea` - Client Secret: `` - OpenID Connect Issuer URL: `https://auth.da.home-webserver.de` 3. Speichern #### Wiki.js (Web-UI) 1. Einstellungen → **"Security"** → **"Authentication"** 2. **"Add Strategy"** → **"OpenID Connect / OAuth2"** 3. Werte: - Client ID: `wikijs` - Client Secret: `` - Authorization URL: `https://auth.da.home-webserver.de/api/oidc/authorization` - Token URL: `https://auth.da.home-webserver.de/api/oidc/token` - User Info URL: `https://auth.da.home-webserver.de/api/oidc/userinfo` - Issuer URL: `https://auth.da.home-webserver.de` ### 4. Traefik-Middleware bei OIDC-Diensten entfernen Dienste, die auf OIDC umgestellt sind, brauchen **keine** `chain-authelia`-Middleware mehr – andernfalls blockiert sich ForwardAuth und OIDC gegenseitig. **In den conf.d-Dateien** die Middleware auf `bypass` setzen oder ganz entfernen: ```yaml # /opt/compose/traefik/conf.d/0130-immich.yml # Vorher: # middlewares: # - chain-authelia # Nachher: keine Middleware (Immich macht OIDC) ``` ### Übersicht: ForwardAuth vs. OIDC | Dienst | Auth-Methode | Middleware in Traefik | policy in Authelia | |---|---|---|---| | Traefik-Dashboard | ForwardAuth | `chain-authelia` | `two_factor` | | Prometheus | ForwardAuth | `chain-authelia` | `two_factor` | | Paperless | ForwardAuth | `chain-authelia` | `one_factor` | | Stirling PDF | ForwardAuth | `chain-authelia` | `one_factor` | | Plex | ForwardAuth | `chain-authelia` | `one_factor` | | Nginx | ForwardAuth | `chain-authelia` | `one_factor` | | Jenkins | ForwardAuth | `chain-authelia` | `one_factor` | | **Immich** | **OIDC** | **keine** | `bypass` | | **Gitea** | **OIDC** | **keine** | `bypass` | | **Wiki.js** | **OIDC** | **keine** | `bypass` | | Nextcloud | eigener Login | `chain-nextcloud` | `bypass` | | Collabora | iFrame-Bypass | `collabora-headers` | `bypass` | --- ## Optional: `.htpasswd`-Auth entfernen Sobald Authelia läuft, können diese Konfigurationen entfallen: - Admin-Benutzer aus `auth/.htpasswd` - Middleware `auth-admin` (Basic-Auth) in `0010-middlewares.yml` - Middleware-Chain `chain-secure-admin` --- ## Passkey-Registrierung (erster Benutzer) 1. **Authelia starten** → `docker compose up -d` 2. **Erstmalig einloggen** unter `auth.da.home-webserver.de` 3. Nach Login → **"Security"** → **"Register Security Key"** klicken 4. Passkey via Touch ID / Windows Hello / YubiKey registrieren 5. Ab sofort reicht beim Login **Benutzername + Passkey** (Passwort optional) --- ## Migrationsplan (Fortschritt) | Schritt | Aktion | Status | | ------- | -------------------------------------------------------------------- | ------ | | 1 | Compose + Config bereitstellen | ✅ **erledigt** | | 2 | `0020-authelia-middleware.yml` + `0015-authelia-service.yml` anlegen | ✅ **erledigt** | | 3 | OIDC-Provider aktivieren (`jwks` statt `issuer_private_keys`) | ✅ **erledigt** (20:01, 18.06.) | | 4 | Gitea OIDC-Auth-Source einrichten | ✅ **erledigt** (Login funktioniert) | | 5 | Stirling PDF als ersten Dienst via ForwardAuth schützen | ✅ **erledigt** (`chain-authelia` aktiv) | | 6 | WebAuthn-Passkey-Config überarbeitet (direct attestation + metadata) | ✅ **erledigt** (19.06.) | | 7 | OIDC consent_mode auf pre-configured gesetzt | ✅ **erledigt** (19.06.) | | 8 | Immich OIDC konfigurieren | ⏳ geplant | | 9 | Wiki.js OIDC konfigurieren | ⏳ geplant | | 10 | Traefik-Dashboard, Prometheus auf ForwardAuth umstellen | ⏳ geplant | | 11 | Paperless, Plex, Nginx, Jenkins auf ForwardAuth umstellen | ⏳ geplant | | 12 | `.htpasswd` und `auth-admin` entfernen | ⏳ geplant | ### Aktuelle Routing-Übersicht (Live vom 18.06., 20:00) | Dienst | Route | Auth-Methode | Status | |---|---|---|---| | Authelia (Portal) | `auth.*` | keine (bypass) | ✅ | | Nextcloud | `cloud.*` | kein Auth (bypass) | ✅ | | Collabora | `office.*` | kein Auth (bypass) | ✅ | | Gitea | `git.*` | OIDC (ohne Middleware) | 🔄 Gitea-WebUI-Konfiguration ausstehend | | Stirling PDF | `pdf.*` | ForwardAuth (`chain-authelia`) | ✅ | | Immich | `photos.*` | `chain-app-standard` (offen) | ⏳ | | Wiki.js | `wiki.*` | `chain-app-standard` (offen) | ⏳ | | Paperless | `paperless.*` | `chain-app-standard` (offen) | ⏳ | | Plex | `music.*` | `chain-app-standard` (offen) | ⏳ | | Nginx | `web.*` | `chain-app-standard` (offen) | ⏳ | | Jenkins | `jenkins.*` | `chain-jenkins` (offen) | ⏳ | | Traefik Dashboard | `traefik.*` | Basic-Auth | ⏳ | | Prometheus | `prometheus.*` | Basic-Auth | ⏳ | | Grafana | `grafana.*` | Grafana-intern | – | --- ## Backup / Wiederherstellung Das SQLite-DB enthält alle Benutzer-Sessions und registrierte Passkeys: ```bash # Sichern cp /opt/compose/authelia/config/db.sqlite3 /backup/authelia-db.sqlite3 # Wiederherstellen cp /backup/authelia-db.sqlite3 /opt/compose/authelia/config/db.sqlite3 ``` Die Users-Datei und Config sind YAML – ideal für Git-Versionierung. --- ## Ressourcenverbrauch (geschätzt) | Metrik | Wert | |---|---| | RAM | ~50–80 MB | | CPU | vernachlässigbar (Go-Binary) | | Speicher | ~50 MB (SQLite + Config) | | Image-Größe | ~75 MB (linux/arm64) | --- ## Verwandte Seiten - [traefik](./traefik.md) – Reverse-Proxy-Grundkonfiguration - [docker-services](../docker-services.md) – Alle Dienste im Überblick - [Authelia Dokumentation](https://www.authelia.com/configuration/)