Dashboard-Auth komplett entfernt statt nur optional: Caddy ist einzige Auth-Schicht

Hermes' eigenes Auth-Gate (dashboard.basic_auth/HERMES_DASHBOARD_PASSWORD_HASH)
engagiert sich laut eigener Fehlermeldung ohnehin nur bei einem 0.0.0.0-Bind,
der Dashboard-Container bindet aber fest auf 127.0.0.1 -- das Gate haette hier
nie gegriffen. Statt es als "Fallback falls Bind mal wieder wandert" zu
behalten, jetzt sauber raus: HERMES_DASHBOARD_PASSWORD_HASH aus .env.example
und docker-compose.yml, der auskommentierte dashboard:-Block aus
config.yaml.example, README-Setup auf 8 statt 9 Schritte umnummeriert.
Caddy (TLS + eigene Basic-Auth) ist damit die einzige noetige Auth-Schicht --
ein Layer statt zwei, weniger Setup, weniger Verwirrung. Stale Kommentare im
Caddy-Compose-Block (redeten noch von "zweiter Basic-Auth-Schicht noetig weil
unklar ob dashboard.basic_auth greift") ebenfalls korrigiert.
This commit is contained in:
ARIA
2026-07-19 22:23:22 +00:00
parent b1423ffb6e
commit 3aaddc4a31
4 changed files with 77 additions and 137 deletions
+44 -51
View File
@@ -28,9 +28,13 @@ hermes-agent (Nous Research, network_mode: host)
v
Anthropic (ueber deine Claude-Max-Subscription)
hermes-agent-dashboard (0.0.0.0:9119, Hermes' eigenes Web-UI/Setup, per
Basic-Auth gesichert seit 19.07.2026 — Stefans
Entscheidung, siehe Sicherheitshinweis)
hermes-agent-dashboard (127.0.0.1:9119, Hermes' eigenes Web-UI/Setup, nur
intern erreichbar)
^
| reverse_proxy
v
caddy (0.0.0.0:443, TLS + Basic-Auth — einzige Auth-/TLS-Schicht,
siehe Sicherheitshinweis)
```
Warum das Gateway trotzdem noch da ist, obwohl alles auf einer Maschine
@@ -83,28 +87,18 @@ aussen — kein anderer Rechner kommt mehr direkt ran.
beim Config-Laden aus den Container-Env-Vars expandiert, die kommen aus
Deiner `.env`. Kein manuelles Ausfuellen noetig.
4. **Dashboard-Auth: NICHT mehr noetig, ueberspringen.** (Historie: war
zwischenzeitlich Pflicht, solange `hermes-agent-dashboard` mit `--host
0.0.0.0` lief — Hermes verweigert diesen Bind hart ohne registrierten
Auth-Provider: `Refusing to bind dashboard to 0.0.0.0 — the auth gate
engages on non-loopback binds, but no auth providers are registered`.
Seit Schritt 5 unten (Caddy) bindet das Dashboard aber nur noch auf
`127.0.0.1` — Hermes' Auth-Gate engagiert sich laut eigener Fehlermeldung
NUR bei einem 0.0.0.0-Bind, hier greift's also gar nicht. Caddy macht die
eigentliche Absicherung nach aussen. `HERMES_DASHBOARD_USER`/
`_PASSWORD_HASH` in `.env` koennen leer bleiben, kein Hash-Erzeugen mehr
noetig.)
Nur falls Du den Dashboard-Bind mal wieder direkt auf `0.0.0.0` stellst
(z.B. um ohne Caddy zu testen), brauchst Du das wieder — dann in
`hermes-agent-config/config.yaml.example` (bzw. Deiner echten
`config.yaml`) den auskommentierten `dashboard:`-Block reaktivieren und
`HERMES_DASHBOARD_PASSWORD_HASH` in `.env` setzen (Anleitung dazu direkt
im Kommentar über dem Block, inkl. Dollarzeichen-Escaping-Falle).
5. **TLS-Reverse-Proxy (Caddy) einrichten — macht Port 443 von aussen
4. **TLS-Reverse-Proxy (Caddy) einrichten — macht Port 443 von aussen
erreichbar, Dashboard bleibt intern auf `127.0.0.1`:**
Hermes' eigenes Dashboard-Auth-Gate (`dashboard.basic_auth` in
`config.yaml` + `HERMES_DASHBOARD_PASSWORD_HASH`) ist bewusst NICHT mehr
Teil des Setups (aufgeraeumt am 19.07.2026, spaeter Abend/20.07.2026) —
das Gate engagiert sich laut eigener Fehlermeldung ohnehin nur bei einem
`0.0.0.0`-Bind, und der Dashboard-Container bindet fest auf `127.0.0.1`
(siehe `command:` im `hermes-agent-dashboard`-Service). Die komplette
Absicherung nach aussen laeuft ausschliesslich ueber Caddy unten —
ein Auth-Layer statt zwei, weniger Setup-Schritte, weniger Verwirrung.
a. Selbstsigniertes Zertifikat, 100 Jahre gueltig (bewusst kein Let's
Encrypt — kein Domain-/Port-80-Zwang, kein Renewal je wieder noetig).
**Erzeugt sich automatisch** — kein manueller Schritt mehr noetig: der
@@ -128,21 +122,22 @@ aussen — kein anderer Rechner kommt mehr direkt ran.
-subj "/CN=hermes-dashboard"
```
b. Caddy-Basic-Auth-Hash erzeugen (EIGENER Hash, nicht derselbe wie bei
Schritt 4 — Caddy will bcrypt, Hermes' Hash ist pbkdf2):
b. Caddy-Basic-Auth-Hash erzeugen (bcrypt, das einzige Auth-Secret das es
jetzt noch braucht):
```bash
docker run --rm caddy:2-alpine caddy hash-password --plaintext 'DEIN-PASSWORT'
```
Output in `.env` bei `CADDY_BASIC_AUTH_HASH` eintragen, danach —
**gleiche Dollarzeichen-Falle wie bei Schritt 4** (bcrypt-Hashes haben
auch rohe `$`-Zeichen drin) — escapen:
**Dollarzeichen-Falle** (bcrypt-Hashes haben rohe `$`-Zeichen drin,
Docker Compose interpretiert `$xyz` in `.env`-Werten sonst als eigene
Variablen-Referenz und ersetzt still durch Leerstring) — escapen:
```bash
sed -i '/^CADDY_BASIC_AUTH_HASH=/ s/\$/$$/g' .env
```
`HERMES_DASHBOARD_USER` aus Schritt 4 wird wiederverwendet (dasselbe
Login gilt fuer beide Auth-Schichten).
`HERMES_DASHBOARD_USER` aus Schritt 2 (`.env`) wird als Login-Name
wiederverwendet.
6. **Stack starten:**
5. **Stack starten:**
```bash
docker compose up -d
```
@@ -150,18 +145,17 @@ aussen — kein anderer Rechner kommt mehr direkt ran.
paar Minuten), startet dann `hermes-proxy`, `hermes-gateway`,
`hermes-agent` (Gateway/Messaging-Prozess), `hermes-agent-dashboard` und
`caddy`. Falls `CADDY_BASIC_AUTH_HASH` noch leer ist: `caddy` bricht beim
Start ab, die anderen laufen trotzdem — Wert nachtragen (Schritt 5b), dann
`docker compose up -d caddy`. `HERMES_DASHBOARD_PASSWORD_HASH` darf leer
bleiben (siehe Schritt 4).
Start ab, die anderen laufen trotzdem — Wert nachtragen (Schritt 4b), dann
`docker compose up -d caddy`.
7. **Einmalig Claude-CLI-Login** (oeffnet Browser-OAuth mit deiner Claude-Max-Subscription):
6. **Einmalig Claude-CLI-Login** (oeffnet Browser-OAuth mit deiner Claude-Max-Subscription):
```bash
docker exec -it hermes-proxy claude
```
Danach liegen die Credentials persistent in `hermes-data/claude-config/`
— ueberlebt Container-Restarts.
8. **Testen, dass der Proxy laeuft:**
7. **Testen, dass der Proxy laeuft:**
```bash
curl -s http://127.0.0.1:${HERMES_GATEWAY_PORT:-8447}/v1/chat/completions \
-H "Content-Type: application/json" \
@@ -170,7 +164,7 @@ aussen — kein anderer Rechner kommt mehr direkt ran.
```
Ohne oder mit falschem Bearer-Token gibt's `401 unauthorized`.
9. **Mit Hermes chatten:**
8. **Mit Hermes chatten:**
```bash
docker exec -it hermes-agent hermes chat
```
@@ -179,7 +173,7 @@ aussen — kein anderer Rechner kommt mehr direkt ran.
beim ersten Aufruf "Zertifikat nicht vertrauenswuerdig" (weil selbstsigniert,
nicht von einer oeffentlichen CA) — einmalig als Ausnahme akzeptieren
("Trotzdem fortfahren" o.ae.), danach fragt Caddy den Basic-Auth-Login aus
Schritt 5b ab. Traffic ist ab hier durchgehend TLS-verschluesselt, kein
Schritt 4b ab. Traffic ist ab hier durchgehend TLS-verschluesselt, kein
SSH-Tunnel mehr noetig.
## Mobiler Client (Android)?
@@ -203,18 +197,17 @@ Zwei GRUNDVERSCHIEDENE Richtungen, nicht verwechseln:
ran, solange Du nicht selbst was aendertst (z.B. fuer den mobilen API-Server
oben, oder falls Hermes doch mal auf eine zweite Maschine zieht).
`hermes-agent-dashboard` bindet seit dem 19.07.2026, spaeter Abend, wieder
auf `127.0.0.1` — von aussen nicht mehr direkt erreichbar. Davor steht seitdem
`caddy` (Service in `docker-compose.yml`, Config in `Caddyfile`): terminiert
TLS auf Port 443 mit einem selbstsignierten 100-Jahre-Zertifikat (Setup-Schritt
5a) und erzwingt eine EIGENE Basic-Auth-Schicht (Setup-Schritt 5b, eigener
bcrypt-Hash in `CADDY_BASIC_AUTH_HASH` — nicht derselbe wie Hermes' pbkdf2-Hash).
Zwei Gruende fuer die doppelte Auth statt nur auf Hermes' eigene zu vertrauen:
1. Hermes' Auth-Gate "engagiert" laut eigener Fehlermeldung nur bei einem
0.0.0.0-Bind — auf 127.0.0.1 (das Caddy anspricht) ist nicht garantiert,
dass `dashboard.basic_auth` noch durchgesetzt wird.
2. Selbst wenn doch: zwei unabhaengige Schichten sind ohnehin robuster als
eine, falls in Zukunft mal eine davon falsch konfiguriert wird.
`hermes-agent-dashboard` bindet fest auf `127.0.0.1` — von aussen nicht mehr
direkt erreichbar. Davor steht `caddy` (Service in `docker-compose.yml`,
Config in `Caddyfile`): terminiert TLS auf Port 443 mit einem selbstsignierten
100-Jahre-Zertifikat (Setup-Schritt 4a) und erzwingt eine Basic-Auth-Schicht
(Setup-Schritt 4b, bcrypt-Hash in `CADDY_BASIC_AUTH_HASH`). Caddy ist die
EINZIGE Auth-/TLS-Schicht — Hermes' eigenes Dashboard-Auth-Gate
(`dashboard.basic_auth`/`HERMES_DASHBOARD_PASSWORD_HASH`) wurde bewusst
komplett rausgenommen (aufgeraeumt 20.07.2026): es engagiert sich laut eigener
Fehlermeldung ohnehin nur bei einem 0.0.0.0-Bind, der Dashboard-Container
bindet aber fest auf 127.0.0.1 — ein zweiter, nie greifender Auth-Layer haette
nur Setup-Schritte und Verwirrung gekostet, ohne echten Sicherheitsgewinn.
Das war vorher (kurzzeitig, testweise) `0.0.0.0` OHNE TLS — Passwort ging als
Basic-Auth im Klartext raus. Ist jetzt behoben: einziger von aussen offene
@@ -222,7 +215,7 @@ Port ist 443, durchgehend verschluesselt.
Das Zertifikat ist selbstsigniert (keine oeffentliche CA dahinter) — Browser
zeigen beim ersten Aufruf eine Warnung, die Du einmalig als Ausnahme
akzeptierst (Details siehe Setup-Schritt 9). Wer eine "echte", warnungsfreie
akzeptierst (Details siehe Setup-Schritt 8). Wer eine "echte", warnungsfreie
CA-Kette will, braucht dafuer eine oeffentliche Domain + Let's Encrypt — war
hier bewusst nicht der Plan.
@@ -240,7 +233,7 @@ Caddy-Reverse-Proxy davorschalten.
(`config.yaml`, aus `hermes-agent-config/config.yaml.example` geseedet),
Sessions, Memory, Skills, `.env`
- `hermes-data/caddy-certs/` — selbstsigniertes 100-Jahre-Zertifikat
(`dashboard.crt`/`dashboard.key`, Setup-Schritt 5a) — Private Key, niemals
(`dashboard.crt`/`dashboard.key`, Setup-Schritt 4a) — Private Key, niemals
committen
- `hermes-data/caddy-data/`, `hermes-data/caddy-config/` — Caddys eigener
Runtime-State (nicht von Dir angefasst)