diff --git a/.env.example b/.env.example index 8b80ce6..6d6969d 100644 --- a/.env.example +++ b/.env.example @@ -23,10 +23,12 @@ HERMES_GID=10000 # Pflicht seit 19.07.2026, SOBALD hermes-agent-dashboard auf 0.0.0.0 bindet: # Hermes verweigert sonst den Start hart ("no auth providers are registered"). # HERMES_DASHBOARD_USER ist Klartext (frei waehlbar), HERMES_DASHBOARD_PASSWORD_HASH -# ist NIEMALS das Klartext-Passwort, sondern der Hash daraus. Erzeugen (einmalig, -# im laufenden Dashboard-Container): -# docker exec -it hermes-agent-dashboard python -c \ +# ist NIEMALS das Klartext-Passwort, sondern der Hash daraus. Erzeugen (einmalig): +# docker exec -it hermes-agent python -c \ # "from plugins.dashboard_auth.basic import hash_password; print(hash_password('DEIN-PASSWORT'))" +# WICHTIG: gegen den "hermes-agent"-Container, NICHT "hermes-agent-dashboard" — +# der braucht HERMES_DASHBOARD_PASSWORD_HASH schon zum Hochfahren (Henne-Ei- +# Problem, siehe docker-compose.yml), "hermes-agent" laeuft auch ohne. # Den Output (nicht das Passwort selbst!) hier eintragen. HERMES_DASHBOARD_USER=admin HERMES_DASHBOARD_PASSWORD_HASH= diff --git a/README.md b/README.md index 081a6ac..4143f15 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,9 @@ hermes-agent (Nous Research, network_mode: host) v Anthropic (ueber deine Claude-Max-Subscription) -hermes-agent-dashboard (127.0.0.1:9119, Hermes' eigenes Web-UI/Setup) +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) ``` Warum das Gateway trotzdem noch da ist, obwohl alles auf einer Maschine @@ -81,22 +83,48 @@ 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. **Stack starten:** +4. **Dashboard-Auth einrichten** (Pflicht seit 19.07.2026 — `hermes-agent-dashboard` + laeuft mit `--host 0.0.0.0` und Hermes verweigert diesen Bind hart, wenn + kein Auth-Provider registriert ist: `Refusing to bind dashboard to + 0.0.0.0 — the auth gate engages on non-loopback binds, but no auth + providers are registered`. Ohne diesen Schritt kommt der Dashboard- + Container beim naechsten Schritt gar nicht hoch): + ```bash + # HERMES_DASHBOARD_USER in .env ist Klartext, HERMES_DASHBOARD_PASSWORD_HASH + # ist NIEMALS das Klartext-Passwort, sondern der Hash daraus. Erzeugen kannst + # Du den erst NACHDEM Schritt 5 unten (docker compose up -d) mindestens + # hermes-agent hochgefahren hat -- gegen "hermes-agent", NICHT + # "hermes-agent-dashboard" (der braucht den Hash schon zum Start, Henne-Ei): + docker exec -it hermes-agent python -c \ + "from plugins.dashboard_auth.basic import hash_password; print(hash_password('DEIN-PASSWORT'))" + ``` + Output (den Hash, nicht das Passwort) in `.env` bei `HERMES_DASHBOARD_PASSWORD_HASH` + eintragen, `HERMES_DASHBOARD_USER` nach Belieben setzen (Default `admin`). + Der `dashboard.basic_auth`-Block dazu liegt schon fertig in + `hermes-agent-config/config.yaml.example` (Platzhalter, die Hermes selbst + aus den Container-Env-Vars expandiert — kein manuelles Ausfuellen noetig, + siehe Schritt 3). + +5. **Stack starten:** ```bash docker compose up -d ``` Baut beim ersten Mal das Hermes-Image aus `hermes-agent-src` (dauert ein paar Minuten), startet dann `hermes-proxy`, `hermes-gateway`, `hermes-agent` (Gateway/Messaging-Prozess) und `hermes-agent-dashboard`. + Falls `HERMES_DASHBOARD_PASSWORD_HASH` noch leer ist (Schritt 4 noch nicht + gemacht): `hermes-agent-dashboard` bricht beim Start ab, die anderen drei + Services laufen trotzdem — Hash nachtragen, dann + `docker compose up -d hermes-agent-dashboard`. -5. **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. -6. **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" \ @@ -105,15 +133,15 @@ aussen — kein anderer Rechner kommt mehr direkt ran. ``` Ohne oder mit falschem Bearer-Token gibt's `401 unauthorized`. -7. **Mit Hermes chatten:** +8. **Mit Hermes chatten:** ```bash docker exec -it hermes-agent hermes chat ``` - oder das Dashboard per SSH-Tunnel oeffnen: - ```bash - ssh -L 9119:localhost:9119 - ``` - dann im Browser `http://localhost:9119`. + oder das Dashboard direkt im Browser oeffnen: `http://:9119` + — bindet auf `0.0.0.0`, kein SSH-Tunnel mehr noetig, dafuer fragt es jetzt + den Basic-Auth-Login aus Schritt 4 ab. Traffic ist weiterhin unverschluesseltes + HTTP (siehe Sicherheitshinweis unten) — fuer mehr als "kurz testen" gehoert + ein TLS-Reverse-Proxy davor. ## Mobiler Client (Android)? @@ -132,13 +160,24 @@ Zwei GRUNDVERSCHIEDENE Richtungen, nicht verwechseln: ## Sicherheitshinweis -`hermes-gateway` bindet jetzt nur noch auf `127.0.0.1` — von aussen kommt -niemand mehr 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). Wenn Du `HERMES_GATEWAY_PORT` oder `API_SERVER_HOST` doch mal nach -aussen exposest: der Traffic ist unverschluesseltes HTTP, kein TLS. Nicht -direkt ins offene Internet haengen — SSH-Tunnel, WireGuard/Tailscale oder -einen TLS-Reverse-Proxy davorschalten. +`hermes-gateway` bindet nur auf `127.0.0.1` — von aussen kommt niemand mehr +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 19.07.2026 bewusst auf `0.0.0.0` (Stefans +Entscheidung — ein SSH-Tunnel machte mit dem SSL-Setup Probleme) und ist per +Basic-Auth gesichert (siehe Setup-Schritt 4, Hermes verweigert den 0.0.0.0-Bind +sonst ohnehin hart). Das ist Testzustand, kein Dauerbetrieb-Haerten: das +Passwort geht als HTTP Basic-Auth unverschluesselt raus (kein TLS auf Port +9119), Keys/Config/Sessions liegen dahinter offen. Fuer Dauerbetrieb gehoert +ein TLS-Reverse-Proxy (Caddy/nginx) davor, der Basic-Auth + Zertifikat +uebernimmt — Dashboard-Port dann wieder `127.0.0.1`, nur der Proxy von aussen +erreichbar. + +Generell gilt: wenn Du `HERMES_GATEWAY_PORT`, `API_SERVER_HOST` oder den +Dashboard-Port doch mal direkt nach aussen exposest, ist der Traffic +unverschluesseltes HTTP, kein TLS. Nicht direkt ins offene Internet haengen — +SSH-Tunnel, WireGuard/Tailscale oder einen TLS-Reverse-Proxy davorschalten. ## Verzeichnisse (nicht committet, siehe .gitignore) diff --git a/hermes-agent-config/config.yaml.example b/hermes-agent-config/config.yaml.example index b2e0edf..6720712 100644 --- a/hermes-agent-config/config.yaml.example +++ b/hermes-agent-config/config.yaml.example @@ -39,9 +39,13 @@ model: # but no auth providers are registered"). Ohne diesen Block bindet's nur # noch auf 127.0.0.1 (Tunnel), egal was im docker-compose `command:` steht. # -# Hash EINMALIG erzeugen (im laufenden Dashboard-Container, NICHT das -# Klartext-Passwort committen oder in .env schreiben — nur den Hash): -# docker exec -it hermes-agent-dashboard python -c \ +# Hash EINMALIG erzeugen (NICHT das Klartext-Passwort committen oder in .env +# schreiben — nur den Hash). Gegen den "hermes-agent"-Container, NICHT +# "hermes-agent-dashboard" — der braucht HERMES_DASHBOARD_PASSWORD_HASH schon +# zum Hochfahren (Henne-Ei-Problem: ohne Hash kein Start, ohne laufenden +# Container kein Hash). "hermes-agent" teilt sich dasselbe Image und laeuft +# auch ohne den Wert: +# docker exec -it hermes-agent python -c \ # "from plugins.dashboard_auth.basic import hash_password; print(hash_password('DEIN-PASSWORT'))" # Ergebnis nach .env als HERMES_DASHBOARD_PASSWORD_HASH eintragen. #