# 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 }