Zum Inhalt

Authelia

Authelia setzt eine Anmeldung vor kaimarkit. Traefik fragt bei jeder Anfrage dort nach, ob die Sitzung gilt, und leitet sonst zur Anmeldeseite weiter. Das erledigt eine ForwardAuth-Middleware.

docker-compose.authelia.yml ist die dritte Schicht und setzt die Traefik-Schicht voraus: Die Middleware hängt an dem Router, den jene anlegt.

Diese Datei startet Authelia nicht mit

Sie erwartet einen laufenden Authelia-Dienst im Traefik-Netz und verweist nur auf ihn. Authelia einzurichten — Benutzerdatenbank, Zugriffsregeln, Sitzungen — steht in dessen eigener Dokumentation.

Zwei Eingriffe in Authelias Konfiguration

Bevor KAIMARKIT_DOMAIN in docker/.env steht, gehören zwei Einträge in Authelias eigene Konfiguration. Beide liegen außerhalb von kaimarkit, und beide fallen erst im Betrieb auf — jedes Mal mit einer Antwort, die in die falsche Richtung zeigt.

Die Domäne muss unter Authelias Cookie-Domäne liegen. Eine Authelia ist für eine Domäne zuständig, etwa example.com; ihr Sitzungscookie gilt für diese und ihre Unterdomänen. Fragt Traefik für einen Host außerhalb davon nach, antwortet Authelia mit 400, und Traefik reicht den Statuscode unverändert durch. Dann kommt keine Anfrage durch, und das schon vor der Anmeldung. KAIMARKIT_DOMAIN gehört also unter dieselbe Domäne wie das Anmeldeportal: kaimarkit.example.com zu auth.example.com.

Authelias access_control braucht eine Regel für diese Domäne. Fehlt sie, gilt die default_policy. Steht die auf deny, führt der Weg durch die Anmeldung und endet danach mit einer Verweigerung: Wer sich anmeldet, kommt trotzdem nicht hinein.

access_control:
  rules:
    - domain: kaimarkit.example.com
      policy: two_factor

Welche policy dort steht und welche Bedingungen dazukommen, entscheidet, wer die Authelia betreibt; die Schreibweise der Regel steht in Authelias eigener Dokumentation.

Eine zweite Cookie-Domäne kostet ein zweites Portal

Wer kaimarkit unter eine andere Domäne stellen will als die vorhandene Authelia, braucht dort eine zweite Cookie-Domäne — und die verlangt je Domäne eine eigene authelia_url. Also ein erreichbares Anmeldeportal unter der neuen Domäne, mit eigenem Zertifikat und eigenem Router. Der kürzere Weg ist meist, kaimarkit unter die vorhandene Domäne zu setzen.

Was vorher da sein muss

Alles aus Traefik, dazu:

  • Ein laufender Authelia im selben Docker-Netz, unter seinem Containernamen erreichbar.
  • Eine Zugriffsregel in Authelias access_control, die KAIMARKIT_DOMAIN abdeckt, und eine Cookie-Domäne, unter der dieser Name liegt — beides wie oben beschrieben.
  • Ein DNS-Eintrag für die Anmeldeseite, etwa auth.example.com.
  • Eine ForwardAuth-Middleware, die Traefik kennt. Bringt die vorhandene Authelia keine mit, definiert diese Schicht eine eigene — siehe den nächsten Abschnitt.

Starten

cp docker/.env.example docker/.env
# Heisst die Middleware der vorhandenen Authelia "authelia@docker", genuegt das.
make up-authelia

Ohne make, alle drei Dateien in dieser Reihenfolge:

docker compose -f docker/docker-compose.yml \
               -f docker/docker-compose.traefik.yml \
               -f docker/docker-compose.authelia.yml up -d --build

Die Reihenfolge entscheidet. Fehlt die mittlere Datei, gibt es keinen Router, an den sich die Middleware hängen könnte.

Zwei Wege zur Middleware

Eine ForwardAuth-Middleware muss irgendwo definiert sein. Entweder bringt die vorhandene Authelia sie mit, oder diese Schicht definiert eine eigene. Beides funktioniert; die Wahl fällt über KAIMARKIT_MIDDLEWARES und KAIMARKIT_API_MIDDLEWARES.

Die vorhandene Middleware — der Normalfall

Wer Authelia betreibt, hat sie meist per Docker-Label an sich selbst beschriftet und schaltet sie so vor einen Dienst:

traefik.http.routers.whoami-secure.middlewares: "authelia@docker"

Dann ist nichts weiter zu tun. Beide Variablen stehen voreingestellt auf authelia@docker, und AUTHELIA_VERIFY_URL und AUTHELIA_RESPONSE_HEADERS bleiben ungenutzt — kaimarkit hängt an derselben Middleware wie alles andere hinter dieser Authelia. Ändert sich dort etwas, ändert es sich an einer Stelle.

Eine Bedingung: Der Zusatz hinter dem @ muss stimmen. Er gehört nicht zum Namen, sondern nennt den Traefik-Anbieter, aus dem die Middleware stammt.

Die eigene Middleware

Wessen Authelia ihre Middleware nicht per Docker-Label mitbringt — weil sie aus einer Datei kommt, außerhalb von Docker läuft oder gar keine hat —, trägt kaimarkit-auth@docker ein und setzt dafür die beiden Variablen. Der Name folgt KAIMARKIT_TRAEFIK_NAME; steht dort etwas anderes als kaimarkit, heißt die Middleware <name>-auth@docker:

KAIMARKIT_MIDDLEWARES=kaimarkit-auth@docker
KAIMARKIT_API_MIDDLEWARES=kaimarkit-auth@docker
AUTHELIA_VERIFY_URL=http://authelia:9091/api/verify?rd=https://auth.example.com
AUTHELIA_RESPONSE_HEADERS=Remote-User,Remote-Groups,Remote-Name,Remote-Email

AUTHELIA_VERIFY_URL nennt zwei verschiedene Adressen in einer Zeile. Vor dem Fragezeichen steht die Adresse, unter der Traefik Authelia im Docker-Netz erreicht — Containername und interner Port, unverschlüsselt, weil beide im selben Netz stehen. Der Parameter rd dagegen ist die Anmeldeseite, wie der Browser sie sieht: von außen erreichbar und mit TLS. Beide zeigen auf denselben Dienst, nur aus verschiedenen Blickwinkeln. Wer nur eine der beiden anpasst, bekommt entweder einen Verbindungsfehler oder eine Weiterleitung ins Leere.

AUTHELIA_RESPONSE_HEADERS legt fest, was Traefik von Authelia an die Anwendung durchreicht: Remote-User, Remote-Groups, Remote-Name, Remote-Email. kaimarkit wertet diese Kopfzeilen nicht aus. Sie stehen bereit, falls später jemand danach unterscheiden will.

Wer den ersten Weg geht, sollte prüfen, dass seine vorhandene Middleware dieselben Kopfzeilen durchreicht — kaimarkit braucht sie zwar nicht, aber eine Authelia, die gar keine durchreicht, verrät später niemandem, wer angemeldet war.

Die eigene Middleware bleibt immer definiert, auch wenn kein Router sie benutzt. Eine leere AUTHELIA_VERIFY_URL stört dabei nicht: Am 01.09.2026 führte Traefik 3.6.25 die ungenutzte Definition unter /api/http/middlewares auf enabled, ohne Fehler und ohne Eintrag im Log.

@docker oder @file — der Zusatz entscheidet

Traefik hängt an jeden Namen den Anbieter an, aus dem er stammt. Dieselbe Authelia heißt authelia@docker, wenn sie ihre Middleware per Container-Label definiert, und authelia@file, wenn sie aus einer statischen Konfigurationsdatei kommt. Unter dem falschen Zusatz findet Traefik sie nicht.

Der Fehler sieht nicht nach einem Tippfehler aus, und er ist folgenreich: Der Router verschwindet. Am 01.09.2026 mit Traefik 3.6.25 gegen einen absichtlich falschen Wert authelia@file gemessen — der Router stand unter /api/http/routers auf "status": "disabled" mit dem Fehler middleware "authelia@file" does not exist, und der Pfad / antwortete mit 404. Der /api-Router blieb dabei unberührt: Er hat seine eigene Variable und antwortete weiter mit 401.

Der falsche Name öffnet den Dienst nicht

Das ist die beruhigende Hälfte: Traefik lässt einen Router mit unbekannter Middleware nicht ungeschützt laufen, sondern gar nicht. Wer sich vertippt, bekommt einen toten Dienst und merkt es sofort. Dasselbe gilt für die eigene Middleware mit leerer AUTHELIA_VERIFY_URL: Sie antwortet mit 500, nicht mit dem Inhalt.

Welche Namen der eigene Traefik kennt, sagt seine API:

curl -sf http://<traefik-host>:8080/api/http/middlewares | jq -r '.[].name'

Der Name der eigenen Middleware folgt dem Namensraum

kaimarkit-auth ist keine feste Zeichenkette, sondern ${KAIMARKIT_TRAEFIK_NAME}-auth. Wer den Namensraum umstellt, weil eine zweite Instanz hinter derselben Traefik hängt, benennt damit auch diese Middleware um — und muss sie unter dem neuen Namen in KAIMARKIT_MIDDLEWARES eintragen. Die Variable dort löst sich nicht von selbst mit auf.

Eine Verkettung in docker/.env nimmt Compose an:

KAIMARKIT_MIDDLEWARES=${KAIMARKIT_TRAEFIK_NAME}-auth@docker

Eine Bedingung hat sie: KAIMARKIT_TRAEFIK_NAME muss in der Datei weiter oben stehen. Rückwärts setzt Compose eine leere Zeichenkette ein, meldet dazu nur eine Warnung und lässt den Aufruf weiterlaufen — der Router hieße dann -auth@docker und verschwände. In docker/.env.example steht die Traefik-Gruppe vor der Authelia-Gruppe, die Reihenfolge stimmt also von selbst.

Am Router steht kein fester Name. Dort entscheidet KAIMARKIT_MIDDLEWARES, und die eigene Middleware ist nur einer der zwei Werte, die dort sinnvoll sind.

Die API bleibt erreichbar

Hinter Authelia bekommt jeder Aufruf ohne Browser-Sitzung eine Weiterleitung zum Login. Ein curl bekäme also die Anmeldeseite statt Markdown, und jedes Skript liefe ins Leere.

Dagegen legt die Schicht einen zweiten Router allein für /api an:

<name> steht wieder für KAIMARKIT_TRAEFIK_NAME, voreingestellt kaimarkit:

Label Wert Wozu
…routers.<name>-api.rule Host(`${KAIMARKIT_DOMAIN}`) && PathPrefix(`/api`) Nur die API.
…routers.<name>-api.priority 100 Vorrang vor dem Router für alles Übrige.
…routers.<name>-api.service <name> Derselbe Dienst wie beim ersten Router.
…routers.<name>-api.middlewares ${KAIMARKIT_API_MIDDLEWARES-authelia@docker} Der Schalter, um den es geht.

Die feste Priorität ist Absicht. Ohne sie ordnet Traefik die Regeln nach Länge; das genügte hier zwar, weil die /api-Regel die längere ist, hinge aber am Wortlaut der anderen. Die Zahl macht den Vorrang davon unabhängig.

Für KAIMARKIT_API_MIDDLEWARES gibt es drei sinnvolle Werte.

Ein Middlewarename — der Standard, voreingestellt authelia@docker. Auch die API verlangt eine Anmeldung, Skripte kommen nicht durch.

Leer lassen — die API steht offen, die Oberfläche bleibt geschützt. Traefik liest ein leeres middlewares= als „keine Middleware“: Der Router bleibt aktiv und meldet keinen Fehler. Am 31.08.2026 mit Traefik 3.6.7 geprüft — der Router stand auf enabled, die Middlewareliste war leer, und ein Aufruf auf /api kam durch, während derselbe Aufruf auf / an Authelia hängenblieb. Ein auskommentierter Block in der Compose-Datei erübrigt sich damit; die leere Variable genügt.

Eine engere Middleware, etwa meine-allowlist@docker — der Mittelweg: eine IP-Allowlist statt der Anmeldung. Sie muss anderswo definiert sein, sonst verwirft Traefik den Router.

KAIMARKIT_MIDDLEWARES kennt dieselben drei Werte, und ein leerer Wert bedeutet auch dort „keine Middleware“ — dann steht die Oberfläche offen. Das ergibt selten Sinn: Wer die Anmeldung vor der Oberfläche nicht braucht, braucht die Authelia-Schicht nicht und bleibt bei Traefik.

Offene API heißt offener Dienst

Die gesamte Funktion von kaimarkit steckt in /api. Wer die Middleware entfernt, gibt sie preis — die Anmeldung schützt dann nur noch die Oberfläche. Das ist im internen Netz vertretbar und im offenen Internet nicht.

In der Compose-Datei steht der Wert in Anführungszeichen. Sie sorgen dafür, dass eine leere Variable als leere Zeichenkette ankommt; ein blanker Wert stünde in YAML für null.

Prüfen

Der Router und seine Middleware lassen sich unmittelbar ablesen:

curl -sf http://<traefik-host>:8080/api/http/routers | jq '.[] | select(.name | startswith("kaimarkit"))'

Der Filter nennt den voreingestellten Namensraum; bei abweichendem KAIMARKIT_TRAEFIK_NAME gehört dessen Wert dorthin.

Beide Router müssen dort mit "status": "enabled" stehen und im Feld middlewares den Namen führen, der in docker/.env steht. Steht einer auf disabled, nennt das Feld error die fehlende Middleware beim Namen.

Dann die beiden Wege gegeneinander:

# Eigene Domain einsetzen.
curl -si https://kaimarkit.example.com/ | head -1    # 302 zur Anmeldeseite
curl -sf https://kaimarkit.example.com/api/health    # bei leerer Variable: 200

Die Wahl der Middleware ist am 01.09.2026 gegen Traefik 3.6.25 durchgemessen, jedes Mal an /api/http/routers abgelesen statt aus der Compose-Datei geschlossen:

KAIMARKIT_MIDDLEWARES Router Antwort auf /
authelia@docker enabled, ["authelia@docker"] 401 von der ForwardAuth
kaimarkit-auth@docker enabled, ["kaimarkit-auth@docker"] 401 von der ForwardAuth
authelia@file (nicht vorhanden) disabled, Fehler middleware … does not exist 404
leer enabled, keine Middleware 200, ungeschützt

Die 401 stammt aus dem Messaufbau, in dem an Authelias Stelle ein Dienst stand, der jede Anfrage abweist. Eine echte Authelia antwortet an dieser Stelle mit 302 auf die Anmeldeseite. Beides heißt dasselbe: Die Anfrage erreichte kaimarkit nicht.

Der vollständige Durchlauf ist am 31.08.2026 gegen Authelia 4.38.19 hinter Traefik 3.6 gelaufen. Ein Aufruf ohne Sitzung endete mit 302 auf der Anmeldeseite, und zwar mit dem Rücksprungziel im Parameter rd. Nach der Anmeldung stand die Oberfläche unter KAIMARKIT_DOMAIN und füllte ihre Enginewahl aus /api/capabilities — der Aufruf kam also durch dieselbe Middleware. Nach dem Löschen des Sitzungscookies führte derselbe Weg wieder zur Anmeldeseite.

404 oder 400 — der Statuscode zeigt die Richtung

Antwortet der Dienst überhaupt nicht, entscheidet der Statuscode, wo man sucht:

  • 404 — kein Router greift. Die Ursache liegt bei Traefik oder bei den Labels dieser Schicht, etwa beim falschen Zusatz hinter dem @.
  • 400, als Klartext 400 Bad Request mit content-length: 15 — etwas hat geantwortet. Die Ursache liegt hinter der Middleware, also bei Authelia. Der nächstliegende Grund ist eine Domäne außerhalb ihrer Cookie-Domäne.

Authelia lässt sich direkt fragen, mit denselben Kopfzeilen, die Traefik ihr schickt:

docker run --rm --network <traefik-netz> curlimages/curl -s -o /dev/null -w '%{http_code}\n' \
  -H "X-Forwarded-Proto: https" -H "X-Forwarded-Host: <domain>" -H "X-Forwarded-Uri: /" \
  http://<authelia>:9091/api/authz/forward-auth

Dieser Aufruf hat die Ursache am 01.09.2026 am VPS-Aufbau des Nutzers gezeigt: Für einen Host außerhalb der Cookie-Domäne antwortete Authelia mit 400. Vorher waren Netz, Middlewarename, Entrypoint, Certresolver, Router-Status und DNS geprüft — alle in Ordnung. Der Statuscode allein zeigt in die falsche Richtung; erst die Frage an Authelia klärt sie.