Gateway+Dashboard in einen Container zusammenfassen (HERMES_DASHBOARD=1)
hermes-agent-dashboard als separater Container ist raus. Stattdessen supervised s6 Gateway und Dashboard jetzt als Geschwister-Prozesse im selben hermes-agent-Container (HERMES_DASHBOARD=1 + HERMES_DASHBOARD_HOST= 127.0.0.1) -- laut Startup-Log selbst "the recommended setup for the s6 container image". Das ist der wahrscheinliche Fix fuer zwei offene Bugs: Dashboard zeigte Gateway-Status immer als "Stopped" (lokale Prozess- Inspektion sah den Gateway-Prozess im getrennten Container nie) und der Restart-Button warf "no such gateway 'default'" (loeste s6-Services nur im eigenen Container auf). README + Architektur-Diagramm entsprechend aktualisiert.
This commit is contained in:
@@ -28,15 +28,32 @@ hermes-agent (Nous Research, network_mode: host)
|
|||||||
v
|
v
|
||||||
Anthropic (ueber deine Claude-Max-Subscription)
|
Anthropic (ueber deine Claude-Max-Subscription)
|
||||||
|
|
||||||
hermes-agent-dashboard (127.0.0.1:9119, Hermes' eigenes Web-UI/Setup, nur
|
hermes-agent (EIN Container, s6 supervisiert Gateway + Dashboard als
|
||||||
intern erreichbar)
|
Geschwister-Prozesse via HERMES_DASHBOARD=1):
|
||||||
|
- Gateway-Prozess: Messaging-Bruecke, redet mit Claude wie oben
|
||||||
|
- Dashboard-Prozess: 127.0.0.1:9119, Hermes' eigenes Web-UI, nur intern
|
||||||
|
erreichbar
|
||||||
^
|
^
|
||||||
| reverse_proxy
|
| reverse_proxy (Dashboard-Port)
|
||||||
v
|
v
|
||||||
caddy (0.0.0.0:443, TLS + Basic-Auth — einzige Auth-/TLS-Schicht,
|
caddy (0.0.0.0:443, TLS + Basic-Auth — einzige Auth-/TLS-Schicht,
|
||||||
siehe Sicherheitshinweis)
|
siehe Sicherheitshinweis)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Wichtig, Kurskorrektur 20.07.2026:** Gateway und Dashboard liefen anfangs
|
||||||
|
in ZWEI getrennten Containern (`hermes-agent` + `hermes-agent-dashboard`,
|
||||||
|
jeweils dasselbe Image mit anderem `command:`). Das verursachte zwei reale
|
||||||
|
Bugs: Dashboard zeigte den Gateway-Status immer als "Stopped" (die Status-
|
||||||
|
Pruefung ist eine LOKALE Prozess-Inspektion im eigenen Container, nicht per
|
||||||
|
Netzwerk-Call — im getrennten Container sah sie den Gateway-Prozess nie),
|
||||||
|
und der "Restart Gateway"-Button im Dashboard scheiterte mit `no such
|
||||||
|
gateway 'default'` (der Button loest s6-Services im EIGENEN Container auf,
|
||||||
|
im Dashboard-Container gab's aber keinen). Der Startup-Log hatte den
|
||||||
|
Hinweis die ganze Zeit schon dabei: *"dashboard supervised alongside if
|
||||||
|
HERMES_DASHBOARD is set. This is the recommended setup for the s6 container
|
||||||
|
image."* Jetzt EIN `hermes-agent`-Container mit `HERMES_DASHBOARD=1` +
|
||||||
|
`HERMES_DASHBOARD_HOST=127.0.0.1` — kein separater Dashboard-Service mehr.
|
||||||
|
|
||||||
Warum das Gateway trotzdem noch da ist, obwohl alles auf einer Maschine
|
Warum das Gateway trotzdem noch da ist, obwohl alles auf einer Maschine
|
||||||
laeuft: `hermes-proxy` selbst hat keine Authentifizierung (genau wie ARIAs
|
laeuft: `hermes-proxy` selbst hat keine Authentifizierung (genau wie ARIAs
|
||||||
Proxy) — jeder andere Container im selben Docker-Host koennte sonst
|
Proxy) — jeder andere Container im selben Docker-Host koennte sonst
|
||||||
@@ -94,10 +111,11 @@ aussen — kein anderer Rechner kommt mehr direkt ran.
|
|||||||
`config.yaml` + `HERMES_DASHBOARD_PASSWORD_HASH`) ist bewusst NICHT mehr
|
`config.yaml` + `HERMES_DASHBOARD_PASSWORD_HASH`) ist bewusst NICHT mehr
|
||||||
Teil des Setups (aufgeraeumt am 19.07.2026, spaeter Abend/20.07.2026) —
|
Teil des Setups (aufgeraeumt am 19.07.2026, spaeter Abend/20.07.2026) —
|
||||||
das Gate engagiert sich laut eigener Fehlermeldung ohnehin nur bei einem
|
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`
|
`0.0.0.0`-Bind, und das Dashboard bindet fest auf `127.0.0.1`
|
||||||
(siehe `command:` im `hermes-agent-dashboard`-Service). Die komplette
|
(`HERMES_DASHBOARD_HOST` im `hermes-agent`-Service, siehe
|
||||||
Absicherung nach aussen laeuft ausschliesslich ueber Caddy unten —
|
`docker-compose.yml`). Die komplette Absicherung nach aussen laeuft
|
||||||
ein Auth-Layer statt zwei, weniger Setup-Schritte, weniger Verwirrung.
|
ausschliesslich ueber Caddy unten — ein Auth-Layer statt zwei, weniger
|
||||||
|
Setup-Schritte, weniger Verwirrung.
|
||||||
|
|
||||||
a. Selbstsigniertes Zertifikat, 100 Jahre gueltig (bewusst kein Let's
|
a. Selbstsigniertes Zertifikat, 100 Jahre gueltig (bewusst kein Let's
|
||||||
Encrypt — kein Domain-/Port-80-Zwang, kein Renewal je wieder noetig).
|
Encrypt — kein Domain-/Port-80-Zwang, kein Renewal je wieder noetig).
|
||||||
@@ -143,9 +161,10 @@ aussen — kein anderer Rechner kommt mehr direkt ran.
|
|||||||
```
|
```
|
||||||
Baut beim ersten Mal das Hermes-Image aus `hermes-agent-src` (dauert ein
|
Baut beim ersten Mal das Hermes-Image aus `hermes-agent-src` (dauert ein
|
||||||
paar Minuten), startet dann `hermes-proxy`, `hermes-gateway`,
|
paar Minuten), startet dann `hermes-proxy`, `hermes-gateway`,
|
||||||
`hermes-agent` (Gateway/Messaging-Prozess), `hermes-agent-dashboard` und
|
`hermes-agent` (EIN Container, s6 supervisiert darin Gateway UND
|
||||||
`caddy`. Falls `CADDY_BASIC_AUTH_HASH` noch leer ist: `caddy` bricht beim
|
Dashboard zusammen, siehe Architektur oben) und `caddy`. Falls
|
||||||
Start ab, die anderen laufen trotzdem — Wert nachtragen (Schritt 4b), dann
|
`CADDY_BASIC_AUTH_HASH` noch leer ist: `caddy` bricht beim Start ab, die
|
||||||
|
anderen laufen trotzdem — Wert nachtragen (Schritt 4b), dann
|
||||||
`docker compose up -d caddy`.
|
`docker compose up -d caddy`.
|
||||||
|
|
||||||
6. **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):
|
||||||
@@ -197,17 +216,19 @@ Zwei GRUNDVERSCHIEDENE Richtungen, nicht verwechseln:
|
|||||||
ran, solange Du nicht selbst was aendertst (z.B. fuer den mobilen API-Server
|
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).
|
oben, oder falls Hermes doch mal auf eine zweite Maschine zieht).
|
||||||
|
|
||||||
`hermes-agent-dashboard` bindet fest auf `127.0.0.1` — von aussen nicht mehr
|
Das Dashboard (s6-supervisierter Geschwister-Prozess im `hermes-agent`-
|
||||||
direkt erreichbar. Davor steht `caddy` (Service in `docker-compose.yml`,
|
Container, `HERMES_DASHBOARD_HOST=127.0.0.1`) bindet fest auf `127.0.0.1` —
|
||||||
Config in `Caddyfile`): terminiert TLS auf Port 443 mit einem selbstsignierten
|
von aussen nicht mehr direkt erreichbar. Davor steht `caddy` (Service in
|
||||||
100-Jahre-Zertifikat (Setup-Schritt 4a) und erzwingt eine Basic-Auth-Schicht
|
`docker-compose.yml`, Config in `Caddyfile`): terminiert TLS auf Port 443 mit
|
||||||
(Setup-Schritt 4b, bcrypt-Hash in `CADDY_BASIC_AUTH_HASH`). Caddy ist die
|
einem selbstsignierten 100-Jahre-Zertifikat (Setup-Schritt 4a) und erzwingt
|
||||||
EINZIGE Auth-/TLS-Schicht — Hermes' eigenes Dashboard-Auth-Gate
|
eine Basic-Auth-Schicht (Setup-Schritt 4b, bcrypt-Hash in
|
||||||
(`dashboard.basic_auth`/`HERMES_DASHBOARD_PASSWORD_HASH`) wurde bewusst
|
`CADDY_BASIC_AUTH_HASH`). Caddy ist die EINZIGE Auth-/TLS-Schicht — Hermes'
|
||||||
komplett rausgenommen (aufgeraeumt 20.07.2026): es engagiert sich laut eigener
|
eigenes Dashboard-Auth-Gate (`dashboard.basic_auth`/
|
||||||
Fehlermeldung ohnehin nur bei einem 0.0.0.0-Bind, der Dashboard-Container
|
`HERMES_DASHBOARD_PASSWORD_HASH`) wurde bewusst komplett rausgenommen
|
||||||
bindet aber fest auf 127.0.0.1 — ein zweiter, nie greifender Auth-Layer haette
|
(aufgeraeumt 20.07.2026): es engagiert sich laut eigener Fehlermeldung
|
||||||
nur Setup-Schritte und Verwirrung gekostet, ohne echten Sicherheitsgewinn.
|
ohnehin nur bei einem 0.0.0.0-Bind, das Dashboard 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
|
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
|
Basic-Auth im Klartext raus. Ist jetzt behoben: einziger von aussen offene
|
||||||
@@ -242,38 +263,39 @@ Caddy liest die Config beim Start neu ein).
|
|||||||
|
|
||||||
**"Restart Gateway"-Button im Dashboard zeigt
|
**"Restart Gateway"-Button im Dashboard zeigt
|
||||||
`✗ no such gateway 'default': register it with 'hermes profile create default'
|
`✗ no such gateway 'default': register it with 'hermes profile create default'
|
||||||
first, or pass an existing profile name via '-p <name>'`:** Kein Bug bei uns,
|
first, or pass an existing profile name via '-p <name>'`, und/oder das
|
||||||
sondern eine Architektur-Inkompatibilitaet zwischen unserem Deploy-Stil und
|
Dashboard zeigt "Gateway Status: Stopped" obwohl der Gateway laeuft:**
|
||||||
dem Dashboard-Button. Hintergrund (im Hermes-Sourcecode nachgesehen,
|
Root Cause war eine Architektur-Inkompatibilitaet: Gateway und Dashboard
|
||||||
`hermes_cli/service_manager.py` + `hermes_cli/container_boot.py`):
|
liefen anfangs in ZWEI GETRENNTEN Containern (`hermes-agent` mit
|
||||||
|
`command: ["gateway", "run"]` + ein separater `hermes-agent-dashboard` mit
|
||||||
|
`command: ["dashboard", ...]`, beide aus demselben Image). Zwei Symptome,
|
||||||
|
eine Ursache:
|
||||||
|
|
||||||
- Unser `hermes-agent`-Service startet mit `command: ["gateway", "run"]`
|
- Der Gateway-Status im Dashboard kommt aus einer **lokalen Prozess-
|
||||||
direkt als Container-Kommando. Das Image erkennt dieses Muster als
|
Inspektion** (PID-Check) im eigenen Container, NICHT aus einem Netzwerk-
|
||||||
"Legacy-Start" und supervised den Prozess ueber den **statischen**
|
Call — im getrennten Dashboard-Container sah dieser Check den
|
||||||
s6-Service `main-hermes` (fest im Image, siehe
|
Gateway-Prozess nie, daher immer "Stopped".
|
||||||
`/etc/s6-overlay/s6-rc.d/`).
|
- Der Restart-Button ruft `hermes gateway restart` auf, das s6-Services
|
||||||
- Der Dashboard-Restart-Button ruft dagegen immer `hermes gateway restart`
|
**im eigenen Container** aufloest. Im Dashboard-Container gab's dafuer
|
||||||
auf (ohne `-p` = Profil `default`). Dieser Befehl sucht einen **dynamisch
|
keinen registrierten Service — daher `no such gateway 'default'`. Der
|
||||||
registrierten** s6-Service `gateway-default` unter `/run/service/` — der
|
echte Gateway-Prozess lief davon unbeeindruckt weiter.
|
||||||
entsteht aber nur durch `hermes profile create <name>` (Per-Profile-
|
|
||||||
Gateway-System). Bei uns wurde das nie ausgefuehrt, `main-hermes` und
|
|
||||||
`gateway-default` sind zwei komplett getrennte Dinge im selben Image.
|
|
||||||
- Ergebnis: der Button findet "sein" `gateway-default` nicht und wirft genau
|
|
||||||
diesen Fehler — der eigentliche Gateway-Prozess (`main-hermes`) laeuft
|
|
||||||
davon voellig unbeeindruckt normal weiter.
|
|
||||||
|
|
||||||
**Fix / Workaround:** Den Dashboard-Restart-Button bei uns einfach nicht
|
**Fix (seit 20.07.2026, `docker-compose.yml`):** Gateway und Dashboard laufen
|
||||||
benutzen, sondern von aussen den Container neu starten:
|
jetzt als s6-supervisierte Geschwister-Prozesse in EINEM `hermes-agent`-
|
||||||
|
Container (`HERMES_DASHBOARD=1` + `HERMES_DASHBOARD_HOST=127.0.0.1` im
|
||||||
|
`environment:`-Block) — genau der vom Image selbst empfohlene Weg, siehe
|
||||||
|
Startup-Log: *"dashboard supervised alongside if HERMES_DASHBOARD is set.
|
||||||
|
This is the recommended setup for the s6 container image."* Kein separater
|
||||||
|
`hermes-agent-dashboard`-Service mehr, kein `hermes profile create default`
|
||||||
|
noetig. Nach `git pull` + `docker-compose up -d --build` sollten Gateway-
|
||||||
|
Status UND Restart-Button im Dashboard den echten Zustand zeigen — bitte
|
||||||
|
nach dem Redeploy einmal ausprobieren.
|
||||||
|
|
||||||
|
Sollte der Restart-Button trotzdem noch spinnen: als Fallback von aussen
|
||||||
|
neu starten (bei s6-Auto-Restart selten noetig):
|
||||||
```bash
|
```bash
|
||||||
docker-compose restart hermes-agent
|
docker-compose restart hermes-agent
|
||||||
```
|
```
|
||||||
Das genuegt fast nie: `main-hermes` laeuft unter s6-Supervision mit
|
|
||||||
Auto-Restart bei Crash (siehe Startup-Log "gateway is now running under s6
|
|
||||||
supervision (auto-restart on crash...)"), ein manueller Restart ist im
|
|
||||||
Normalbetrieb also selten noetig. `hermes profile create default`
|
|
||||||
NICHT ausfuehren, um den Button zu "reparieren" — das wuerde einen zweiten,
|
|
||||||
parallelen Gateway-Mechanismus fuer denselben Port aufmachen und ist nicht
|
|
||||||
das, wofuer unser Single-Profile-Setup gebaut ist.
|
|
||||||
|
|
||||||
## Verzeichnisse (nicht committet, siehe .gitignore)
|
## Verzeichnisse (nicht committet, siehe .gitignore)
|
||||||
|
|
||||||
|
|||||||
+50
-55
@@ -113,12 +113,15 @@ services:
|
|||||||
- hermes-net
|
- hermes-net
|
||||||
|
|
||||||
# ─── Hermes Agent selbst (Nous Research) ───────────────────
|
# ─── Hermes Agent selbst (Nous Research) ───────────────────
|
||||||
# Offizielle Service-Definition 1:1 aus NousResearch/hermes-agent/docker-compose.yml
|
# Basiert auf der offiziellen Service-Definition aus
|
||||||
# (nur umbenannt gateway->hermes-agent, dashboard->hermes-agent-dashboard, damit
|
# NousResearch/hermes-agent/docker-compose.yml (umbenannt gateway->hermes-agent,
|
||||||
# es nicht mit unserem eigenen "hermes-gateway" oben verwechselt wird — das ist
|
# damit's nicht mit unserem eigenen "hermes-gateway" oben verwechselt wird —
|
||||||
# ein GANZ ANDERES Ding: Hermes' eigener Gateway-Begriff meint die Messaging-
|
# das ist ein GANZ ANDERES Ding: Hermes' eigener Gateway-Begriff meint die
|
||||||
# Bruecke (Telegram/Discord/...) + optionalen OpenAI-API-Server, NICHT unseren
|
# Messaging-Bruecke (Telegram/Discord/...) + optionalen OpenAI-API-Server,
|
||||||
# Auth-Proxy vor Claude).
|
# NICHT unseren Auth-Proxy vor Claude). Seit 20.07.2026 EIN Container fuer
|
||||||
|
# Gateway + Dashboard zusammen (HERMES_DASHBOARD=1, siehe Kommentar unten
|
||||||
|
# direkt vorm Service) statt zwei getrennter — kein eigener
|
||||||
|
# "hermes-agent-dashboard"-Service mehr.
|
||||||
#
|
#
|
||||||
# VORAUSSETZUNG: der echte Hermes-Agent-Sourcecode muss danebenliegen, weil
|
# VORAUSSETZUNG: der echte Hermes-Agent-Sourcecode muss danebenliegen, weil
|
||||||
# das Image nicht auf Docker Hub existiert, sondern per `build:` aus dem Repo
|
# das Image nicht auf Docker Hub existiert, sondern per `build:` aus dem Repo
|
||||||
@@ -128,6 +131,28 @@ services:
|
|||||||
# network_mode: host wie im Original — manche Messaging-Plattformen brauchen
|
# network_mode: host wie im Original — manche Messaging-Plattformen brauchen
|
||||||
# echte Host-Ports, und dadurch erreicht Hermes unser hermes-gateway einfach
|
# echte Host-Ports, und dadurch erreicht Hermes unser hermes-gateway einfach
|
||||||
# ueber "http://localhost:${HERMES_GATEWAY_PORT}/v1" statt ueber Docker-DNS.
|
# ueber "http://localhost:${HERMES_GATEWAY_PORT}/v1" statt ueber Docker-DNS.
|
||||||
|
# Kurskorrektur 20.07.2026: KEIN separater hermes-agent-dashboard-Container
|
||||||
|
# mehr. Grund (in Hermes' eigener Docs + unserem eigenen Startup-Log
|
||||||
|
# nachgelesen -- Log-Zeile "dashboard supervised alongside if HERMES_DASHBOARD
|
||||||
|
# is set. This is the recommended setup for the s6 container image"): das
|
||||||
|
# offizielle Docker-Image kann Gateway UND Dashboard als zwei GESCHWISTER-
|
||||||
|
# Prozesse in DERSELBEN s6-Supervision, DEMSELBEN Container laufen lassen,
|
||||||
|
# gesteuert per Env-Var HERMES_DASHBOARD=1. Das ist explizit "the recommended
|
||||||
|
# setup" -- und loest genau unser strukturelles Problem:
|
||||||
|
# - Dashboard erkennt den Gateway-Status ueber LOKALE Prozess-Inspektion
|
||||||
|
# (psutil/PID-Check) im eigenen Container, NICHT ueber eine Netzwerk-
|
||||||
|
# Health-URL. Mit zwei getrennten Containern (unser alter Aufbau) sieht
|
||||||
|
# das Dashboard den Gateway-Prozess nie -> "Gateway Status: Stopped"
|
||||||
|
# obwohl der Gateway echt lief.
|
||||||
|
# - Der "Restart Gateway"-Button im Dashboard ruft intern `hermes gateway
|
||||||
|
# restart` auf, das ueber s6-svc gegen die Service-Verzeichnisse IM
|
||||||
|
# EIGENEN Container aufgeloest wird -- im getrennten Dashboard-Container
|
||||||
|
# gab's dort keinen "default"-Gateway-Service, daher der Fehler "no such
|
||||||
|
# gateway 'default'". Im kombinierten Container sollte der Button den
|
||||||
|
# echten main-hermes-Service finden.
|
||||||
|
# Kein `command:` mehr noetig (Default-CMD des Images uebernimmt "gateway
|
||||||
|
# run" + s6 kuemmert sich per HERMES_DASHBOARD=1 automatisch ums Mitstarten
|
||||||
|
# des Dashboards).
|
||||||
hermes-agent:
|
hermes-agent:
|
||||||
build: ./hermes-agent-src
|
build: ./hermes-agent-src
|
||||||
image: hermes-agent
|
image: hermes-agent
|
||||||
@@ -154,6 +179,14 @@ services:
|
|||||||
# Config-Laden aus os.environ — siehe hermes_cli/config.py _expand_env_vars).
|
# Config-Laden aus os.environ — siehe hermes_cli/config.py _expand_env_vars).
|
||||||
- HERMES_GATEWAY_PORT=${HERMES_GATEWAY_PORT:-8447}
|
- HERMES_GATEWAY_PORT=${HERMES_GATEWAY_PORT:-8447}
|
||||||
- HERMES_GATEWAY_TOKEN=${HERMES_GATEWAY_TOKEN:?HERMES_GATEWAY_TOKEN muss in .env gesetzt sein - siehe .env.example}
|
- HERMES_GATEWAY_TOKEN=${HERMES_GATEWAY_TOKEN:?HERMES_GATEWAY_TOKEN muss in .env gesetzt sein - siehe .env.example}
|
||||||
|
# Dashboard als s6-supervisierten Geschwister-Prozess IM SELBEN Container
|
||||||
|
# aktivieren (siehe Kommentar oben). HERMES_DASHBOARD_HOST=127.0.0.1
|
||||||
|
# haelt den Bind lokal (Caddy ist die einzige Auth-/TLS-Schicht nach
|
||||||
|
# aussen, siehe caddy-Service unten und README) -- ohne das wuerde Hermes
|
||||||
|
# per Default auf 0.0.0.0 binden und sein eigenes Auth-Gate verlangen.
|
||||||
|
- HERMES_DASHBOARD=1
|
||||||
|
- HERMES_DASHBOARD_HOST=127.0.0.1
|
||||||
|
- HERMES_DASHBOARD_PORT=9119
|
||||||
# Optional: Hermes' EIGENER OpenAI-kompatibler API-Server, falls Du spaeter
|
# Optional: Hermes' EIGENER OpenAI-kompatibler API-Server, falls Du spaeter
|
||||||
# einen mobilen Client (gpt_mobile, Maid, OpenWebUI, ...) direkt GEGEN
|
# einen mobilen Client (gpt_mobile, Maid, OpenWebUI, ...) direkt GEGEN
|
||||||
# Hermes sprechen lassen willst (andere Richtung als unser Proxy oben!
|
# Hermes sprechen lassen willst (andere Richtung als unser Proxy oben!
|
||||||
@@ -164,72 +197,34 @@ services:
|
|||||||
# - API_SERVER_KEY=${API_SERVER_KEY}
|
# - API_SERVER_KEY=${API_SERVER_KEY}
|
||||||
command: ["gateway", "run"]
|
command: ["gateway", "run"]
|
||||||
|
|
||||||
hermes-agent-dashboard:
|
|
||||||
# Gleicher Build-Kontext wie oben bei "hermes-agent" (nicht nur "image:").
|
|
||||||
# Grund: "hermes-agent" ist kein Docker-Hub-Image, sondern wird lokal aus
|
|
||||||
# ./hermes-agent-src gebaut. Ohne eigenes build: hier versucht Compose
|
|
||||||
# beim "up" trotzdem erst einen Registry-Pull fuer dieses Image, der mit
|
|
||||||
# "pull access denied" fehlschlaegt UND (anders als beim hermes-agent-
|
|
||||||
# Service oben, der einen build:-Fallback hat) hart abbricht statt lokal
|
|
||||||
# zu bauen. Mit build: hier baut Compose denselben Kontext nochmal --
|
|
||||||
# dank Docker-Layer-Cache praktisch instant, landet aber wieder unter
|
|
||||||
# dem Tag "hermes-agent".
|
|
||||||
build: ./hermes-agent-src
|
|
||||||
image: hermes-agent
|
|
||||||
pull_policy: build
|
|
||||||
container_name: hermes-agent-dashboard
|
|
||||||
restart: unless-stopped
|
|
||||||
network_mode: host
|
|
||||||
depends_on:
|
|
||||||
- hermes-agent
|
|
||||||
volumes:
|
|
||||||
- ./hermes-data/agent-home:/opt/data
|
|
||||||
environment:
|
|
||||||
- HERMES_UID=${HERMES_UID:-10000}
|
|
||||||
- HERMES_GID=${HERMES_GID:-10000}
|
|
||||||
# HERMES_DASHBOARD_USER wird hier NICHT fuer Hermes' eigenes Auth-Gate
|
|
||||||
# gebraucht (das Gate engagiert sich laut eigener Fehlermeldung nur bei
|
|
||||||
# einem 0.0.0.0-Bind, der Service unten bindet aber fest auf 127.0.0.1
|
|
||||||
# per `command:`) — steht nur der Vollstaendigkeit halber mit drin,
|
|
||||||
# tatsaechlich genutzt wird die Variable von Caddy (siehe unten) fuer
|
|
||||||
# dessen Basic-Auth. Absicherung nach aussen laeuft komplett ueber Caddy.
|
|
||||||
- HERMES_DASHBOARD_USER=${HERMES_DASHBOARD_USER:-admin}
|
|
||||||
# Kurskorrektur 19.07.2026, spaeter Abend: Stefan wollte erst 0.0.0.0
|
|
||||||
# (SSH-Tunnel machte mit SSL Probleme), jetzt aber die richtige Loesung:
|
|
||||||
# Dashboard bleibt auf 127.0.0.1 (Hermes' eigenes Auth-Gate verlangt dann
|
|
||||||
# gar keinen registrierten Provider mehr, siehe Fehlermeldung "the auth
|
|
||||||
# gate engages on non-loopback binds") und der Caddy-Reverse-Proxy unten
|
|
||||||
# macht TLS + Basic-Auth auf Port 443 nach aussen. Das ist die einzige
|
|
||||||
# Auth-Schicht die im Normalbetrieb wirklich noetig ist.
|
|
||||||
command: ["dashboard", "--host", "127.0.0.1", "--no-open"]
|
|
||||||
|
|
||||||
# ─── Caddy (TLS-Reverse-Proxy + Basic-Auth vor dem Dashboard) ──────────
|
# ─── Caddy (TLS-Reverse-Proxy + Basic-Auth vor dem Dashboard) ──────────
|
||||||
# Stefans Entscheidung 19.07.2026: Dashboard bleibt intern auf 127.0.0.1,
|
# Stefans Entscheidung 19.07.2026: Dashboard bleibt intern auf 127.0.0.1,
|
||||||
# Caddy uebernimmt TLS-Termination auf Port 443 UND die Basic-Auth davor.
|
# Caddy uebernimmt TLS-Termination auf Port 443 UND die Basic-Auth davor.
|
||||||
# Caddy ist die EINZIGE Auth-/TLS-Schicht (aufgeraeumt 20.07.2026): Hermes'
|
# Caddy ist die EINZIGE Auth-/TLS-Schicht (aufgeraeumt 20.07.2026): Hermes'
|
||||||
# eigenes Dashboard-Auth-Gate (dashboard.basic_auth) wurde komplett entfernt,
|
# eigenes Dashboard-Auth-Gate (dashboard.basic_auth) wurde komplett entfernt,
|
||||||
# weil es sich laut eigener Fehlermeldung ohnehin nur bei einem 0.0.0.0-Bind
|
# weil es sich laut eigener Fehlermeldung ohnehin nur bei einem 0.0.0.0-Bind
|
||||||
# engagiert — der Dashboard-Container bindet aber fest auf 127.0.0.1, das
|
# engagiert — der Dashboard-Bind (HERMES_DASHBOARD_HOST im hermes-agent-
|
||||||
# Gate haette hier nie gegriffen. Ein zweiter, nie greifender Auth-Layer
|
# Service) bleibt aber fest auf 127.0.0.1, das Gate haette hier nie
|
||||||
# haette nur Setup-Schritte gekostet, kein Sicherheitsgewinn. Nutzt
|
# gegriffen. Ein zweiter, nie greifender Auth-Layer haette nur Setup-
|
||||||
# HERMES_DASHBOARD_USER (aus .env) als Login-Name + einen eigenen bcrypt-
|
# Schritte gekostet, kein Sicherheitsgewinn. Nutzt HERMES_DASHBOARD_USER
|
||||||
# Hash in CADDY_BASIC_AUTH_HASH (Caddy verlangt bcrypt, siehe .env.example
|
# (aus .env) als Login-Name + einen eigenen bcrypt-Hash in
|
||||||
# fuer die Erzeugung).
|
# CADDY_BASIC_AUTH_HASH (Caddy verlangt bcrypt, siehe .env.example fuer die
|
||||||
|
# Erzeugung).
|
||||||
#
|
#
|
||||||
# Zertifikat: bewusst KEIN Let's Encrypt (bräuchte oeffentliche Domain +
|
# Zertifikat: bewusst KEIN Let's Encrypt (bräuchte oeffentliche Domain +
|
||||||
# Port-80-Challenge). Stefans Wunsch: ein selbstsigniertes Zertifikat mit
|
# Port-80-Challenge). Stefans Wunsch: ein selbstsigniertes Zertifikat mit
|
||||||
# 100 Jahren Laufzeit, einmalig im Browser als Ausnahme akzeptieren, nie
|
# 100 Jahren Laufzeit, einmalig im Browser als Ausnahme akzeptieren, nie
|
||||||
# wieder um Erneuerung kuemmern. Erzeugung siehe README Setup-Schritt.
|
# wieder um Erneuerung kuemmern. Erzeugung siehe README Setup-Schritt.
|
||||||
# network_mode: host aus demselben Grund wie bei hermes-agent/-dashboard:
|
# network_mode: host aus demselben Grund wie bei hermes-agent: muss
|
||||||
# muss 127.0.0.1:9119 (Dashboard) erreichen UND selbst auf dem Host-Port
|
# 127.0.0.1:9119 (Dashboard, jetzt Teil des hermes-agent-Containers)
|
||||||
# 443 lauschen.
|
# erreichen UND selbst auf dem Host-Port 443 lauschen.
|
||||||
caddy:
|
caddy:
|
||||||
image: caddy:2-alpine
|
image: caddy:2-alpine
|
||||||
container_name: hermes-caddy
|
container_name: hermes-caddy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
network_mode: host
|
network_mode: host
|
||||||
depends_on:
|
depends_on:
|
||||||
- hermes-agent-dashboard
|
- hermes-agent
|
||||||
volumes:
|
volumes:
|
||||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
# kein :ro mehr -- der Entrypoint unten schreibt das Zertifikat selbst
|
# kein :ro mehr -- der Entrypoint unten schreibt das Zertifikat selbst
|
||||||
|
|||||||
Reference in New Issue
Block a user