docs(hermes): document namespace addressability and fix stale claims

New page Architecture/Container Network Namespaces.md: which local services are
addressable from which Podman network namespace on Dankclaw (rootless podman +
netavark). Verified live 2026-09-02: gateway/webui/CDP run in the host netns and
dial loopback; hermes-dashboard is the only Hermes container on a bridge network
(dankclaw_default, 10.89.1.0/24 gw 10.89.1.1) and can dial published ports only —
unpublished host-netns listeners (signal-cli :8080, webui :8787) are refused from
that namespace even though both bind 0.0.0.0.

Corrected while verifying the above:
- Hermes.md: data root is /home/dank/Containers/hermes/data (not the retired
  /home/dank/hermes-data); gateway dials the Signal daemon on loopback; the
  daemon itself is a host user unit (signal-cli-daemon.service) bound to
  0.0.0.0:8080, so the Signal HTTP API is LAN-reachable.
- Hermes-Dashboard.md: it is a Quadlet unit (Network=dankclaw_default), not a
  compose service; data root + /opt/data anonymous volume corrected.
- Hermes-WebUI.md: binds 0.0.0.0:8787 in the host netns (verified: unauthenticated
  GET /health from another LAN machine returned 200) — the SSH tunnel is an access
  path, not a containment boundary; HealthCmd and data-path corrections.
- Network Architecture.md: no hermes vhost exists in either the tracked or the live
  Caddyfile (hermes.franksdank.cloud resolves but routes nowhere); SearXNG exits the
  tunnel via the shared named network searxng.network, not service:gluetun.

Docs only — deploy is a no-op for this change.
This commit is contained in:
Frank committed 2026-09-02 16:10:57 -07:00
1 parent 834ad54112
commit 2e179b024d
6 files changed
+213 -30

No files matched your search

@@ -0,0 +1,128 @@
---
type: reference
title: Container Network Namespaces
description: Which local services are addressable from which Podman network namespace on
Dankclaw, and why bridge-network containers cannot dial host-netns loopback listeners.
tags:
- networking
- podman
- netavark
- rootless
- dankclaw
timestamp: 2026-09-02
---
# Container Network Namespaces
On a rootless-Podman host, "talk to a local service" is not one question — it is
one question **per network namespace**. A container in the host network
namespace sees every host listener on `127.0.0.1`; a container on a bridge
network does not, and cannot be made to by name or by loopback. This page is the
address map for Dankclaw (192.168.0.143) and the rule that explains it.
## The rule
A container only reaches services that are reachable **from inside its own
network namespace**:
- `Network=host` → the container *is* in the host netns. It dials other host
services on loopback (`127.0.0.1:PORT`) and binds any free port itself.
- `Network=<name>.network` / `Network=dankclaw_default` (bridge, netavark) → the
container has its own netns. Loopback inside it is **its own** loopback. The
only host address it can dial is the network's gateway IP, and on a rootless
host that path is served by `rootlessport`, which forwards **published port
maps only**. An unpublished host listener is refused immediately (RST), not
routed.
- Container DNS names (`gitea-server`, `authentik-postgres`, `valkey`) resolve
**only inside the network that owns them**, so a container on another network
can never reach a peer by name — see the naming quirk below.
## Live address map (Dankclaw, verified 2026-09-02)
| Container | `NetworkMode` | Reachable from it |
|---|---|---|
| `systemd-hermes` (gateway) | `host` | everything on the host netns, incl. signal-cli at `127.0.0.1:8080` and the webui on `:8787` |
| `hermes-webui` | `host` | same; binds `0.0.0.0:8787`, so it is LAN-reachable, not loopback-only |
| `chrome-devtools-protocol` | `host` | binds `127.0.0.1:9222` — deliberately loopback-only, unreachable from the LAN and from bridge nets |
| `hermes-dashboard` | `dankclaw_default` (bridge) | only published ports, via the gateway IP `10.89.1.1` |
`Network=` values are read from the live Quadlet sources in
`/home/dank/.config/containers/systemd/*.container`; runtime network names on the
host at the same date were `podman`, `dankclaw_default`, `systemd-gitea`,
`systemd-searxng`, `systemd-open-webui`.
Two consequences that are easy to miss:
1. **The Hermes gateway can dial the Signal daemon on loopback only because it
runs in the host netns.** The dashboard — same image, same `/data` — cannot;
it shares state through the bind mount instead, never over the network.
2. **Caddy sits on `dankclaw_default`**, so every upstream it proxies must be
reachable from that network by **IP + published port**. Cross-network traffic
by container DNS name is not available to it: `gitea-server` lives on
`systemd-gitea`, `valkey` on `systemd-searxng`, and neither resolves from
Caddy's namespace. That is why Gitea is fronted as `IP:3000` and SearXNG as
`:8081` rather than by service name.
## Naming quirk: `<name>.network` becomes `systemd-<name>`
A Quadlet `Network=gitea.network` yields a runtime network named
**`systemd-gitea`**, not `gitea`. Probe with `podman network ls`, never by the
filename, or health checks and `Network-Alias` plans target a network that does
not exist.
## Verification recipe (read-only)
```bash
# which containers are on which network? (`podman network inspect` in this
# podman version has no `.containers` field, so list from the container side)
podman ps -a --format '{{.Names}} {{.Networks}}' # empty Networks = host or shared netns
# what listens on the host netns, and who owns it?
sudo ss -ltnp 'sport = :8080'
# what can a bridge-net container actually dial? run the probe inside its netns
podman exec <name> cat /proc/net/route # default route → gateway IP
podman exec <name> sh -c 'timeout 2 bash -c "exec 3<>/dev/tcp/10.89.1.1/8080"; echo rc=$?'
```
Verified outcomes of that recipe on 2026-09-02: from inside `hermes-dashboard`,
`10.89.1.1:3000` (Gitea, published), `:8081` (SearXNG via Gluetun's netns,
published) and `:9119` (its own published port) connect; `:8080` and `:8787`
are **refused instantly** even though both listeners are bound to `0.0.0.0` in
the host netns. Probes to `host.containers.internal` (`169.254.1.2`) from that
network time out rather than refuse — the alias is an address on the *default*
`podman` network, and this container is not on it.
## Operational rules
- Health checks for a bridge-network service must target a **published** port (or
run via `podman exec` inside the unit), never `localhost:<port>` from the
host — and never the reverse either: the deployer's health probe runs on the
host, so it sees host-netns listeners that the container itself cannot dial.
- To give a bridge-net container access to a host-netns listener, the options
are (a) move it to `Network=host`, or (b) publish the needed port. Option (b)
makes that port reachable from every netns and from the LAN — an exposure
change that needs operator approval before deployment, not a silent fix.
- `chrome-devtools-protocol` is intentionally `Network=host` with a loopback-only
bind so the browser tool stays unreachable from the LAN; do not "tidy" it onto
a bridge network — its two consumers (gateway, webui) are host-netns and reach
it on loopback.
## Exposure note: signal-cli-daemon is a host process, not a container
`signal-cli-daemon.service` runs as a **user** unit for `dank`
(`systemctl --user cat signal-cli-daemon.service`) with
`org.asamk.signal.Main --account <redacted> daemon --http 0.0.0.0:8080`. The
bind is all-interfaces, so the daemon's HTTP API is reachable from anywhere on
the LAN; verified from a second LAN machine with an unauthenticated
`GET /v1/version` → `HTTP 404` and body `<h1>404 Not Found</h1>No context found
for request` (Micronaut's no-route response), i.e. the socket answers to
strangers. The Hermes gateway in the host netns dials it on loopback, which is
the only reason a non-loopback bind is not *required* by any consumer here —
see [[Hermes]] for the consumer side.
## See Also
- [[Hermes]] — the gateway + Signal daemon this page's address map is keyed on
- [[Hermes-Dashboard]] — the one Hermes container that is *not* in the host netns
- [[Hermes-WebUI]] — host-netns service with a `0.0.0.0` bind and password-only auth
- [[Network Architecture]] — the Caddy/Anubis/Authentik front door this map feeds
@@ -28,7 +28,6 @@ graph TB
AUTH -->|session valid, provider internal_host| POST[Caddy post-auth listener :8017] AUTH -->|session valid, provider internal_host| POST[Caddy post-auth listener :8017]
POST --> HOME[Homepage file_server] POST --> HOME[Homepage file_server]
POST --> SEARCH[SearXNG via Gluetun netns :8081] POST --> SEARCH[SearXNG via Gluetun netns :8081]
POST --> HERMES[Hermes :8090]
POST --> PROM[Prometheus :9090] POST --> PROM[Prometheus :9090]
DIRECT -->|3000 + ssh 2222| GITEA[Gitea] DIRECT -->|3000 + ssh 2222| GITEA[Gitea]
DIRECT -->|3005| OWEBUI[OpenWebUI] DIRECT -->|3005| OWEBUI[OpenWebUI]
@@ -56,7 +55,7 @@ graph TB
DIRECT --> ARR DIRECT --> ARR
``` ```
Guarded (through Anubis): homepage, search, hermes, prometheus, romm, files. Guarded (through Anubis): homepage, search, prometheus, romm, files.
Exempt by construction: `auth.` (the IdP login itself), plex (plain HTTP), Exempt by construction: `auth.` (the IdP login itself), plex (plain HTTP),
gitea (git smart-HTTP clients cannot solve JS challenges — `/info/refs` and gitea (git smart-HTTP clients cannot solve JS challenges — `/info/refs` and
`git-*-pack` pass unchallenged), grafana (own auth). `git-*-pack` pass unchallenged), grafana (own auth).
@@ -78,7 +77,14 @@ Caddy holds one Let's Encrypt certificate per vhost, issued and renewed through
## Gluetun Path (SearXNG only) ## Gluetun Path (SearXNG only)
SearXNG attaches to the Gluetun network namespace (`network_mode: service:gluetun`). Only SearXNG shares the tunnel. Everything else on Dankclaw uses the normal LAN route. This matches KB Pattern 2 in [[Gluetun]]. `gluetun.container`, `searxng.container` and `searxng-valkey.container` all set
`Network=searxng.network` in their Quadlet sources (runtime network
`systemd-searxng`); only those three share the tunnel. The old compose idiom
(`network_mode: service:gluetun`) is gone — a shared named network is what
carries SearXNG's outbound traffic through the VPN exit. Everything else on
Dankclaw uses the normal LAN route. This matches KB Pattern 2 in [[Gluetun]].
See [[Container Network Namespaces]] for which addresses are reachable from that
namespace (none of the unpublished host-netns listeners).
## Access Policy ## Access Policy
@@ -92,4 +98,5 @@ SearXNG attaches to the Gluetun network namespace (`network_mode: service:gluetu
- [[Caddy]] — vhost map, TLS, basic auth - [[Caddy]] — vhost map, TLS, basic auth
- [[Dankserver Stack]], [[Dankclaw Stack]] - [[Dankserver Stack]], [[Dankclaw Stack]]
- [[Gluetun]] - [[Gluetun]]
- Knowledge base: [[Gluetun]], [[SearXNG]] - Knowledge base: [[Gluetun]], [[SearXNG]]
- [[Container Network Namespaces]] — who can dial what on Dankclaw (host netns vs bridge nets)
@@ -12,17 +12,36 @@ The Hermes web dashboard is a browser UI for managing the agent. It shows config
| Command | `hermes dashboard --host 0.0.0.0 --port 9119 --no-open --skip-build` | | Command | `hermes dashboard --host 0.0.0.0 --port 9119 --no-open --skip-build` |
| Port | `9119` (published to the LAN) | | Port | `9119` (published to the LAN) |
| Auth | HTTP basic auth (username + scrypt password hash) | | Auth | HTTP basic auth (username + scrypt password hash) |
| Data | shares `/home/dank/hermes-data` with the gateway | | Data | bind mount `/home/dank/Containers/hermes/data` → `/data`, shared with the gateway; plus a fresh anonymous volume at `/opt/data` per recreation |
## Why a separate container ## Why a separate container
The gateway container runs `hermes gateway run` (the Signal platform). That entrypoint does not start the dashboard. The dashboard is a separate process. So it runs in its own compose service (`hermes-dashboard`). Both services mount the same data volume. Both restart at boot (`restart: unless-stopped`). The gateway container runs `hermes gateway run` (the Signal platform). That
entrypoint does not start the dashboard. The dashboard is a separate process, so
it runs in its own Quadlet unit
([`dankclaw/hermes/quadlet/hermes-dashboard.container`](../../dankclaw/hermes/quadlet/hermes-dashboard.container):
image `localhost/hermes-agent:latest`, `Pull=never`, `Exec=hermes dashboard
--host 0.0.0.0 --port 9119 --no-open --skip-build`, `Restart=always`,
`RestartSec=5`). All three Hermes containers mount the same `/data` bind mount.
Unlike its two siblings — `hermes.container` and `hermes-webui.container` both
run with `Network=host` — the dashboard is the only Hermes container on a bridge
network (`Network=dankclaw_default`, subnet `10.89.1.0/24`, gateway `10.89.1.1`).
That has a functional consequence: from inside its namespace it can dial only
published ports via the gateway IP, and `host.containers.internal`
(`169.254.1.2`) is an alias on the *default* `podman` network that this container
is not attached to, so probes to it time out. It therefore never talks to the
gateway, the webui, or the CDP daemon over the network — it shares their state
through the bind mount instead. See [[Container Network Namespaces]].
## Authentication ## Authentication
The dashboard refuses to bind to a non-loopback address without an auth provider. There is no unauthenticated public bind. This repo uses basic auth: The dashboard refuses to bind to a non-loopback address without an auth provider. There is no unauthenticated public bind. This repo uses basic auth:
- `dashboard.basic_auth.username` and `dashboard.basic_auth.password_hash` live in the live `/home/dank/hermes-data/config.yaml`; the tracked backup at `dankclaw/hermes/config.yaml.example` intentionally omits the password hash. - `dashboard.basic_auth.username` and `dashboard.basic_auth.password_hash` live in
the live `/data/config.yaml` (host path
`/home/dank/Containers/hermes/data/config.yaml`); the tracked backup at
`dankclaw/hermes/config.yaml.example` intentionally omits the password hash.
- The stored value is a one-way scrypt hash. The plaintext password is never written to a file or the repo. - The stored value is a one-way scrypt hash. The plaintext password is never written to a file or the repo.
- The hash is generated with `plugins.dashboard_auth.basic.hash_password`. - The hash is generated with `plugins.dashboard_auth.basic.hash_password`.
@@ -39,3 +58,4 @@ Open `http://192.168.0.143:9119` in a browser on the LAN. Log in with the config
## See Also ## See Also
- [[Hermes-WebUI]] — the phone-facing API server (Hermex) - [[Hermes-WebUI]] — the phone-facing API server (Hermex)
- [[Container Network Namespaces]] — why this container cannot dial the gateway, webui, or CDP daemon
+33 -17
View File
@@ -1,7 +1,7 @@
--- ---
type: configuration type: configuration
title: Hermes-WebUI (Hermex server) title: Hermes-WebUI (Hermex server)
description: The hermes-webui compose service on Dankclaw — the loopback-only API server that the Hermex iPhone app talks to over an SSH tunnel. description: The hermes-webui container on Dankclaw — the API server that the Hermex iPhone app talks to, reachable over an SSH tunnel and, because it binds all interfaces, from the whole LAN.
tags: tags:
- hermes - hermes
- hermes-webui - hermes-webui
@@ -19,7 +19,7 @@ the Hermes agent in-process from the shared `HERMES_HOME`, so it is the *same*
agent — same memory, skills, and sessions — as the [[Hermes]] gateway and the agent — same memory, skills, and sessions — as the [[Hermes]] gateway and the
[[Hermes-Dashboard]]. [[Hermes-Dashboard]].
**Host:** Dankclaw — **Port:** `127.0.0.1:8787` (loopback only) — **Ingress:** SSH tunnel **Host:** Dankclaw — **Port:** `0.0.0.0:8787` (all interfaces) — **Ingress:** SSH tunnel for the phone app; direct LAN access also works
## Facts ## Facts
@@ -27,11 +27,11 @@ agent — same memory, skills, and sessions — as the [[Hermes]] gateway and th
|------|-------| |------|-------|
| Image | `docker.io/nousresearch/hermes-agent:latest` (same as the gateway) | | Image | `docker.io/nousresearch/hermes-agent:latest` (same as the gateway) |
| Command | `python3 /webui/bootstrap.py --foreground` | | Command | `python3 /webui/bootstrap.py --foreground` |
| Source checkout | `/home/dank/hermes-webui` on Dankclaw (mounted at `/webui`) | | Source checkout | `/home/dank/Containers/hermes/webui` on Dankclaw, bind-mounted at `/webui` |
| Port | `8787`, published to `127.0.0.1` only | | Port | `8787`, bound to `0.0.0.0` in the **host** network namespace (`Network=host`) — LAN-reachable, not loopback-only |
| Auth | `HERMES_WEBUI_PASSWORD` (host `.env`; Hermex signs in with it) | | Auth | `HERMES_WEBUI_PASSWORD` (host `.env`; Hermex signs in with it) |
| Data | shares `/home/dank/hermes-data` with the gateway and dashboard | | Data | bind mount `/home/dank/Containers/hermes/data` → `/data`, shared with the gateway and dashboard; anonymous volume at `/opt/data` |
| Health | `GET /health` (compose healthcheck + deployer) | | Health | `HealthCmd=` in the Quadlet unit probes `http://127.0.0.1:8787/health` from inside the unit (works because the webui runs in the host netns); the deployer probes the same path from the host |
## Why a container, not a host process ## Why a container, not a host process
@@ -56,9 +56,15 @@ gateway's `0600` state files.
## Remote access (Hermex on iOS — persistent SSH tunnel) ## Remote access (Hermex on iOS — persistent SSH tunnel)
Only port `22` is forwarded to Dankclaw at the router, so the webui is Only port `22` is forwarded to Dankclaw at the router, so the phone reaches the
reached through an SSH **local forward** — no extra router ports, no webui through an SSH **local forward** — no extra router ports, no third-party
third-party relay (no Tailscale, no Cloudflare). Implemented 2026-08-31: relay (no Tailscale, no Cloudflare). Implemented 2026-08-31. The tunnel is an
*access path* for the phone, **not** a containment boundary: the server binds
`0.0.0.0:8787`, so any host that can route to `192.168.0.143` can reach the API
directly and needs only `HERMES_WEBUI_PASSWORD` to get in (verified 2026-09-02:
an unauthenticated `GET /health` from another LAN machine returned HTTP 200).
See [[Container Network Namespaces]] for why the webui is reachable this way and
the sibling dashboard on `9119` is not.
- Dedicated `tunnel` account on Dankclaw (`/usr/sbin/nologin` shell, password - Dedicated `tunnel` account on Dankclaw (`/usr/sbin/nologin` shell, password
locked). Authentication is key-only; the account can do nothing except locked). Authentication is key-only; the account can do nothing except
@@ -88,8 +94,8 @@ third-party relay (no Tailscale, no Cloudflare). Implemented 2026-08-31:
graph LR graph LR
A[Hermex app] -->|http://localhost:8787| B[SSH local forward on iPhone<br/>persistent via personal VPN] A[Hermex app] -->|http://localhost:8787| B[SSH local forward on iPhone<br/>persistent via personal VPN]
B ==>|encrypted SSH to port 22| C[Dankclaw sshd<br/>tunnel user, forced nologin] B ==>|encrypted SSH to port 22| C[Dankclaw sshd<br/>tunnel user, forced nologin]
C --> D["hermes-webui 127.0.0.1:8787"] C --> D["hermes-webui 0.0.0.0:8787 (host netns)"]
D --> E["/home/dank/hermes-data (shared agent state)"] D --> E["/home/dank/Containers/hermes/data (shared agent state)"]
``` ```
## Deployment ## Deployment
@@ -98,8 +104,11 @@ graph LR
./scripts/deploy.sh dankclaw --service hermes-webui ./scripts/deploy.sh dankclaw --service hermes-webui
``` ```
The planner maps changes to the `hermes-webui` compose block (and only that `deploy.sh` copies `dankclaw/hermes/quadlet/*.container` into the quadlet unit
block) to this service, so gateway and inference restarts stay isolated. directory and restarts `hermes.service`, `hermes-dashboard.service` and
`hermes-webui.service` in the **user** manager of `dank` (linger must be on for
them to come up at boot), so gateway/dashboard/webui restarts stay isolated from
inference deploys.
Before first deploy, set a strong `HERMES_WEBUI_PASSWORD` in the live Before first deploy, set a strong `HERMES_WEBUI_PASSWORD` in the live
`dankclaw/.env`. `dankclaw/.env`.
@@ -107,10 +116,16 @@ Before first deploy, set a strong `HERMES_WEBUI_PASSWORD` in the live
- The `/webui` mount is **rw on purpose**: `bootstrap.py` creates `.venv` in - The `/webui` mount is **rw on purpose**: `bootstrap.py` creates `.venv` in
the repo root. Do not flip it to `:ro`. the repo root. Do not flip it to `:ro`.
- Never publish `8787` beyond loopback without keeping the password set — - The webui binds `0.0.0.0:8787` today, so the SSH tunnel is an access path for
the webui can run agent commands. the phone, not a security boundary: any LAN host that can route to
- The webui and the gateway share one data volume. A config change made on one `192.168.0.143` reaches the API and needs only `HERMES_WEBUI_PASSWORD`. The
side takes effect when the other restarts (same caveat as the dashboard). webui can run agent commands, so treat that password as a credential with
command-execution blast radius. To make loopback-only binding true again, set
`HERMES_WEBUI_HOST=127.0.0.1` in the unit and require the tunnel for every
client — that is an exposure change to decide deliberately, not a silent fix.
- The webui and the gateway share one data root (`/data` is a bind mount of
`/home/dank/Containers/hermes/data`). A config change made on one side takes
effect when the other restarts (same caveat as the dashboard).
- `bootstrap.py` auto-installs a Hermes Agent if it cannot find one; in this - `bootstrap.py` auto-installs a Hermes Agent if it cannot find one; in this
image the agent is already present, so that path should never fire. If the image the agent is already present, so that path should never fire. If the
log shows an install attempt, the image changed — re-verify the entrypoint. log shows an install attempt, the image changed — re-verify the entrypoint.
@@ -125,3 +140,4 @@ Before first deploy, set a strong `HERMES_WEBUI_PASSWORD` in the live
- [[Hermes]] — the agent and its Signal gateway - [[Hermes]] — the agent and its Signal gateway
- [[Hermes-Dashboard]] — the LAN browser management UI - [[Hermes-Dashboard]] — the LAN browser management UI
- [[Dankclaw Stack]] - [[Dankclaw Stack]]
- [[Container Network Namespaces]] — why this host-netns service is LAN-reachable
+17 -6
View File
@@ -4,8 +4,11 @@ Hermes is the self-improving AI agent from Nous Research. It runs in a terminal,
**Host:** Dankclaw — **Hostname:** `hermes.dankclaw.local` — **Docs:** https://hermes-agent.nousresearch.com/docs **Host:** Dankclaw — **Hostname:** `hermes.dankclaw.local` — **Docs:** https://hermes-agent.nousresearch.com/docs
**Persistent state:** `/home/dank/hermes-data` on Dankclaw, mounted as `/data` in **Persistent state:** `/home/dank/Containers/hermes/data` on Dankclaw, bind-mounted
both containers. The tracked, sanitized configuration baseline is at `/data` in all three Hermes containers (gateway, webui, dashboard). Each
container additionally gets an anonymous volume at `/opt/data`, which is
re-created empty on every container recreation — anything that lives only there
is not durable. The tracked, sanitized configuration baseline is
[`dankclaw/hermes/config.yaml.example`](../../dankclaw/hermes/config.yaml.example). [`dankclaw/hermes/config.yaml.example`](../../dankclaw/hermes/config.yaml.example).
## Facts (from research, primary source) ## Facts (from research, primary source)
@@ -22,7 +25,12 @@ both containers. The tracked, sanitized configuration baseline is
## Configuration ## Configuration
- Point Hermes at the local model endpoint or an external provider through its provider config. - Point Hermes at the local model endpoint or an external provider through its provider config.
- The gateway process exposes one port for chat integration; the exact port is set in the Hermes config (`8090` convention in this repo). - The gateway runs `hermes gateway run --force -v` in the **host** network
namespace (`Network=host` in its Quadlet unit) and reaches the Signal daemon at
`http://127.0.0.1:8080`. That loopback hop works only because the gateway is in
the host netns — see [[Container Network Namespaces]]. The daemon itself is a
**host** user unit (`signal-cli-daemon.service`), not a container, and binds
`0.0.0.0:8080`, so the Signal HTTP API is reachable from the whole LAN.
- The data volume persists skills, memory, and session history. - The data volume persists skills, memory, and session history.
- Hermes has two named local providers: `dankclaw-large` reaches - Hermes has two named local providers: `dankclaw-large` reaches
`http://192.168.0.143:7770/v1` and exposes `frank-default-large`; `http://192.168.0.143:7770/v1` and exposes `frank-default-large`;
@@ -33,9 +41,11 @@ both containers. The tracked, sanitized configuration baseline is
## Volumes ## Volumes
| Container path | Host path (convention) | | Container path | Host path (live) | Backing |
|----------------|------------------------| |----------------|------------------|---------|
| `/data` | `/home/dank/hermes-data` | | `/data` | `/home/dank/Containers/hermes/data` | bind mount (durable; shared by all three containers) |
| `/webui` | `/home/dank/Containers/hermes/webui` | bind mount (webui only — the `bootstrap.py` venv lives here) |
| `/opt/data` | anonymous volume | image `VOLUME`; fresh empty volume per recreation |
## Gotchas ## Gotchas
@@ -64,3 +74,4 @@ restart) pays one first-call npm download; subsequent calls are cached.
- [[Dankclaw Stack]] - [[Dankclaw Stack]]
- [[OpenWebUI]] — the chat UI that pairs with Hermes - [[OpenWebUI]] — the chat UI that pairs with Hermes
- Knowledge base: [[SearXNG]] (Hermes as the search agent) - Knowledge base: [[SearXNG]] (Hermes as the search agent)
- [[Container Network Namespaces]] — why the gateway and webui can dial loopback services and the dashboard cannot
+1
View File
@@ -30,6 +30,7 @@ covers both workloads).
- [[Deployment Flow]] — service-scoped git deploy, target map, and health checks - [[Deployment Flow]] — service-scoped git deploy, target map, and health checks
- [[Testing Policy]] — the test seams and how to run them - [[Testing Policy]] — the test seams and how to run them
- [[E2E Suite]] — the Playwright suite that drives the live guard chain - [[E2E Suite]] — the Playwright suite that drives the live guard chain
- [[Container Network Namespaces]] — which local services are addressable from each Podman network namespace on Dankclaw
## Dankserver Storage ## Dankserver Storage