imkofty/Hermuse
Hermuse is a set of scripts and guides for running Hermes Agent (from Nous Research), the 9Router OpenAI-compatible model router and a Telegram gateway on a Linux VM. It adds a Cloudflare Pages and D1 long-poll tunnel to expose the 9Router dashboard, cron watchdogs including a gateway stall detector, and a default-deny Telegram allowlist. MIT licensed.
What it claims
Hermuse packages the exact stack running on one operator's ("Muse's") VM. Hermes Agent talks to Telegram through a polling gateway. Hermes sends model calls either straight to Nous (OAuth or API key) or to 9Router at 127.0.0.1:20128. The tunnel relays HTTP through a D1 queue because WebSocket, QUIC/UDP and cloudflared to the edge all failed on that network. The README says plain cloudflared is probably simpler on a normal network, and it ships scripts/setup-tunnel-cloudflared.sh for that case.
How it works
flowchart LR TG[Telegram] -->|polling| GW[Hermes gateway] GW --> NOUS[Nous direct] GW --> R[9Router 127.0.0.1:20128] B[Browser] -->|HTTPS| P[Pages Functions] P <--> D1[(D1 queue)] TC[tunnel-client.mjs on VM] -->|~20s long-poll| P TC --> R
The /__tunnel/poll endpoint holds an idle connection for about 20 seconds. Polling every 400ms to 2.5s would exhaust the Workers free tier of 100k requests/day within hours. With long-poll, idle use is about 4,300 requests/day.
Tunnel auth fails closed. Pages rejects poll and respond calls unless the TUNNEL_KEY secret is set and matches the client's key. Request and response bodies travel as Base64. They are capped at 1,350,000 raw bytes (1,800,000 Base64 chars) because of D1's 2,000,000-byte row limit, and larger payloads get a 413. A stored response is replayed only when the idempotency key, caller credential and payload all match. Reusing a key with a different payload returns 409.
There are two watchdogs, both run from cron every 5 minutes:
watchdog.shchecks 9Router via curl to/dashboard, the tunnel client via pgrep, and the gateway process. It restarts whatever died and logs only when it restarts something.gateway-watch.shcatches stalls where the process is still alive. It restarts immediately if the PID is gone or the heartbeat at$HERMES_HOME/state/gateway.heartbeatis older than 120s. If the heartbeat is fresh butgateway.logshows no Telegram adapter activity for 15 minutes, it restarts only after two consecutive runs confirm it. It kills only when exactly one candidate PID exists, and it never touches 9Router.
With a .health-key file, the watchdog and doctor probe the public tunnel end to end using an authenticated nonce answered by the local client.
How to use it
Requirements are Ubuntu 22.04 or 24.04, 2 vCPU and 4 GB RAM, a free Cloudflare account and a BotFather bot. install.sh needs passwordless sudo or root.
bash scripts/install.sh
hermes setup --portal
hermes gateway setup
CLOUDFLARE_API_TOKEN='<token>' bash scripts/setup-tunnel.sh <pages-project-name> <d1-name>The services must start in order: bash restart-9router.sh, then export TUNNEL_BASE_URL='https://<your-project>.pages.dev' and bash restart-tunnel.sh, then bash start-gateway.sh. The health check is bash scripts/doctor.sh, which should report 0 FAIL.
Cron does not inherit the shell environment, so the tunnel URL goes in a file:
echo -n 'https://<your-project>.pages.dev' > .tunnel-url && chmod 600 .tunnel-url
*/5 * * * * /path/to/Hermuse/watchdog.sh
*/5 * * * * /path/to/Hermuse/gateway-watch.shDRY_RUN=1 bash gateway-watch.sh tests the stall watchdog without acting. scripts/start-all.sh is idempotent and can run at boot through cron @reboot or the systemd user unit given in the README.
Limits
Existing tunnel databases need migrations 001 through 004 applied in order. scripts/check-tunnel-schema.sh <db-name> prints any missing fix. start-9router.sh refuses to boot with a public tunnel configured if .dashboard-pw is missing or empty. The authors say the reboot examples have not been tested on every distro. The archive of failed tunnel attempts, docs/arsip-tunnel-gagal.md, is written in Indonesian. The project is MIT licensed.
Organisations named here
- Nous Research
- Cloudflare
- Telegram
Technologies named here
- Hermes Agent
- 9Router
- Wrangler
- Tailscale
- HERMES
- Cloudflare
- Cloudflare Pages
- Node.js
- OAuth
- Linux
- systemd
- Muse
- BotFather
- cloudflared
- Cloudflare D1
- Cloudflare Pages Functions
- gateway-watch.sh
- Hermuse
- scripts/start-all.sh
- Telegram
- Telegram gateway
- tunnel-client.mjs
- watchdog.sh
Techniques named here
- Long polling
Concepts named here
- Default-deny allowlist
- Fail-closed authentication
- Heartbeat-based health checking
- Idempotency
Related in agents



