docs: rename docs/ -> serverAppConfigs-docs/ per system-wide PROJECTNAME-docs convention
All in-repo path references (AGENTS.md, README, old scripts, report artifacts,
test code paths) rewritten in the same commit; focused-test map extended for
.gitignore, old/scripts/*, dankclaw/comfyui/*, and report/* per this repo's
own convention ('add one before committing'). Obsidian wikilinks are
title-based and unaffected.
This commit is contained in:
1 parent
6d4a96a423
commit
5829a0bfe8
140 files changed
+1820
-86
No files matched your search
@@ -0,0 +1,114 @@
|
||||
---
|
||||
type: configuration
|
||||
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.
|
||||
tags:
|
||||
- hermes
|
||||
- hermes-webui
|
||||
- hermex
|
||||
- dankclaw
|
||||
- ssh-tunnel
|
||||
timestamp: 2026-09-14
|
||||
---
|
||||
|
||||
# Hermes-WebUI (Hermex server)
|
||||
|
||||
`hermes-webui` is the [hermes-webui](https://github.com/nesquena/hermes-webui)
|
||||
server (MIT, third-party) that the **Hermex** iPhone app connects to. It runs
|
||||
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
|
||||
[[Hermes-Dashboard]].
|
||||
|
||||
**Host:** Dankclaw — **Port:** `127.0.0.1:8787` (loopback only) — **Ingress:** SSH tunnel
|
||||
|
||||
## Facts
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Image | `docker.io/nousresearch/hermes-agent:latest` (same as the gateway) |
|
||||
| Command | `python3 /webui/bootstrap.py --foreground` |
|
||||
| Source checkout | `/home/dank/hermes-webui` on Dankclaw (mounted at `/webui`) |
|
||||
| Port | `8787`, published to `127.0.0.1` only |
|
||||
| Auth | `HERMES_WEBUI_PASSWORD` (host `.env`; Hermex signs in with it) |
|
||||
| Data | shares `/home/dank/hermes-data` with the gateway and dashboard |
|
||||
| Health | `GET /health` (compose healthcheck + deployer) |
|
||||
|
||||
## Why a container, not a host process
|
||||
|
||||
The gateway's state files are owned by the container-mapped uid (`109999`,
|
||||
from rootless Podman's `1 → 100000/65536` subuid range). A fresh rootless
|
||||
namespace on Dankclaw maps identically (verified with `podman unshare
|
||||
cat /proc/self/uid_map`), so a second container using the same image reads
|
||||
and writes the shared volume with exactly the ownership the gateway already
|
||||
uses. A host-side process running as `dank` (uid 1000) could not read the
|
||||
gateway's `0600` state files.
|
||||
|
||||
## How it works
|
||||
|
||||
- `bootstrap.py` creates `/webui/.venv` on first boot, pip-installs the WebUI
|
||||
and agent requirements, then **execs** `server.py` as one foreground process
|
||||
(`--foreground`). systemd-free: Podman supervises it via
|
||||
`restart: unless-stopped`.
|
||||
- `HERMES_WEBUI_SKIP_ONBOARDING=1` keeps the first-run wizard off; a profile
|
||||
already exists in `/data` from the gateway.
|
||||
- The healthcheck `start_period` is 600 s because the very first boot spends
|
||||
minutes pip-installing into a fresh venv.
|
||||
|
||||
## Remote access (Hermex on iOS, from anywhere)
|
||||
|
||||
Only port `22` is forwarded to Dankclaw at the router, so the webui is
|
||||
reached through an SSH local forward — no extra router ports, no third-party
|
||||
relay (no Tailscale, no Cloudflare):
|
||||
|
||||
1. On the iPhone, open **Termius** (or any SSH client with local port
|
||||
forwarding) and connect to `<dankclaw-public>:22` with the usual key.
|
||||
2. On that connection, add a **local forward**: `127.0.0.1:8787` →
|
||||
`127.0.0.1:8787`. The forward runs inside the encrypted SSH session;
|
||||
nothing else on the phone routes through it.
|
||||
3. In Hermex, set the server URL to `http://localhost:8787` and sign in with
|
||||
the webui password.
|
||||
|
||||
The tunnel lives as long as the SSH session on the phone — iOS does not allow
|
||||
a true background daemon, so connect before you use Hermex.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Hermex app] -->|http://localhost:8787| B[SSH local forward on iPhone]
|
||||
B ==>|encrypted SSH to public IP:22| C[Dankclaw sshd]
|
||||
C --> D["hermes-webui 127.0.0.1:8787"]
|
||||
D --> E["/home/dank/hermes-data (shared agent state)"]
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
```
|
||||
./scripts/deploy.sh dankclaw --service hermes-webui
|
||||
```
|
||||
|
||||
The planner maps changes to the `hermes-webui` compose block (and only that
|
||||
block) to this service, so gateway and inference restarts stay isolated.
|
||||
Before first deploy, set a strong `HERMES_WEBUI_PASSWORD` in the live
|
||||
`dankclaw/.env`.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- The `/webui` mount is **rw on purpose**: `bootstrap.py` creates `.venv` in
|
||||
the repo root. Do not flip it to `:ro`.
|
||||
- Never publish `8787` beyond loopback without keeping the password set —
|
||||
the webui can run agent commands.
|
||||
- The webui and the gateway share one data volume. 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
|
||||
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.
|
||||
|
||||
# Citations
|
||||
|
||||
- hermes-webui README (env vars, `--foreground`, `/health`): https://github.com/nesquena/hermes-webui
|
||||
- Hermex setup model (server URL + password; Cloudflare/Tailscale are optional, not required): https://hermexapp.com/
|
||||
|
||||
## See Also
|
||||
|
||||
- [[Hermes]] — the agent and its Signal gateway
|
||||
- [[Hermes-Dashboard]] — the LAN browser management UI
|
||||
- [[Dankclaw Stack]]
|
||||
Reference in new issue
Block a user