Set up Hermex Run, expose, connect
Hermex is a native iPhone and iPad client for a Hermes agent you run yourself. It connects straight to the dashboard that comes with Hermes Agent (open source, MIT). Three moves and you’re steering it from your phone, no Hermex account needed.
This guide needs Hermex 2.0 or later.
On Hermex 1.x, or connecting a hermes-webui server? Use the legacy webui guide.
What you’ll need
- A machine you control running Hermes Agent 0.21.3 or later — Linux, macOS, WSL2 or native Windows.
- For the recommended path, Tailscale on both that machine and your iPhone or iPad.
- An iPhone or iPad with Hermex 2.0 or later (free on the App Store).
The shortcut: let your agent do it
Hermex’s onboarding gives you a setup prompt for your Hermes agent; here it is to copy on your computer. Send it to Hermes and it does steps 01 and 02: it turns on the dashboard’s sign-in, finds or proposes an HTTPS route, and replies with the address, username and password for step 03. It waits for your approval before adding a route, and tells you before it restarts the dashboard.
Show the setup prompt
Set up the Hermes dashboard on this machine for access from my iPhone.
Inventory before changing anything:
- Find the running `hermes dashboard` process, its `--host` and `--port` (default 9119), its launcher or service, and its `config.yaml`. Reuse and preserve working state instead of reinstalling it.
- Check who owns the dashboard port with `lsof -nP -iTCP:9119 -sTCP:LISTEN` (or the OS equivalent, with the actual port). Do not kill an unknown process; stop and report the owner or conflict.
- Look for an existing HTTPS route to the dashboard: a Cloudflare Tunnel, Tailscale Serve, or a reverse proxy. Preserve every existing route; do not reset, remove, or overwrite one.
Require sign-in:
- Never run the dashboard without its sign-in gate, and never bypass or disable it.
- Keep an existing `dashboard.basic_auth.username` and password. Otherwise set `dashboard.basic_auth.username` and a `password_hash` for a secure random password, hashed with the dashboard's own Python from the hermes-agent checkout: `python -c "from plugins.dashboard_auth.basic import hash_password; print(hash_password('<password>'))"`. Do not store a plaintext `password`.
- Keep an existing `dashboard.basic_auth.secret`. Otherwise set it to a random value of at least 32 bytes (for example `openssl rand -base64 32`) so sign-ins survive a restart.
- Edit only these keys and `dashboard.public_url` in `config.yaml`, and preserve every other line. Do not print `config.yaml` or the secret.
Choose the address my iPhone will use:
- Prefer HTTPS: an existing Cloudflare Tunnel or private network (such as Tailscale) route to the dashboard, with the dashboard still bound to `127.0.0.1`. If none exists, propose the exact steps to add one and wait for me to approve them.
- Treat same Wi-Fi over plain HTTP as an explicit manual fallback only. Explain that the password then crosses the network unencrypted, and require my confirmation before binding beyond loopback.
- Set `dashboard.public_url` to the exact address my iPhone will use, scheme and host (for example `https://hermes.example.com`). Without it the dashboard rejects the phone with `400 Invalid Host header`.
- Restart only the dashboard, through its existing launcher or service, and tell me before you do. Do not configure auto-start yourself; propose the exact OS-appropriate commands and wait for me to run them.
Verify in this order:
1. Confirm the dashboard locally with `curl --fail http://127.0.0.1:9119/api/status` (use the actual port).
2. Confirm the phone's address with `curl --fail <exact-phone-address>/api/status`, keeping its scheme and port (`https://` unless I confirmed the same Wi-Fi fallback), and check that it reports `"auth_required": true` with `basic` in `auth_providers`.
Reply with the exact address, username, password, and both check results, plus any remaining action required on my iPhone. Do not include `config.yaml` or the secret.Run the dashboard
New to Hermes? Install it with Nous Research’s installer (Linux, macOS and WSL2; native Windows has a PowerShell installer in the installation docs):
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bashAlready have it? Hermex needs Hermes 0.21.3 or later; hermes update brings it up to date.
Start it
hermes dashboard --no-openIt listens on 127.0.0.1:9119, local only until step 02. Check it on the machine:
curl --fail http://127.0.0.1:9119/api/statusServing the Hermes Webapp from your gateway instead (Hermes 0.23 or later)? Hermex 2.1 connects to it too. It listens on 127.0.0.1:9120: use that port in step 02, set webapp.public_url to your address, and sign in with the Webapp’s password in step 03.
On Hermex 1.x, or connecting a hermes-webui server? Use the legacy webui guide.
Make it reachable
Your iPhone or iPad needs a way to reach the dashboard. Pick one path; each ends with an address, which the dashboard needs to know before it turns on sign-in.
Option A — Tailscale Serve (private, recommended)
Tailscale puts the machine and your iPhone or iPad on the same private network, with nothing exposed to the public internet. Install it on both and sign in to the same tailnet. Leave the dashboard on 127.0.0.1 and publish it to your tailnet over HTTPS:
tailscale serve --bg 9119
tailscale serve status # shows your https://….ts.net URLYour address is the https://<machine>.<tailnet>.ts.net URL that tailscale serve status prints. The first time, Tailscale may ask you to enable HTTPS certificates for your tailnet. Serve answers on HTTPS port 443 at the root path, so if this machine already serves something there, check the status first so you don’t replace it. On Linux, if it reports Access denied: serve config denied, run it with sudo or allow your user once with sudo tailscale set --operator=$USER.
Option B — Cloudflare Tunnel, behind Cloudflare Access
Cloudflare Tunnel gives the dashboard a public HTTPS hostname without opening a port, and the dashboard stays on 127.0.0.1. Because its password sign-in isn’t meant for the open internet, put Cloudflare Access with a service token in front of it. For a hostname on a domain you’ve added to Cloudflare:
cloudflared tunnel login
cloudflared tunnel create hermes
cloudflared tunnel route dns hermes hermes.yourdomain.com
cloudflared tunnel run --url http://localhost:9119 hermesYour address is https://hermes.yourdomain.com. In Hermex, choose Cloudflare Tunnel when you connect: it adds CF-Access-Client-Id and CF-Access-Client-Secret fields for the service token.
Other ways
- Another private network, such as NetBird: install its app on the iPhone, keep it connected, start the dashboard with
--hostset to the machine’s address on that network, and use that address. - Same Wi-Fi (a fallback): start the dashboard with
--host 0.0.0.0and usehttp://<machine-ip>:9119. The password then crosses your network unencrypted, so only do this on a network you trust.
Turn on sign-in
Put your address in ~/.hermes/config.yamlas the dashboard’s public_url, scheme and host. Without it the dashboard turns your phone away with 400 Invalid Host header.
dashboard:
public_url: "https://<machine>.<tailnet>.ts.net" # your addressThen stop the dashboard and start it again in a terminal with hermes dashboard --no-open (plus the --host from above, if you chose a private network or the same Wi-Fi). Because the address reaches beyond this machine, Hermes requires sign-in and asks how: choose Username & password. It saves the username, a hashed password and a signing secret (so sign-ins survive a restart) to config.yaml. From then on, run the dashboard under your usual service manager (systemd, launchd, tmux) so it survives logging out.
The Hermes docs mean this password sign-in for a trusted network or a VPN, not the open internet, which is why Tailscale is the recommended path. To set it by hand instead, see dashboard.basic_auth in the web dashboard docs.
Check it from outside
From another device, the address should answer with "auth_required": true and basic in auth_providers:
curl --fail https://<your-address>/api/statusBehind Cloudflare Access, add the service token’s -H "CF-Access-Client-Id: …" and -H "CF-Access-Client-Secret: …" headers. On the same Wi-Fi, use your http://<machine-ip>:9119 address.
Connect Hermex
- Install Hermex 2.0 or later from the App Store and open it on your iPhone or iPad.
- Enter your Server URL from step 02 and tap Connect. Hermex recognizes the Hermes dashboard and asks for its username and password.
- Enter the username and password from step 02 and tap Connect. Hermex keeps the sign-in in the iOS Keychain on your device and sends it only to your server.
- Optional: turn on push notifications for the server in Hermex’s Settings. Hermex installs the open-source hermex-push plugin on your Hermes host, and notification text travels end-to-end encrypted through an open-source relay; see the privacy policy.
Moving from webui
Used Hermex with hermes-webui? After you update to 2.0, each webui server asks once whether to move to Hermes, then keeps a banner on its chat list. Move to Hermes brings the server’s chats and drafts to a Hermes server: it checks everything before it changes anything, and you can pause and resume it. Push carries over when the Hermes server is the same Hermes install; otherwise turn notifications on again for the Hermes server. Moves need Hermes 0.22.3 or later.
webui servers keep working in Hermex 2.0 and still get fixes; new features come to Hermes. The legacy webui guide stays here for them.
Troubleshooting
On Hermex 1.x, or connecting a hermes-webui server? Use the legacy webui guide.
The app can’t reach the server
Work outward. On the machine, check curl --fail http://127.0.0.1:9119/api/status. If that works, try your address’s /api/status from another device. Whichever hop fails is the one to fix.
400 Invalid Host header
dashboard.public_url doesn’t match the address you entered in Hermex. Set it to exactly that address, scheme and host, and restart the dashboard.
Hermex asks you to update Hermes
Hermex needs Hermes 0.21.3 or later, and session edits and Move to Hermes need 0.22.3. Run hermes update on the machine and restart the dashboard.
Sign-in keeps failing
The username and password must match dashboard.basic_auth. A HERMES_DASHBOARD_BASIC_AUTH_PASSWORD environment variable wins over the hash in config.yaml, so check for one. If sign-ins stop working after every restart, set dashboard.basic_auth.secret.
The Tailscale URL doesn’t respond
Confirm both devices are signed in to the same tailnet and show as connected in the Tailscale app. On the machine, tailscale serve status should list your ts.net URL proxying to 127.0.0.1:9119. If it doesn’t, run tailscale serve --bg 9119 again.
The Cloudflare address stopped working
Check cloudflared tunnel info hermes and make sure cloudflared is still running. If Cloudflare Access turns Hermex away, check the service token’s CF-Access-Client-Id and CF-Access-Client-Secretin the server’s connection settings.
Port 9119 is already taken
Find the owner with lsof -nP -iTCP:9119 -sTCP:LISTEN, or move the dashboard with hermes dashboard --port 9120 (update your Serve port or tunnel to match).
Still stuck? Ask in the Hermex Discord or message me on X — include what /api/status returns on the machine and which path (Tailscale or Cloudflare) you’re on. Found a bug in the app? Open an issue on GitHub. Issues with Hermes itself live upstream at NousResearch/hermes-agent.
