Zurück zum Blog

Umami Analytics mit Authentik Forward-Auth absichern

Umami Analytics mit Authentik Forward-Auth absichern - matzka.cloud

Umami Analytics mit Authentik Forward-Auth absichern

Datum 10. Januar 2026
Kategorie Sicherheit, SSO, Infrastruktur
Lesezeit 20 Minuten

Einleitung: Das Problem mit Umami und SSO

Umami Analytics ist eine hervorragende, datenschutzfreundliche Alternative zu Google Analytics. Es bietet eine saubere Oberflaeche, DSGVO-Konformitaet und Self-Hosting-Moeglichkeiten. Allerdings hat Umami ein signifikantes Problem: Es unterstuetzt kein natives OAuth/OIDC.

Das Kernproblem: Umami verwendet ausschliesslich Benutzername/Passwort-Authentifizierung mit eigenem JWT-Token-System. Es gibt keinen nativen Support fuer OAuth2, OIDC, SAML oder andere SSO-Protokolle.

Bei matzka.cloud nutzen wir Authentik als zentralen Identity Provider (IdP) fuer alle Dienste. Die Anforderung war klar: Umami soll nur fuer authentifizierte Authentik-Benutzer zugaenglich sein, waehrend der Tracking-Endpunkt (/api/send) oeffentlich bleibt fuer Website-Analytics.

Anforderungen

  • Zugriffskontrolle: Nur Authentik-authentifizierte Benutzer sollen das Dashboard sehen
  • Tracking funktionsfaehig: Der /api/send Endpunkt muss oeffentlich bleiben
  • Nahtlose Integration: Kein separater Login-Schritt noetig
  • Wartbarkeit: Moeglichst wenig Custom-Code

Zwei Ansaetze: SSO Proxy vs. Forward-Auth

Bei der Implementierung wurden zwei verschiedene Ansaetze evaluiert. Der erste Ansatz (Custom SSO Proxy) stellte sich als zu komplex heraus, was uns zum zweiten, eleganten Ansatz fuehrte.

Ansatz 1: Custom SSO Proxy (Verworfen)

Der erste Versuch war ein Node.js/Express-basierter SSO Proxy, der:

  1. OAuth2/OIDC-Flow mit Authentik durchfuehrt
  2. Benutzer automatisch in Umami erstellt (via Umami Admin API)
  3. Umami JWT-Token generiert und in die Session injiziert
  4. Alle Requests zu Umami proxyt mit injiziertem Token
Warum dieser Ansatz scheiterte:

Das Hauptproblem war die Token-Injection ins Browser-localStorage. Umami speichert seinen JWT-Token clientseitig in localStorage. Der Proxy konnte den Token serverseitig setzen, aber Umami's Frontend erwartete ihn im Browser.

Versuche, den Token via JavaScript in die HTML-Response zu injizieren, funktionierten nicht zuverlaessig wegen Timing-Problemen und Next.js' clientseitigem Rendering.

Ansatz 2: Authentik Forward-Auth (Implementiert)

Der zweite, erfolgreiche Ansatz nutzt Authentik's Forward-Auth Funktion:

Forward-Auth Prinzip:

Forward-Auth ist ein "Gatekeeper"-Pattern. Traefik fragt vor jedem Request bei Authentik nach, ob der Benutzer authentifiziert ist. Ist er es nicht, wird er zu Authentik's Login weitergeleitet. Nach erfolgreicher Authentifizierung wird der Original-Request durchgelassen.

Vergleich der Ansaetze

Kriterium SSO Proxy Forward-Auth
Komplexitaet Hoch (Custom Code) Niedrig (Konfiguration)
Wartbarkeit Aufwaendig Einfach
Auto-Login in Umami Ja (theoretisch) Nein (separater Login)
Zugriffskontrolle Ja Ja
Zuverlaessigkeit Problematisch Stabil
Wichtige Unterscheidung:

Forward-Auth ist kein echtes SSO. Der Benutzer muss sich zuerst bei Authentik authentifizieren (Gatekeeper), und danach nochmals bei Umami einloggen. Der Vorteil ist jedoch, dass nur berechtigte Benutzer ueberhaupt zum Umami-Login kommen.

Architektur: Forward-Auth erklaert

Request-Flow Diagramm

┌─────────────────┐
│    Browser      │
│  (Benutzer)     │
└────────┬────────┘
         │ 1. GET https://analytics.matzka.cloud/
         ▼
┌─────────────────┐
│    Traefik      │
│  (Reverse Proxy)│
└────────┬────────┘
         │ 2. Forward-Auth Request
         │    GET /outpost.goauthentik.io/auth/traefik
         │    Headers: X-Forwarded-Host, X-Original-URL, ...
         ▼
┌─────────────────────────────────┐
│  Authentik Embedded Outpost     │
│  (http://authentik-server:9000) │
└────────┬────────────────────────┘
         │
         │ 3a. Nicht authentifiziert?
         │     → HTTP 401 + Location Header → Authentik Login
         │
         │ 3b. Authentifiziert?
         │     → HTTP 200 + X-authentik-* Headers
         ▼
┌─────────────────┐
│    Traefik      │
│  (Entscheidung) │
└────────┬────────┘
         │ 4. Bei 200: Request weiterleiten
         ▼
┌─────────────────┐
│     Umami       │
│  (Dashboard)    │
└─────────────────┘

Netzwerk-Topologie

Die Docker-Container muessen in den richtigen Netzwerken sein, damit die interne Kommunikation funktioniert:

┌───────────────────────────────────────────────────────────┐
│                    Docker Networks                         │
├───────────────────────────────────────────────────────────┤
│                                                           │
│  ┌─────────────────────────────────────────────────────┐ │
│  │                 frontend (external)                  │ │
│  │  ┌──────────┐  ┌──────────┐  ┌───────────────────┐  │ │
│  │  │ Traefik  │  │  Umami   │  │  authentik-server │  │ │
│  │  │          │  │          │  │                   │  │ │
│  │  └──────────┘  └──────────┘  └───────────────────┘  │ │
│  └─────────────────────────────────────────────────────┘ │
│                                                           │
│  ┌─────────────────────────────────────────────────────┐ │
│  │              authentik-backend (internal)           │ │
│  │  ┌──────────────────┐  ┌─────────────────────────┐  │ │
│  │  │  authentik-server│  │  postgres-authentik     │  │ │
│  │  │  (Port 9000)     │  │  redis-authentik        │  │ │
│  │  └──────────────────┘  └─────────────────────────┘  │ │
│  └─────────────────────────────────────────────────────┘ │
│                                                           │
│  ┌─────────────────────────────────────────────────────┐ │
│  │                monitoring (internal)                │ │
│  │  ┌──────────┐  ┌──────────────┐  ┌───────────────┐  │ │
│  │  │  Umami   │  │ postgres-    │  │  Prometheus   │  │ │
│  │  │          │  │ umami        │  │               │  │ │
│  │  └──────────┘  └──────────────┘  └───────────────┘  │ │
│  └─────────────────────────────────────────────────────┘ │
│                                                           │
└───────────────────────────────────────────────────────────┘
Kritisch: Sowohl Traefik als auch authentik-server muessen im frontend Netzwerk sein. Die Forward-Auth-Kommunikation erfolgt ueber die interne Docker-URL (http://authentik-server:9000), nicht ueber die oeffentliche URL.

Authentik Konfiguration (Schritt fuer Schritt)

Die Authentik-Konfiguration erfordert drei Komponenten: einen Provider, eine Application und ein Outpost-Binding.

Schritt 1: Provider erstellen

Im Authentik Admin Interface navigieren zu: Applications → Providers → Create

Provider-Typ: Proxy Provider

Wichtig: Es muss ein Proxy Provider sein, kein OAuth2 Provider. Der Proxy Provider implementiert das Forward-Auth Pattern.

Provider-Einstellungen

# Provider Konfiguration
Name:                  Umami Analytics Forward-Auth
Authorization flow:    default-provider-authorization-implicit-consent
Mode:                  Forward auth (single application)

# Wichtig: External Host
External host:         https://analytics.matzka.cloud

# Optional aber empfohlen
Access token validity: 24 hours
Mode "Forward auth (single application)" bedeutet, dass dieser Provider nur fuer eine einzelne Anwendung (Umami) zustaendig ist. Der "Forward auth (domain level)" Modus wuerde alle Subdomains schuetzen.

Schritt 2: Application erstellen

Navigieren zu: Applications → Applications → Create

# Application Konfiguration
Name:           Umami Analytics
Slug:           umami
Provider:       Umami Analytics Forward-Auth (aus Schritt 1)
Launch URL:     https://analytics.matzka.cloud

# Policy Engine Mode
Policy engine mode:    any (Standard)

Erlaubte Weiterleitungs-URIs

Nach dem Erstellen der Application muessen die Redirect-URIs im Provider konfiguriert werden. Diese werden automatisch generiert, aber zur Vollstaendigkeit:

# Redirect URIs (automatisch generiert)
https://analytics.matzka.cloud/outpost.goauthentik.io/callback?X-authentik-auth-callback=true
https://analytics.matzka.cloud?X-authentik-auth-callback=true

Schritt 3: Outpost zuweisen

Navigieren zu: Applications → Outposts → authentik Embedded Outpost → Edit

Embedded Outpost:

Authentik's Embedded Outpost ist der einfachste Weg fuer Forward-Auth. Er laeuft im selben Container wie der Authentik-Server und ist unter /outpost.goauthentik.io/ erreichbar.

# Outpost Konfiguration
Name:                       authentik Embedded Outpost
Type:                       Proxy
Selected Applications:      [x] Umami Analytics   ← Checkbox aktivieren!
                           [x] Andere Apps...

# Wichtig: Configuration
authentik_host:            https://auth.matzka.cloud/
Haeufiger Fehler: Vergessen, die Umami Application dem Outpost zuzuweisen! Ohne diese Zuweisung liefert der Outpost 404-Fehler fuer alle Forward-Auth-Anfragen.

Schritt 4: Authentik neu starten

Nach allen Aenderungen muss Authentik neu gestartet werden:

# Auf dem Server ausfuehren
ssh root@ssh2.matzka.cloud

# In das Authentik-Verzeichnis wechseln
cd /opt/docker/compose

# Authentik-Container neu starten
docker compose restart authentik-server authentik-worker

# Logs pruefen
docker logs -f authentik-server 2>&1 | head -50

Traefik Konfiguration (Detailliert)

Die Traefik-Konfiguration ist der kritischste Teil der Integration. Hier werden die meisten Fehler gemacht, insbesondere bei der Forward-Auth-Middleware und den Headers.

Das Zwei-Router-Pattern

Umami benoetigt zwei verschiedene Router: einen oeffentlichen fuer das Tracking und einen geschuetzten fuer das Dashboard.

                    ┌─────────────────────────────────┐
                    │       analytics.matzka.cloud    │
                    └─────────────────┬───────────────┘
                                      │
                    ┌─────────────────┴───────────────┐
                    │                                  │
           ┌────────▼────────┐              ┌─────────▼─────────┐
           │  /api/send      │              │  /* (alles andere)│
           │  Priority: 100  │              │  Priority: 1      │
           │                 │              │                   │
           │  KEIN AUTH      │              │  FORWARD-AUTH     │
           │  (Oeffentlich)  │              │  (Geschuetzt)     │
           └────────┬────────┘              └─────────┬─────────┘
                    │                                  │
                    └─────────────┬────────────────────┘
                                  ▼
                          ┌──────────────┐
                          │    Umami     │
                          │   Container  │
                          └──────────────┘

Router 1: Tracking-Endpunkt (Oeffentlich)

# Traefik Labels fuer Umami Container
# Router 1: Tracking endpoint - PUBLIC (no auth required)
- "traefik.http.routers.umami-tracking.rule=Host(`analytics.${DOMAIN}`) && Path(`/api/send`)"
- "traefik.http.routers.umami-tracking.entrypoints=websecure"
- "traefik.http.routers.umami-tracking.tls.certresolver=letsencrypt"
- "traefik.http.routers.umami-tracking.priority=100"
- "traefik.http.routers.umami-tracking.service=umami"
Priority 100:

Die hohe Prioritaet (100) stellt sicher, dass Requests an /api/send immer zuerst von diesem Router behandelt werden, nicht vom geschuetzten Router. Traefik verwendet hoehere Zahlen = hoehere Prioritaet.

Router 2: Dashboard (Geschuetzt)

# Router 2: Dashboard - PROTECTED with Authentik Forward-Auth
- "traefik.http.routers.umami.rule=Host(`analytics.${DOMAIN}`)"
- "traefik.http.routers.umami.entrypoints=websecure"
- "traefik.http.routers.umami.tls.certresolver=letsencrypt"
- "traefik.http.routers.umami.priority=1"

# Forward-Auth Middleware Definition
- "traefik.http.middlewares.umami-auth.forwardauth.address=http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
- "traefik.http.middlewares.umami-auth.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.umami-auth.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid"

# Security Headers Middleware
- "traefik.http.middlewares.umami-headers.headers.stsSeconds=31536000"
- "traefik.http.middlewares.umami-headers.headers.stsIncludeSubdomains=true"

# Middlewares anwenden
- "traefik.http.routers.umami.middlewares=umami-auth,umami-headers"

# Service Konfiguration
- "traefik.http.services.umami.loadbalancer.server.port=3000"
- "traefik.docker.network=frontend"

Die Forward-Auth URL erklaert

Die Forward-Auth-Adresse ist der wichtigste Teil der Konfiguration:

http://authentik-server:9000/outpost.goauthentik.io/auth/traefik
│                       │    │                          │
│                       │    │                          └── Traefik-spezifischer Endpunkt
│                       │    └── Authentik Outpost Pfad
│                       └── Interner Docker Port
└── Container-Name im Docker-Netzwerk
Kritisch: Interne Docker-URL verwenden!

Die Forward-Auth-Anfragen muessen ueber die interne Docker-URL gehen, nicht ueber die oeffentliche URL. Dies verhindert:

  • Header-Manipulation durch Traefik's externe Router
  • SSL/TLS-Probleme bei internen Anfragen
  • Potentielle Endlosschleifen

Falsch vs. Richtig

# FALSCH: Oeffentliche URL
# Fuehrt zu 404-Fehlern wegen Header-Problemen
forwardauth.address=https://auth.matzka.cloud/outpost.goauthentik.io/auth/traefik

# RICHTIG: Interne Docker-URL
# Direkte Container-zu-Container Kommunikation
forwardauth.address=http://authentik-server:9000/outpost.goauthentik.io/auth/traefik

Trust Forward Headers

Die Option trustForwardHeader=true ist notwendig, damit Authentik die urspruengliche Client-IP und Host-Informationen erhaelt:

# Diese Header werden von Traefik an Authentik weitergeleitet:
X-Forwarded-For:    Client IP-Adresse
X-Forwarded-Host:   analytics.matzka.cloud (der urspruengliche Host)
X-Forwarded-Proto:  https
X-Forwarded-Uri:    /dashboard (der urspruengliche Pfad)
X-Original-URL:     https://analytics.matzka.cloud/dashboard

Auth Response Headers

Nach erfolgreicher Authentifizierung kann Authentik Benutzer-Informationen an die Backend-Anwendung weitergeben:

# Headers die Authentik zurueckgibt (bei 200 OK):
X-authentik-username:  benutzer@example.com
X-authentik-groups:    umami-users,admins
X-authentik-email:     benutzer@example.com
X-authentik-name:      Max Mustermann
X-authentik-uid:       ak-user-uuid-1234...
Verwendung in Umami:

Umami nutzt diese Headers nicht direkt fuer die Authentifizierung. Sie koennten jedoch fuer Logging oder zukuenftige Erweiterungen nuetzlich sein.

Docker Compose Integration

Hier ist die vollstaendige Docker Compose Konfiguration fuer Umami mit Forward-Auth:

Umami Service Definition

###############################################################################
# UMAMI ANALYTICS - Privacy-focused Web Analytics
###############################################################################
postgres-umami:
  image: postgres:17-alpine
  container_name: postgres-umami
  restart: unless-stopped
  networks:
    - monitoring
  environment:
    POSTGRES_DB: umami
    POSTGRES_USER: umami
    POSTGRES_PASSWORD: ${UMAMI_POSTGRES_PASSWORD}
  volumes:
    - postgres_umami_data:/var/lib/postgresql/data
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U umami"]
    interval: 30s
    timeout: 10s
    retries: 5
  labels:
    - "backup.stop-during-backup=true"

umami:
  image: ghcr.io/umami-software/umami:postgresql-latest
  container_name: umami
  restart: unless-stopped
  networks:
    - monitoring
    - frontend          # Wichtig fuer Traefik!
  environment:
    DATABASE_URL: postgresql://umami:${UMAMI_POSTGRES_PASSWORD}@postgres-umami:5432/umami
    DATABASE_TYPE: postgresql
    APP_SECRET: ${UMAMI_APP_SECRET}
    HOSTNAME: 0.0.0.0
    PORT: 3000
  depends_on:
    postgres-umami:
      condition: service_healthy
  labels:
    - "traefik.enable=true"

    # Router 1: Tracking endpoint - PUBLIC
    - "traefik.http.routers.umami-tracking.rule=Host(`analytics.${DOMAIN}`) && Path(`/api/send`)"
    - "traefik.http.routers.umami-tracking.entrypoints=websecure"
    - "traefik.http.routers.umami-tracking.tls.certresolver=letsencrypt"
    - "traefik.http.routers.umami-tracking.priority=100"
    - "traefik.http.routers.umami-tracking.service=umami"

    # Router 2: Dashboard - PROTECTED with Authentik Forward-Auth
    - "traefik.http.routers.umami.rule=Host(`analytics.${DOMAIN}`)"
    - "traefik.http.routers.umami.entrypoints=websecure"
    - "traefik.http.routers.umami.tls.certresolver=letsencrypt"
    - "traefik.http.routers.umami.priority=1"

    # Authentik Forward-Auth Middleware (internal Docker URL!)
    - "traefik.http.middlewares.umami-auth.forwardauth.address=http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
    - "traefik.http.middlewares.umami-auth.forwardauth.trustForwardHeader=true"
    - "traefik.http.middlewares.umami-auth.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid"

    # Security Headers
    - "traefik.http.middlewares.umami-headers.headers.stsSeconds=31536000"
    - "traefik.http.middlewares.umami-headers.headers.stsIncludeSubdomains=true"

    # Apply Middlewares to protected router
    - "traefik.http.routers.umami.middlewares=umami-auth,umami-headers"

    # Service configuration
    - "traefik.http.services.umami.loadbalancer.server.port=3000"
    - "traefik.docker.network=frontend"
    - "backup.stop-during-backup=true"

Netzwerk-Konfiguration

###############################################################################
# NETWORKS
###############################################################################
networks:
  monitoring:
    external: true
    name: monitoring

  frontend:
    external: true
    name: frontend

  authentik-backend:
    external: true
    name: authentik-backend
Netzwerk-Voraussetzung:

Die Netzwerke frontend und authentik-backend muessen bereits existieren. Sie werden typischerweise von Traefik bzw. Authentik erstellt.

Troubleshooting: 404-Fehler beheben

Der haeufigste Fehler bei Forward-Auth ist ein 404 Not Found von Authentik. Hier sind die drei Hauptursachen und deren Loesungen:

Problem 1: Falscher Endpunkt

Symptom:
HTTP 404 Not Found
Header: X-Authentik-Error: "no provider found"

Ursache

Der Endpunkt /auth/nginx wurde verwendet statt /auth/traefik.

Loesung

# FALSCH:
forwardauth.address=http://authentik-server:9000/outpost.goauthentik.io/auth/nginx

# RICHTIG:
forwardauth.address=http://authentik-server:9000/outpost.goauthentik.io/auth/traefik

Problem 2: X-Forwarded-Host wird ueberschrieben

Symptom:
HTTP 404 Not Found
Authentik findet keinen Provider fuer den Host

Ursache

Eine andere Traefik-Middleware (z.B. authentik-headers@file) ueberschreibt den X-Forwarded-Host Header auf auth.matzka.cloud.

Diagnose

# Traefik Dynamic Config pruefen
ssh root@ssh2.matzka.cloud "cat /opt/docker/compose/traefik/dynamic/authentik.yml"

# Suche nach customRequestHeaders:
http:
  middlewares:
    authentik-headers:
      headers:
        customRequestHeaders:
          X-Forwarded-Host: "auth.matzka.cloud"  # <- PROBLEM!

Loesung

Die X-Forwarded-Host Zeile aus der Middleware entfernen oder diese Middleware nicht fuer Umami verwenden:

# /opt/docker/compose/traefik/dynamic/authentik.yml
# Korrigierte Version ohne X-Forwarded-Host Override
http:
  services:
    authentik-backup:
      loadBalancer:
        servers:
          - url: "http://authentik-server:9000"

  # Middleware OHNE X-Forwarded-Host Override
  middlewares:
    authentik-headers:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true

Problem 3: Oeffentliche URL statt interne Docker-URL

Symptom:
HTTP 404 Not Found
Sporadische Fehler, manchmal funktioniert es

Ursache

Die Forward-Auth-Anfragen gehen ueber die oeffentliche URL (https://auth.matzka.cloud/...), was bedeutet, dass sie wieder durch Traefik geroutet werden. Dabei werden Headers modifiziert.

Loesung

# FALSCH: Oeffentliche URL (geht durch Traefik)
forwardauth.address=https://auth.matzka.cloud/outpost.goauthentik.io/auth/traefik

# RICHTIG: Interne Docker-URL (direkte Container-Kommunikation)
forwardauth.address=http://authentik-server:9000/outpost.goauthentik.io/auth/traefik

Debugging-Befehle

# 1. Forward-Auth manuell testen
curl -v -H "X-Forwarded-Host: analytics.matzka.cloud" \
     -H "X-Original-URL: https://analytics.matzka.cloud/" \
     http://localhost:9000/outpost.goauthentik.io/auth/traefik

# 2. Traefik Router pruefen
curl -s http://localhost:8080/api/http/routers | \
  python3 -c 'import sys,json; [print(json.dumps(r,indent=2)) for r in json.load(sys.stdin) if "umami" in r.get("name","")]'

# 3. Authentik Logs pruefen
docker logs authentik-server 2>&1 | grep -i "outpost\|forward\|404"

# 4. Traefik Logs pruefen
docker logs traefik 2>&1 | grep -i "umami\|forward"

Testing und Validierung

Test 1: Tracking-Endpunkt (muss oeffentlich sein)

# Dieser Request sollte OHNE Authentifizierung funktionieren
curl -X POST https://analytics.matzka.cloud/api/send \
  -H "Content-Type: application/json" \
  -d '{"type":"event","payload":{"website":"test"}}'

# Erwartete Antwort: HTTP 200 oder spezifische Umami-Antwort
# NICHT: HTTP 302 Redirect zu Authentik

Test 2: Dashboard (muss geschuetzt sein)

# Ohne Session Cookie - sollte zu Authentik redirecten
curl -I https://analytics.matzka.cloud/

# Erwartete Antwort:
HTTP/2 302
location: https://auth.matzka.cloud/application/o/authorize/?...

Test 3: Browser-Test (Inkognito-Modus)

  1. Browser im Inkognito/Private Modus oeffnen
  2. https://analytics.matzka.cloud aufrufen
  3. Erwartung: Redirect zu Authentik Login
  4. Mit Authentik-Credentials einloggen
  5. Erwartung: Redirect zurueck zu Umami Dashboard
  6. Umami Login-Seite erscheint (separater Login noetig)
Warum Inkognito?

Wenn Sie bereits eine aktive Authentik-Session haben (z.B. von einem anderen Service), werden Sie automatisch durchgelassen. Der Inkognito-Modus stellt sicher, dass keine vorhandene Session die Tests beeinflusst.

Test 4: Authentik Session Validierung

# Mit vorhandener Authentik-Session (Cookie)
curl -I -b "authentik_session=..." https://analytics.matzka.cloud/

# Erwartete Antwort:
HTTP/2 200
# oder
HTTP/2 302 (redirect to Umami's own login, not Authentik)

Erwartetes Verhalten

Szenario Erwartetes Ergebnis
Unauthentifizierter User → Dashboard 302 Redirect zu Authentik Login
Authentifizierter User → Dashboard 200 OK, Umami Login-Seite
Jeder → /api/send 200 OK (Tracking funktioniert)
Unauthentifizierter User → /settings 302 Redirect zu Authentik Login

Lessons Learned

Technische Erkenntnisse

1. Forward-Auth ist kein SSO

Forward-Auth implementiert einen Gatekeeper, nicht Single Sign-On. Der Benutzer muss sich bei der Zielanwendung (Umami) separat einloggen. Fuer echtes SSO waere eine Anwendung mit nativer OIDC-Unterstuetzung noetig.

2. Interne Docker-URLs sind kritisch

Forward-Auth-Anfragen muessen immer ueber interne Docker-URLs gehen, nicht ueber oeffentliche URLs. Die oeffentliche URL fuehrt zu:

  • Header-Manipulation durch Traefik
  • Potentielle Endlosschleifen
  • Erhoehte Latenz
  • SSL/TLS-Probleme

3. X-Forwarded-Host darf nicht ueberschrieben werden

Authentik's Outpost nutzt den X-Forwarded-Host Header, um den richtigen Provider zu finden. Wenn dieser Header von einer Middleware ueberschrieben wird, findet Authentik keinen passenden Provider und gibt 404 zurueck.

4. Router-Prioritaeten sind wichtig

Bei mehreren Routern fuer denselben Host muss die Prioritaet korrekt gesetzt sein. Der spezifischere Router (z.B. nur /api/send) braucht eine hoehere Prioritaet als der Catch-All Router.

Prozess-Erkenntnisse

Best Practices:
  • Immer im Inkognito-Modus testen (keine vorhandene Session)
  • curl fuer API-Tests verwenden (keine Browser-Caching-Probleme)
  • Authentik- und Traefik-Logs parallel beobachten
  • Schrittweise vorgehen: erst Authentik, dann Traefik, dann testen
  • Nach jeder Aenderung Container neu starten

Bekannte Einschraenkungen

  • Kein Auto-Login: Benutzer muessen sich bei Umami separat einloggen
  • Keine Benutzersynchronisation: Umami-Benutzer muessen manuell erstellt werden
  • Session-Timeout: Authentik- und Umami-Sessions sind unabhaengig

Fazit

Die Integration von Umami Analytics mit Authentik Forward-Auth ist eine robuste Loesung fuer Zugriffskontrolle, auch wenn Umami kein natives SSO unterstuetzt.

Erreichte Ziele:
✅ Dashboard nur fuer authentifizierte Authentik-Benutzer zugaenglich
✅ Tracking-Endpunkt (/api/send) bleibt oeffentlich
✅ Keine Custom-Code-Wartung noetig
✅ Vollstaendige Integration in bestehende Authentik-Infrastruktur
✅ HTTPS mit Let's Encrypt SSL
✅ Security Headers (HSTS) aktiviert

Konfiguration auf einen Blick

Komponente Konfiguration
Authentik Provider Proxy Provider, Mode: Forward auth (single application)
External Host https://analytics.matzka.cloud
Outpost authentik Embedded Outpost
Forward-Auth URL http://authentik-server:9000/outpost.goauthentik.io/auth/traefik
Public Router umami-tracking (Priority 100, Path /api/send)
Protected Router umami (Priority 1, alle anderen Pfade)

Diese Implementierung zeigt, dass auch Anwendungen ohne native SSO-Unterstuetzung in eine moderne Identity-Management-Infrastruktur integriert werden koennen. Forward-Auth ist eine elegante Loesung fuer Zugriffskontrolle auf Reverse-Proxy-Ebene.