Diese Dokumentation beschreibt die Schutz- und Fehlerbehandlung des Traefik-Reverse-Proxys für unbekannte Hosts, verdächtige URL-Pfade und automatisierte Exploit-Scans.
Die Konfiguration ist historisch gewachsen und wurde insbesondere im Zusammenhang mit Nextcloud eingerichtet. Mehrere Middleware-Regeln entstanden nach umfangreicher Fehlersuche, um Probleme mit Redirects, Security-Headern, WebDAV/CalDAV und anderen Nextcloud-Funktionen zu vermeiden.
Die bestehenden Middleware-Ketten nicht ohne vorherige Tests vereinfachen oder entfernen.
Insbesondere Änderungen an block-paths, php-endings, global-chain und global-secure-chain können Auswirkungen auf bestehende Anwendungen haben.
Grundsatz: Funktionierende Konfiguration zuerst dokumentieren, dann nur kontrolliert und einzeln verändern.
Der öffentliche HTTP-/HTTPS-Verkehr erreicht zunächst Traefik.
Vereinfachter Ablauf:
Internet
|
v
FRITZ!Box
|
v
Traefik
|
+---- bekannter Host ------> definierter Router ------> Anwendung
|
+---- unbekannter Host ----> Catch-all
|
v
Middleware
|
v
errorpage
|
v
HTTP 418
Der Errorpage-Container dient dabei als kontrolliertes Ziel fĂĽr nicht zuordenbare bzw. fehlerhafte Requests.
Wichtige EntryPoints:
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
imap:
address: ":993"
smtp:
address: ":587"
smtp25:
address: ":25"
ssh:
address: ":58222"
matrix:
address: ":8448"
metrics:
address: ":8082"
Der Metrics-EntryPoint ist für Prometheus vorgesehen und wird nicht nach außen veröffentlicht.
Traefik verwendet den Docker Provider:
providers:
docker:
exposedByDefault: false
network: docker_backend
file:
directory: /etc/traefik/dynamic/
watch: true
Durch
exposedByDefault: false
werden Docker-Container nicht automatisch über Traefik veröffentlicht.
Ein Container muss explizit ĂĽber entsprechende Traefik-Labels aktiviert werden.
Die dynamische Konfiguration befindet sich unter:
/etc/traefik/dynamic/
Zum Zeitpunkt der Dokumentation existieren unter anderem:
crowdsec.yml dokuzusatz.yml errorpage.yml security.yml adynamic.yml tcp.yml
Zusätzlich existieren einige .bak-Dateien.
Bei der Fehlersuche immer zuerst prüfen, welche Dateien tatsächlich aktiv geladen werden und welche lediglich Backups sind.
In adynamic.yml existiert ein Catch-all:
catchall:
rule: "HostRegexp(`{host:.+}`)"
entryPoints:
- web
- websecure
service: noop@internal
middlewares:
- custom-404
- global-secure-chain
Dieser Router kann Requests auffangen, deren Hostname keinem spezifischeren Router zugeordnet wird.
Dadurch landen beispielsweise automatisierte Internet-Scans gegen die öffentliche IP-Adresse nicht direkt bei einer internen Anwendung.
In errorpage.yml existieren zusätzlich Router mit niedriger Priorität:
catchall-http:
rule: "PathPrefix(`/`)"
entryPoints: [web]
priority: -10
service: error-svc
middlewares:
- custom-404
- global-chain
FĂĽr HTTPS:
catchall-https:
rule: "PathPrefix(`/`)"
entryPoints: [websecure]
priority: -10
tls: {}
service: error-svc
middlewares:
- custom-404
- global-chain
Die niedrige Priorität sorgt dafür, dass spezifische Router bevorzugt werden.
Die Fehlerbehandlung erfolgt ĂĽber:
custom-404:
errors:
status:
- "404-599"
service: error-svc
query: "/?s={status}"
Als Error-Service dient:
error-svc:
loadBalancer:
servers:
- url: "http://errorpage:8080"
Damit werden HTTP-Fehler im Bereich 404 bis 599 an den eigenen Errorpage-Container weitergereicht.
Der Container basiert auf Nginx.
Mounts:
/opt/stacks/traefik/errorpage/nginx.conf
-> /etc/nginx/nginx.conf
/opt/stacks/traefik/errorpage
-> /usr/share/nginx/html
Die relevante Nginx-Konfiguration lautet:
events {}
http {
server {
listen 8080;
listen [::]:8080;
server_name localhost;
location / {
return 418;
}
error_page 418 /index.html;
location = /index.html {
root /usr/share/nginx/html;
internal;
}
location = /sprueche.json {
root /usr/share/nginx/html;
internal;
}
}
}
Damit beantwortet der Container beliebige Requests kontrolliert mit:
HTTP/1.1 418
also:
418 I'm a teapot
Direkter Test innerhalb des Docker-Netzes:
docker run --rm \ --network docker_backend \ curlimages/curl \ -sv \ -H 'Host: 79.254.196.8' \ 'http://errorpage:8080/irgendwas-vollkommen-unbekannt.php' \ -o /dev/null
Erwartete Antwort:
HTTP/1.1 418 Server: nginx Content-Type: text/html
Bei der Analyse vom 21.08.2026 betrug die Größe der Fehlerseite:
Content-Length: 38337
Dies ist wichtig fĂĽr die Analyse von Suricata-Ereignissen:
Wenn dort bei einem verdächtigen Request eine Antwortgröße von ungefähr 38337 Byte zusammen mit HTTP 418 auftaucht, handelt es sich sehr wahrscheinlich um die eigene Errorpage und nicht um die Ausgabe einer angegriffenen Anwendung.
Die zentrale Security-Konfiguration befindet sich in:
/etc/traefik/dynamic/security.yml
CrowdSec wird ĂĽber ForwardAuth eingebunden:
crowdsec-forwardauth:
forwardAuth:
address: "http://crowdsec-bouncer:8080/api/v1/forwardAuth"
trustForwardHeader: true
authResponseHeaders:
- X-Forwarded-For
- X-Real-IP
Typische Scanner- und Angriffspfade werden durch block-paths behandelt:
block-paths:
redirectRegex:
regex: ^/(?:\.env(?:$|/)|\.git(?:$|/)|\.svn(?:$|/)|\.hg(?:$|/)|\.idea(?:$|/)|backup(?:$|/)|vendor(?:$|/)|cgi-bin(?:$|/)).*
replacement: /
permanent: false
Erfasst werden insbesondere:
permanent: false erzeugt bei einem Treffer einen temporären Redirect.
Dadurch können bei Suricata-Ereignissen HTTP-302-Antworten sichtbar werden.
Ein HTTP 302 auf einen Exploit-Pfad bedeutet daher nicht automatisch, dass die angegriffene Anwendung diesen Redirect erzeugt hat.
Der Redirect kann vollständig von der Traefik-Security-Middleware stammen.
Zusätzlich existiert:
php-endings:
redirectRegex:
regex: \.php(?:$|\?)
replacement: /
permanent: false
Diese Middleware ist dafĂĽr vorgesehen, direkte Requests auf PHP-Dateien abzufangen.
Sie ist nicht in allen Middleware-Ketten aktiv.
Ohne CrowdSec:
global-chain:
chain:
middlewares:
- block-paths
- php-endings
- sec-headers
- ratelimit
- compress
Mit CrowdSec:
global-secure-chain:
chain:
middlewares:
- crowdsec-forwardauth
- block-paths
# - php-endings
- sec-headers
- ratelimit
- compress
Wichtig:
php-endings ist hier bewusst nicht aktiv.
Für administrative Oberflächen existiert eine strengere Chain:
admin-chain:
chain:
middlewares:
- crowdsec-forwardauth
- block-paths
- php-endings
- admin-ips
- admin-rl
- sec-headers
- compress
- admin-basic
Die allgemeinen Security Header umfassen unter anderem:
sec-headers:
headers:
frameDeny: true
contentTypeNosniff: true
referrerPolicy: no-referrer-when-downgrade
permissionsPolicy: geolocation=(), microphone=(), camera=()
customResponseHeaders:
Server: ""
Allgemeines Rate Limit:
ratelimit:
rateLimit:
average: 50
burst: 100
period: 1s
Für administrative Oberflächen:
admin-rl:
rateLimit:
average: 10
burst: 20
period: 1s
FĂĽr Nextcloud existieren gesonderte Header-Einstellungen.
Beispielsweise:
security-headers:
headers:
frameDeny: false
customFrameOptionsValue: "SAMEORIGIN"
contentTypeNosniff: true
browserXssFilter: true
Die Konfiguration wurde nach umfangreicher Fehlersuche eingefĂĽhrt, da allgemeinere bzw. strengere Middleware-Regeln wiederholt Probleme mit Nextcloud und einzelnen Funktionen verursachten.
Nextcloud reagiert empfindlich auf Änderungen an Reverse-Proxy-, Header- und Redirect-Konfigurationen.
Änderungen deshalb niemals gleichzeitig an mehreren Middleware-Komponenten durchführen.
Am 21.08.2026 wurde über Suricata ein automatisierter Exploitversuch gegen den öffentlich erreichbaren Traefik erkannt.
Unter anderem wurden typische PHP-/PHPUnit- und RCE-Pfade angesprochen.
Beispiel:
/vendor/phpunit/...
Solche Requests treffen auf die vorhandene Middleware:
Request
|
v
Traefik
|
v
global-secure-chain
|
+--> CrowdSec
|
+--> block-paths
|
+--> /vendor/... erkannt
|
v
HTTP Redirect
Andere nicht zuordenbare Requests können dagegen beim Catch-all bzw. Errorpage-Service enden:
Internet Scanner
|
v
Traefik
|
v
Catch-all
|
v
custom-404
|
v
errorpage:8080
|
v
HTTP 418
Die Untersuchung ergab:
redirectRegex der Security-Middlewares entstehen.Bewertung: automatisierter Exploit-Scan, erfolgreich durch vorhandene Proxy-/Security-Struktur abgefangen.
Bei einem neuen Web-Attack-Alarm nicht allein anhand des HTTP-Status entscheiden, ob ein Backend tatsächlich angesprochen wurde.
Folgende Punkte prĂĽfen:
flow_idBesonders wichtig:
HTTP 302
kann durch redirectRegex entstehen.
HTTP 418 Content-Length: ~38337
HTTP 418 zusammen mit einer Response-Größe um 38 KB ist ein starker Hinweis auf die eigene Errorpage. Die genaue Größe hängt von der aktuellen Version der index.html ab. Die zufällig angezeigten Sprüche verändern die HTTP-Response-Größe nicht, da sie clientseitig per JavaScript ausgewählt werden.
Einen kompletten Flow aus eve.json ausgeben:
sudo jq -c ' select(.flow_id == FLOW_ID) ' /opt/stacks/suricata/data/eve.json
Beispiel:
sudo jq -c ' select(.flow_id == 2246373244831953) ' /opt/stacks/suricata/data/eve.json
Test gegen Traefik mit unbekanntem Host:
curl -sv \ -H 'Host: 79.254.196.8' \ 'http://192.168.178.96/irgendwas-vollkommen-unbekannt.php' \ -o /dev/null
Damit lässt sich prüfen, wie Traefik einen Request behandelt, der keinem normalen Host-Router entspricht.
Ohne Traefik:
docker exec traefik sh -c ' wget -S -O /dev/null \ --header="Host: test.invalid" \ "http://errorpage:8080/test.php" '
Erwartet:
HTTP/1.1 418
Dieser Test ist besonders hilfreich, um zwischen einer Traefik-Antwort und einer Antwort des Errorpage-Containers zu unterscheiden.
Geladene dynamische Dateien:
docker exec traefik sh -c ' find /etc/traefik/dynamic -maxdepth 2 -type f -print '
Nach Redirects und Catch-all-Regeln suchen:
docker exec traefik sh -c ' grep -RniE "HostRegexp|redirect|replacePath|replacePathRegex|stripPrefix|addPrefix|418|catch|fallback" \ /etc/traefik/dynamic 2>/dev/null '
Errorpage-Nginx prĂĽfen:
docker exec errorpage nginx -T
Traefik-Konfiguration anzeigen:
docker exec traefik cat /etc/traefik/traefik.yml
Never change a running system ohne RĂĽckfallplan.
Vor Änderungen an der Traefik-Security-Konfiguration:
Falls nach einer Änderung unerklärliche Nextcloud-Fehler auftreten, zuerst die zuletzt geänderte Middleware zurücksetzen.
Die Kombination aus Traefik, CrowdSec, Security-Middlewares, Catch-all-Routern und eigener HTTP-418-Errorpage bildet eine zusätzliche Schutzschicht vor den eigentlichen Anwendungen.
Automatisierte Scanner können dadurch Antworten wie HTTP 302 oder HTTP 418 erhalten, ohne dass der angesprochene Exploit-Pfad auf einem Backend tatsächlich existiert.
Die vorhandene Konfiguration ist historisch gewachsen und teilweise das Ergebnis umfangreicher Fehlersuche, insbesondere mit Nextcloud.
Sie sollte daher nicht allein aus Gründen einer vermeintlich saubereren oder einfacheren Konfiguration verändert werden.
Stabilität und nachvollziehbares Verhalten haben Vorrang vor kosmetischer Vereinfachung.