Root Cause im echten Hermes-Sourcecode (hermes_cli/web_server.py, _ws_host_origin_reason) verifiziert, nicht geraten: WebSocket-Upgrades (/api/ws, /api/pub, /api/events) haben einen zweiten Guard neben dem Host-Header, der zusaetzlich den Origin-Header gegen den Bind (127.0.0.1) prueft. Browser schickt die echte Server-Adresse als Origin -> origin_mismatch -> WS wird mit 4403 (Browser: 1006) geschlossen, komplett ohne Logging (anders als /api/console + /api/pty). Fix: Origin-Header in Caddy entfernen, dann ueberspringt Hermes den Check ganz.
53 lines
2.7 KiB
Caddyfile
53 lines
2.7 KiB
Caddyfile
# Caddy-Config fuer den Hermes-Dashboard-Reverse-Proxy.
|
|
# Keine Secrets hier drin — Username/Passwort-Hash kommen als {$ENV_VAR}
|
|
# (Caddyfile-Shorthand fuer {env.ENV_VAR}) aus dem Container-Environment,
|
|
# das wiederum aus .env kommt (siehe docker-compose.yml, Service "caddy").
|
|
#
|
|
# TLS: bewusst kein "tls internal" (Caddys eigene interne CA, Zertifikate nur
|
|
# ~12h gueltig, auto-rotiert) und kein Let's Encrypt (braucht oeffentliche
|
|
# Domain + Port 80). Stattdessen ein selbstsigniertes Zertifikat mit 100
|
|
# Jahren Laufzeit — wird beim allerersten Container-Start automatisch vom
|
|
# Entrypoint in docker-compose.yml erzeugt (kein manueller openssl-Befehl
|
|
# noetig), landet persistent im /certs-Volume. Einmalig im Browser als
|
|
# Sicherheits-Ausnahme akzeptieren, danach nie wieder Renewal-Aerger.
|
|
:443 {
|
|
tls /certs/dashboard.crt /certs/dashboard.key
|
|
|
|
basic_auth {
|
|
{$HERMES_DASHBOARD_USER} {$CADDY_BASIC_AUTH_HASH}
|
|
}
|
|
|
|
# Hermes' Dashboard-Backend validiert den eingehenden Host-Header gegen
|
|
# den Host, an den es gebunden wurde (127.0.0.1:9119) -- Schutz gegen
|
|
# DNS-Rebinding. Caddy reicht per Default den ORIGINALEN Host-Header
|
|
# vom Browser durch (die Server-IP/Domain), das lehnt Hermes mit
|
|
# "Invalid Host header" ab. Deshalb hier den Host-Header explizit auf
|
|
# das ueberschreiben, worauf das Dashboard tatsaechlich lauscht.
|
|
#
|
|
# GLEICHES Problem existiert fuer WebSocket-Upgrades (Chat/Events-Feed,
|
|
# /api/ws + /api/pub + /api/events), nur eine Ebene tiefer und OHNE
|
|
# jede Fehlermeldung: Hermes' WS-Handshake-Guard (hermes_cli/web_server.py,
|
|
# _ws_host_origin_reason) prueft zusaetzlich zum Host-Header auch den
|
|
# Origin-Header gegen den Bind (127.0.0.1). Der Origin-Header vom Browser
|
|
# traegt aber immer die echte aufgerufene Adresse (Deine Server-IP/Domain),
|
|
# nicht 127.0.0.1 -- das ergibt "origin_mismatch" und Hermes schliesst die
|
|
# WS-Verbindung sofort mit Code 4403 (Browser zeigt oft 1006). Anders als
|
|
# beim Host-Header-Fehler auf der normalen HTTP-Seite loggt Hermes diese
|
|
# Ablehnung fuer /api/ws, /api/pub und /api/events NICHT (nur /api/console
|
|
# und /api/pty tun das) -- daher blieb der Chat-Fehler in den Logs
|
|
# unsichtbar, obwohl der Ablauf identisch zum Host-Header-Bug war. Fix:
|
|
# Origin-Header komplett entfernen, bevor die Anfrage ans Dashboard geht --
|
|
# fehlt der Origin-Header, ueberspringt Hermes den Origin-Check ganz
|
|
# (siehe _ws_host_origin_reason: "if not origin: return None").
|
|
reverse_proxy 127.0.0.1:9119 {
|
|
header_up Host 127.0.0.1:9119
|
|
header_up -Origin
|
|
}
|
|
}
|
|
|
|
# Optional-freundlich: wer versehentlich mit http:// statt https:// draufklickt,
|
|
# landet trotzdem verschluesselt statt an "connection refused".
|
|
:80 {
|
|
redir https://{host}{uri} permanent
|
|
}
|