How-To Guide
How to Secure a Hermes Agent Server
Keep Hermes admin access private, choose the right dashboard authentication, restrict messaging users, configure approvals and verify recovery without exposing secrets.
Quick answer
Keep the dashboard on loopback with an SSH tunnel or private VPN path. For an internet-facing dashboard, use HTTPS plus Nous OAuth or a conformant OIDC provider; the built-in username/password provider is for trusted networks or VPNs, not direct public exposure. Run Hermes as a non-root account, restrict messaging users, review approvals and mounted files, protect credentials and backups, and test both allowed and denied access.
A Hermes server can execute commands, use connected accounts and read private conversations. Secure the route into that runtime before adding more tools. This guide separates network access, dashboard authentication, messaging authorization and command approval: passing one does not prove the others. There is no universal five-minute hardening guarantee.
Managed cloud · API costs included · Skill library · Cancel anytime
Before you start:
- ☑A server you administer, a known working SSH session and recovery-console access
- ☑The actual Hermes version, installation method and owning OS account
- ☑An inventory of dashboard, gateway, API, webhook and reverse-proxy listeners; do not assume their ports are interchangeable
Steps
- 1
Inventory the runtime before changing access
Run
hermes --version,hermes config path,hermes dashboard --statusandhermes gateway statuson the owning host. Record the installation, service user, active profile and intended network path without copying secrets. A local browser address does not identify a remote server. Use the VPS deployment guide to establish which machine owns the runtime before editing firewall rules. - 2
Keep SSH recovery available
Use a non-root service account and SSH keys. Before disabling password login or changing a firewall, prove key-based access in a second terminal and retain the original session plus provider recovery-console access. Allow the SSH port actually configured on this host, not a guessed port 22. Validate the SSH configuration before reloading it. Do not run a blanket firewall recipe that can lock you out.
- 3
Keep the dashboard private by default
Start
hermes dashboard --host 127.0.0.1 --port 9119 --no-openon the server. From your laptop, usessh -N -L 9119:127.0.0.1:9119 user@your-server, replacing the host and account, then openhttp://127.0.0.1:9119. Restrict SSH access itself. Loopback dashboards do not require a login by default, so never forward that origin through a public tunnel and assume the tunnel activates Hermes authentication. The dashboard setup guide covers launch and reachability. - 4
Choose authentication for the actual exposure
For a trusted LAN or VPN, the built-in username/password provider can be appropriate; it is a shared credential, not per-user accounts or MFA. For a public HTTPS hostname, use Nous OAuth or your own conformant OIDC provider. A non-loopback bind engages the auth gate and fails closed if no provider is configured. The deprecated
--insecureflag does not bypass it. Authentication protects access to a powerful administration surface; it is not a limited guest-chat role. - 5
Match the OAuth callback to the public hostname
For Nous OAuth, register on the owning host with
hermes dashboard register --redirect-uri https://dashboard.example.com/auth/callback, replacing the example domain. ConfigureHERMES_DASHBOARD_PUBLIC_URL=https://dashboard.example.comfor that same deployment and serve it through HTTPS. Load the settings into the intended service and restart it in a maintenance window. Keep the origin reachable only by the intended private/proxy path; do not open port 9119 to the world just to repair a redirect. Follow the official Dashboard authentication documentation for provider configuration. - 6
Verify the gate, not just a green status response
From a signed-out browser, check that management pages require login. Inspect
curl -fsS https://dashboard.example.com/api/statusforauth_required: trueand the expected auth provider. This endpoint is deliberately public and its HTTP 200 is not proof of authorization. Attempt a read-only management endpoint such as/api/configwithout credentials: it must not disclose configuration. Sign in normally, verify the owning profile, then test one harmless Chat response. Log out and repeat the denied-access check. Record only the status and result, not cookies, authorization headers or returned private configuration. - 7
Authorize messaging users separately
Dashboard login does not authorize Telegram or Discord senders. Use
hermes gateway setupand the supported per-platform allowlists; for Telegram,TELEGRAM_ALLOWED_USERSis a comma-separated list of numeric user IDs in the owning profile environment. Review existing pairing approvals as well as allowlists and remove unintended access through supported pairing commands. A whole-group authorization may permit every member, which differs from a sender allowlist. Follow the Telegram setup guide and Discord setup guide, then prove one permitted request and one denied or pairing-only request without running privileged actions. - 8
Configure approvals and understand their limits
In
config.yaml, setapprovals.mode: manualwhen you require a human decision on commands classified as dangerous, and retainapprovals.cron_mode: denyandapprovals.single_query_mode: denyfor unattended work that must not auto-approve them. These are nested YAML keys, not a complete replacement file. Reviewcommand_allowlist, YOLO settings and the tools available to the agent. Manual mode does not prompt for every command or every possible external write. Tirith scanning is a separate setting,security.tirith_enabled; it is not the approval policy. Consult the official security reference before changing defaults. - 9
Bound file, tool and network access
A profile separates agent configuration and state, but is not an operating-system sandbox. Use a dedicated account or isolated environment for a distinct trust boundary, mount only necessary files, and avoid exposing the host Docker socket or unrelated credentials. The terminal backend guide explains execution placement. File-tool write guards do not stop a terminal process running as the same OS user from accessing those files. Command approvals and prompt-injection scanning reduce mistakes; neither proves that an adversarial process is contained.
- 10
Protect secrets and recoverable state
Keep credentials out of source control, screenshots, public logs and support exports. On POSIX, restrict the owning profile .env with
chmod 600 ~/.hermes/.env, adjusting the path for a named profile; also check parent-directory ownership and backup access. If a token appears in a log or shared transcript, revoke or rotate that token and review provider activity. A redaction setting cannot un-leak it. Use the Hermes backup and restore guide and test recovery privately without starting a second live messaging poller. - 11
Update deliberately and repeat the acceptance checks
Run
hermes doctorfor diagnostics and advisories, back up, then update using the method appropriate to this installation. A source checkout, container image and declarative Nix deployment do not have identical update procedures. After restart, repeat private reachability, denied management access, intended-profile login and a harmless permitted workflow. Treat newly exposed ports, missing auth or unexpected users as a failed release rather than calling the server secure because the process started. - 12
Decide who owns ongoing security
Write down who owns host patches, dashboard identity configuration, provider credentials, backups, gateway access and incident response. Self-hosted Web UI is an administration surface, including supported TUI Chat, not managed operations. Compare FlyHermes pricing and hosting responsibility if your requirement is managed browser/mobile access and uptime. Confirm current plan scope; managed hosting does not erase your responsibility for connected-account permissions or approval of consequential actions.
Pro Tips
- 💡Keep a small acceptance record: host/profile, version, exposure path, auth provider, signed-out result, permitted-user result, denied-user result, recovery owner and timestamp. Do not include secrets.
- 💡Do not use a public reverse proxy as a substitute for Hermes authentication. Test both the proxy entry point and whether the origin can be reached around it.
- 💡Telegram polling uses outbound connections. Expose an inbound endpoint only for an intentionally configured webhook or other service; protect it with the documented verification mechanism.
- 💡These instructions are a hardening baseline, not a penetration test or a guarantee against compromise. Review the full official security documentation for your threat model.
Troubleshooting
❌ Public dashboard opens without a login
✅ Remove public routing or restrict it at the firewall while you investigate. A loopback-bound origin behind a public tunnel can remain auth-free. Configure Nous OAuth or OIDC and a non-loopback bind on a protected origin, then repeat signed-out management-access checks before restoring access.
❌ Portal sign-in succeeds but never returns to the dashboard
✅ Compare the configured public URL and registered callback exactly, including scheme, hostname, port and /auth/callback path. Start a fresh ordinary login from the dashboard and correlate its timestamp with backend auth logs. Do not paste a callback URL, authorization code, PKCE material or cookies into a public ticket. Reaching Portal alone does not prove the callback or dashboard session succeeded.
❌ The dashboard logs everyone out after a restart on a trusted network
✅ For built-in username/password auth, an unset signing secret creates a random per-process key. Configure a stable protected secret through the documented provider settings if sessions must survive restart; coordinate workers and plan credential rotation. Never reuse provider API keys as signing secrets.
❌ An unwanted Telegram sender still has access
✅ Review platform/global allow-all settings, pairing approvals, sender allowlists and whole-group authorization. A narrow sender list does not revoke an existing independent grant. Use the owning profile, restart the relevant gateway when required, and retest with a non-privileged request.
❌ A key appeared in logs
✅ Treat the key as exposed: revoke or rotate it, inspect account activity and remove access to exposed copies. Review log collection and support-export practices. Do not rely on an undocumented logging.redactSecrets option or assume existing copies are now safe.
FAQ
Is a password enough for a public Hermes dashboard?
The built-in username/password provider is intended for trusted networks or VPNs. For direct internet-facing use, the official documentation recommends Nous OAuth or a conformant OIDC provider, together with HTTPS and controlled origin access.
Does a Cloudflare Tunnel activate Hermes authentication?
No. Transport and authentication are separate. The Hermes auth gate depends on the dashboard bind; a public tunnel to a loopback dashboard can expose an auth-free admin surface.
Is /api/status supposed to work before login?
Yes. It is a public readiness endpoint. Check auth_required and auth_providers, then separately prove that unauthenticated management reads cannot retrieve private configuration.
Does Tirith replace command approval?
No. security.tirith_enabled controls scanning. approvals.mode controls dangerous-command approval policy. Neither is a complete sandbox or a guarantee that every side effect prompts.
Do separate profiles isolate untrusted users?
They separate configuration and state, but do not replace OS users, containers or separate machines as security boundaries. Review the permissions of the actual runtime and connected tools.
Should I delete my Hermes home to repair a login failure?
No. Diagnose the auth provider, callback, service environment and selected profile first. Deleting the home can remove credentials, sessions, memory, skills and scheduled work without fixing the redirect.
Does FlyHermes remove every security responsibility?
No. It changes who operates the hosted runtime. You still need to review connected accounts, data access, authorized users and consequential actions, and confirm current plan responsibilities.