hermes: single-container deploy (gateway + dashboard), as deployed on bob
All checks were successful
images / hermes (push) Successful in 37s

The image's command selects mode; no command = interactive CLI which
crash-loops under systemd. Switched to the supported headless setup: one
container running `gateway run` with the dashboard supervised alongside
via HERMES_DASHBOARD=1 (same netns so the dashboard can reach the gateway,
which two bridge-networked containers could not). Image fails closed on a
0.0.0.0 dashboard bind, so HERMES_DASHBOARD_INSECURE=1 opts into the chosen
trusted-LAN exposure on :5100. Verified live on bob: gateway stable, dash
HTTP 200 across the LAN, inference endpoint reachable, enrolled in
podman-auto-update.timer. Dropped the redundant separate dashboard quadlet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011D3YeWKpjg5bT488fVanCH
This commit is contained in:
grenade
2026-06-23 12:53:51 +03:00
parent 745a676702
commit 1142929874
2 changed files with 58 additions and 51 deletions

View File

@@ -1,24 +1,23 @@
# Reference quadlet for deploying Hermes on bob (bob.hanzalova.internal).
# Deploy to /etc/containers/systemd/hermes.container (rootful, matching the
# existing agent-zero.container and open-webui.container), then:
# sudo install -d -o 10000 -g 10000 /var/lib/hermes # /opt/data owner = HERMES_UID
# sudo install -o 10000 -g 10000 /path/to/config.yaml /var/lib/hermes/config.yaml
# sudo install -o 10000 -g 10000 /path/to/.env /var/lib/hermes/.env # if needed
# sudo systemctl daemon-reload && sudo systemctl start hermes.service
# Hermes Agent for bob — single-container "recommended s6" mode.
# The image runs `hermes gateway run` under s6 supervision, with the dashboard
# web UI supervised alongside in the SAME container when HERMES_DASHBOARD is set
# (per the image's own startup guidance). Running both in one container keeps
# them in one network namespace, so the dashboard can reach the gateway exactly
# as upstream's host-networked compose assumes — which two bridge-networked
# containers could not.
#
# Gated on git.lair.cafe/lair/hermes:latest being published by the `images`
# workflow first. After that it's a normal pull + AutoUpdate=registry quadlet —
# same lifecycle as the other two services, and now enrolled in the (enabled)
# podman-auto-update.timer.
# Command must be explicit: the image default (no command) is the interactive
# CLI, which exits without a TTY under systemd and crash-loops.
#
# Dashboard: the image binds the dashboard on 0.0.0.0:9119 by default
# (HERMES_DASHBOARD_HOST / HERMES_DASHBOARD_PORT), so bridge networking +
# PublishPort below exposes it on the LAN at :5100 with no override needed.
# ⚠ The dashboard stores provider API keys and has NO auth — keep it on a trusted
# LAN only; front it with an authenticating reverse proxy for anything wider.
# Setup: sudo install -d -o 10000 -g 10000 /var/lib/hermes ; drop config.yaml
# (provider: custom -> http://hanzalova.internal:31313/v1) ; daemon-reload ; start.
# Dashboard publishes to the LAN at :5100 (agent-zero=5080, open-webui=5090).
# ⚠ The dashboard stores provider API keys and has NO auth — trusted LAN only;
# front it with an authenticating reverse proxy for any wider exposure.
# AutoUpdate=registry keeps it current via the enabled podman-auto-update.timer.
[Unit]
Description=Hermes Agent
Description=Hermes Agent (gateway + dashboard)
After=network-online.target
Wants=network-online.target
@@ -26,15 +25,19 @@ Wants=network-online.target
Image=git.lair.cafe/lair/hermes:latest
ContainerName=hermes
AutoUpdate=registry
# Keeps the 50X0 LAN convention (agent-zero=5080, open-webui=5090, hermes=5100).
Exec=gateway run
PublishPort=5100:9119
Volume=/var/lib/hermes:/opt/data:Z
# Upstream drops to the non-root hermes user (uid/gid 10000); /var/lib/hermes
# must be owned 10000:10000 on the host (see install -d above).
Environment=HERMES_UID=10000
Environment=HERMES_GID=10000
# LLM backend (local sovereign inference) is configured in
# /var/lib/hermes/config.yaml via provider: "custom" -> see readme.md.
# Enable the supervised dashboard web UI inside this container (binds 0.0.0.0:9119).
Environment=HERMES_DASHBOARD=1
# The image fails closed: it refuses a non-loopback (0.0.0.0) dashboard bind
# unless OAuth is configured OR --insecure is opted in. We expose on the trusted
# LAN without auth (the chosen "LAN port like the others" tradeoff), so opt in.
# ⚠ Anyone on the LAN can reach the API-key-storing UI. To switch to real auth,
# drop this and set HERMES_DASHBOARD_OAUTH_CLIENT_ID (+ portal) instead.
Environment=HERMES_DASHBOARD_INSECURE=1
[Service]
Restart=always