Skip to content

Commit 9b3b7c9

Browse files
committed
docs(app-router): document HTTPS-Secure-cookie requirement and Hermes dashboard build step
Two recurring gotchas hit during fleet rollout, now documented: 1. The session cookie is Secure, so password-protected apps only work over HTTPS. Serving over a plain-HTTP Tailscale listener makes login appear to succeed (303) but every subsequent request bounces back to login because the browser never returns the cookie. Added notes to the Auth Model and Troubleshooting sections, plus the HTTPS tailnet-serve command. 2. Hermes dashboards crash-loop under --skip-build when web_dist was never built on a fresh install. Added an 'Adding a Hermes dashboard' subsection covering the one-time 'npm run build', profile/HERMES_HOME pinning, and the X-Forwarded-Prefix Caddy block, plus a matching troubleshooting entry.
1 parent 745aea1 commit 9b3b7c9

1 file changed

Lines changed: 62 additions & 0 deletions

File tree

devops/app-router/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,47 @@ The app is immediately live at `https://<host>/<slug>/`.
175175
upstream (Caddy on `:8080`) at `:443`; Caddy handles all per-app path routing. Only edit
176176
`~/openclaw-apps/router/tailscale-serve.json` when changing ports or funnel state.
177177
178+
### Adding a Hermes dashboard
179+
180+
A common app is a Hermes agent's own dashboard. Two gotchas specific to Hermes:
181+
182+
1. **Build the web UI first, or drop `--skip-build`.** The dashboard is served from a
183+
pre-built `web_dist/` directory. On a fresh Hermes install that directory may not
184+
exist yet, and `hermes dashboard --skip-build` will crash-loop with
185+
`✗ --skip-build was passed but no web dist found`. Build it once:
186+
187+
```
188+
cd ~/.hermes/hermes-agent/web && npm install && npm run build
189+
```
190+
191+
This emits `~/.hermes/hermes-agent/hermes_cli/web_dist/`. After that, `--skip-build`
192+
works (and is preferred under PM2 so the process starts instantly without rebuilding).
193+
194+
2. **Pin the profile and `HERMES_HOME`.** A dashboard reads sessions from one SQLite DB.
195+
For a profile agent, pass `--profile <name>`; for the root agent (cron jobs, no
196+
profile), omit `--profile`. Always set `HERMES_HOME` explicitly in the PM2 `env` so
197+
PM2's rewritten `$HOME` doesn't point the dashboard at an empty DB:
198+
199+
```js
200+
{
201+
name: "hermes-<agent>",
202+
script: "/Users/<user>/.hermes/hermes-agent/venv/bin/hermes",
203+
args: "--profile <name> dashboard --port 9120 --no-open --skip-build",
204+
interpreter: "none",
205+
cwd: "/Users/<user>/.hermes/hermes-agent",
206+
env: {
207+
PATH: "/Users/<user>/.hermes/hermes-agent/venv/bin:/opt/homebrew/bin:/usr/bin:/bin",
208+
HERMES_HOME: "/Users/<user>/.hermes",
209+
},
210+
max_restarts: 10,
211+
min_uptime: "30s",
212+
}
213+
```
214+
215+
Add the matching `forward_auth` + `strip_prefix` Caddy block with
216+
`header_up X-Forwarded-Prefix /hermes-<agent>` so the dashboard's SPA asset URLs
217+
resolve under the path prefix.
218+
178219
## Removing an App
179220

180221
```
@@ -213,6 +254,16 @@ Slugs are validated against `^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$` — lowerca
213254
alphanumerics and hyphens, max 32 chars. Anything outside that gets a 400 from
214255
`/auth/verify` and `/auth/login`.
215256

257+
**The session cookie is `Secure`, so password-protected apps only work over HTTPS.**
258+
The cookie is set with the `Secure` attribute, which means browsers (and `curl`) will
259+
refuse to send it back over plain `http://`. If you front the router with a plain-HTTP
260+
Tailscale Serve listener (e.g. `tailscale serve --http=<port>`), login will appear to
261+
succeed (the POST returns a 303) but every subsequent request gets bounced back to the
262+
login page because the cookie never returns. Always expose the router over an **HTTPS**
263+
door — `tailscale serve --https=<port> http://127.0.0.1:8080` for tailnet-only, or the
264+
default `:443` HTTPS funnel. Open (no-password) apps work fine over HTTP because they
265+
have no cookie to lose.
266+
216267
## Fronting OpenClaw Webhooks (optional)
217268

218269
External callers like AgentMail Svix webhooks and iOS Shortcuts don't always support
@@ -285,6 +336,17 @@ the app emits HTML with absolute paths to `/static/...` that 404 once it lives u
285336
`/my-app/`. Either configure a base path in the app, or rewrite assets at the Caddy
286337
layer.
287338

339+
**Login succeeds (303) but every page bounces back to the login screen.** The session
340+
cookie is `Secure` and you're serving over plain HTTP, so the browser never sends the
341+
cookie back. Expose the router over HTTPS instead — `tailscale serve --https=<port>
342+
http://127.0.0.1:8080` (tailnet-only) or the default `:443` funnel. See the note in the
343+
Auth Model section.
344+
345+
**A Hermes dashboard app crash-loops in PM2.** Check `pm2 logs hermes-<agent>`. If you
346+
see `✗ --skip-build was passed but no web dist found`, the dashboard UI was never built
347+
on this machine. Build it once with `cd ~/.hermes/hermes-agent/web && npm install &&
348+
npm run build`, then `pm2 restart hermes-<agent>`. See "Adding a Hermes dashboard."
349+
288350
**Tailscale config gets wiped on gateway restart.** The OpenClaw gateway's Tailscale
289351
integration is enabled. Disable it in `~/.openclaw/openclaw.json`:
290352

0 commit comments

Comments
 (0)