Enabled via HERMES_DASHBOARD=1 (supervised in-container alongside the
gateway, per docs/user-guide/docker.md), bound to 0.0.0.0:9119 so Traefik
can reach it. Two independent auth layers, not one:
1. Traefik basicauth middleware in front of the whole route.
2. Hermes's own basic-auth gate (mandatory once the bind is non-loopback).
Hermes's docs explicitly call basic-auth-alone "not suitable for direct
public-internet exposure" and cite a real June 2026 incident where
internet scanners reached exposed dashboards and drove agents into
planting SSH-key backdoors — hence the extra Traefik-level gate rather
than relying on Hermes's own login page alone.
Also fixes: the htpasswd hash for Traefik's basicauth needs its literal
'$' characters escaped as '2824147' in .env, or docker compose's own variable
interpolation corrupts it (mistook '' for further
references). Also switched the hash from Python's default SHA-512
crypt ('$...') to apr1 ('$...', via openssl passwd -apr1) —
Traefik's basicauth middleware doesn't accept SHA-512-crypt.
Also re-adds Hermes's OPENAI_BASE_URL/OPENAI_API_KEY routing through the
local litellm gateway (instead of OPENROUTER_API_KEY direct) — this was
part of the now-abandoned PR #12 and never actually landed on main.
Correctness bugs (confirmed against diff/commit message):
.env.example:50 — hash-generation command still uses Python's crypt.METHOD_SHA512, but the commit message says this was switched to apr1 because Traefik's basicauth middleware rejects SHA-512-crypt. The doc was never updated to match the actual fix.
.env.example:49 — no instruction to escape literal $ as $$ before putting the hash in .env, even though the commit message calls this out as required to avoid docker compose's interpolation corrupting the hash.
README.md:33 — the DNS checklist (confirm these resolve to 217.160.66.143) wasn't updated to include hermes.apps.williamturner.eu, so a fresh deploy following the README won't provision DNS for the new dashboard.
Plausible (lower confidence, depends on external config not in this repo):
docker-compose.yml:84 — Hermes now routes through litellm, which only exposes aliased model names (auto, router-classifier, anthropic-claude). If Hermes's external config (/home/william/hermes-data) still references an OpenRouter-style model ID, completions will fail with "model not found."
Net effect: the two .env.example gaps mean the PR's stated security fix (Traefik-level basic auth) can silently fail to work as documented if someone follows the instructions as written.
## Summary
**Correctness bugs (confirmed against diff/commit message):**
1. **`.env.example:50`** — hash-generation command still uses Python's `crypt.METHOD_SHA512`, but the commit message says this was switched to `apr1` because Traefik's basicauth middleware rejects SHA-512-crypt. The doc was never updated to match the actual fix.
2. **`.env.example:49`** — no instruction to escape literal `$` as `$$` before putting the hash in `.env`, even though the commit message calls this out as required to avoid docker compose's interpolation corrupting the hash.
3. **`README.md:33`** — the DNS checklist (`confirm these resolve to 217.160.66.143`) wasn't updated to include `hermes.apps.williamturner.eu`, so a fresh deploy following the README won't provision DNS for the new dashboard.
**Plausible (lower confidence, depends on external config not in this repo):**
4. **`docker-compose.yml:84`** — Hermes now routes through litellm, which only exposes aliased model names (`auto`, `router-classifier`, `anthropic-claude`). If Hermes's external config (`/home/william/hermes-data`) still references an OpenRouter-style model ID, completions will fail with "model not found."
Net effect: the two `.env.example` gaps mean the PR's stated security fix (Traefik-level basic auth) can silently fail to work as documented if someone follows the instructions as written.
By request: one auth layer, not two. Note this isn't really removing a
layer I added on top of nothing — Hermes's own gate is mandatory and
can't be disabled while the dashboard is reachable through a separate
Traefik container (it fails closed at startup on any non-loopback bind
without a configured auth provider). The only thing actually optional
was the Traefik-level middleware, so that's what comes out; Traefik now
just does TLS termination + routing.
william
merged commit ec37245b37 into main2026-08-23 17:16:05 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Details in the commit message.
Enabled via HERMES_DASHBOARD=1 (supervised in-container alongside the gateway, per docs/user-guide/docker.md), bound to 0.0.0.0:9119 so Traefik can reach it. Two independent auth layers, not one: 1. Traefik basicauth middleware in front of the whole route. 2. Hermes's own basic-auth gate (mandatory once the bind is non-loopback). Hermes's docs explicitly call basic-auth-alone "not suitable for direct public-internet exposure" and cite a real June 2026 incident where internet scanners reached exposed dashboards and drove agents into planting SSH-key backdoors — hence the extra Traefik-level gate rather than relying on Hermes's own login page alone. Also fixes: the htpasswd hash for Traefik's basicauth needs its literal '$' characters escaped as '2824147' in .env, or docker compose's own variable interpolation corrupts it (mistook '' for further references). Also switched the hash from Python's default SHA-512 crypt ('$...') to apr1 ('$...', via openssl passwd -apr1) — Traefik's basicauth middleware doesn't accept SHA-512-crypt. Also re-adds Hermes's OPENAI_BASE_URL/OPENAI_API_KEY routing through the local litellm gateway (instead of OPENROUTER_API_KEY direct) — this was part of the now-abandoned PR #12 and never actually landed on main.Summary
Correctness bugs (confirmed against diff/commit message):
.env.example:50— hash-generation command still uses Python'scrypt.METHOD_SHA512, but the commit message says this was switched toapr1because Traefik's basicauth middleware rejects SHA-512-crypt. The doc was never updated to match the actual fix..env.example:49— no instruction to escape literal$as$$before putting the hash in.env, even though the commit message calls this out as required to avoid docker compose's interpolation corrupting the hash.README.md:33— the DNS checklist (confirm these resolve to 217.160.66.143) wasn't updated to includehermes.apps.williamturner.eu, so a fresh deploy following the README won't provision DNS for the new dashboard.Plausible (lower confidence, depends on external config not in this repo):
docker-compose.yml:84— Hermes now routes through litellm, which only exposes aliased model names (auto,router-classifier,anthropic-claude). If Hermes's external config (/home/william/hermes-data) still references an OpenRouter-style model ID, completions will fail with "model not found."Net effect: the two
.env.examplegaps mean the PR's stated security fix (Traefik-level basic auth) can silently fail to work as documented if someone follows the instructions as written.