{"slug": "securely-access-a-hermes-dashboard-on-a-vps-with-an-ssh-tunnel", "title": "Securely Access a Hermes Dashboard on a VPS with an SSH Tunnel", "summary": "Hermes Agent, the open-source autonomous AI agent from Nous Research, starts its web dashboard on 127.0.0.1:9119 by default, and the official documentation identifies a loopback bind reached through an SSH tunnel as an appropriate way to keep the dashboard private. The tutorial details running `hermes dashboard --host 127.0.0.1 --port 9119 --no-open` on the VPS and forwarding the port locally with `ssh -N -T -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -L 127.0.0.1:9119:127.0.0.1:9119 your-user@your-vps`, noting that Hermes now activates an authentication gate for non-loopback binds and fails closed when no authentication provider is configured. The setup keeps the administrative interface off the public internet, with readiness verifiable via the documented GET /api/status endpoint and `ss -ltnp | grep ':9119'` confirming the listener is 127.0.0.1:9119 rather than 0.0.0.0:9119.", "body_md": "*The dashboard stays on the VPS loopback interface while SSH securely forwards it to the local browser. Image created by the author using AI.*\n\nHermes Agent is an open-source autonomous AI agent from Nous Research that can run on a local computer, a VPS, or other infrastructure while using tools to carry out tasks. [1] Its web dashboard is a browser-based management interface for configuring the agent, managing API keys and integrations, and monitoring sessions. [2]\n\n*Disclosure: I developed this tutorial from my own Hermes VPS setup and verified the workflow against the official documentation. AI assisted with drafting and editing the article.*\n\nI run Hermes Agent on a virtual private server. Most of the time, I interact with the agent remotely, but occasionally I want the convenience of its web dashboard on my own computer.\n\nThat creates a small networking puzzle.\n\nThe dashboard runs on the VPS. My browser runs on my laptop. Opening http://127.0.0.1:9119 in the browser normally points back to my laptop—not to the VPS. I could bind the dashboard to the server's public interface, but then I would be turning an administrative interface into an internet-facing service.\n\nThe cleaner solution is SSH local port forwarding:\n\n```\nLocal browser127.0.0.1:9119       │       │ encrypted SSH connection       ▼VPS loopback interface127.0.0.1:9119       │       ▼Hermes dashboard\n```\n\nThe result feels local: I open a localhost URL in my browser. Underneath, SSH carries the connection to the dashboard listening on the VPS.\n\nThis article explains the setup, the meaning of the command, and the mistakes that commonly make it fail.\n\nHermes starts its web dashboard on 127.0.0.1:9119 by default. The CLI also provides --host, --port, and --no-open options. The official documentation specifically identifies a loopback bind reached through an SSH tunnel as an appropriate way to keep the dashboard private. [2]\n\nThe distinction between these two bind addresses is important:\n\nBinding to 127.0.0.1 means an arbitrary internet client cannot connect directly to port 9119 on the VPS. A user must first have SSH access to the server and then forward a local port through that authenticated connection.\n\nHermes now activates an authentication gate for non-loopback binds and fails closed when no authentication provider is configured. That is useful protection, but it does not make a public bind necessary for this use case. If the only person who needs the dashboard already has SSH access, a loopback bind and local tunnel keep the network surface smaller. [2]\n\nConnect to the VPS and start the dashboard with an explicit loopback address:\n\n```\nhermes dashboard \\  --host 127.0.0.1 \\  --port 9119 \\  --no-open\n```\n\nEach option has a specific purpose:\n\nKeep this process running. If it exits, the SSH connection may remain established, but there will be no dashboard service at the far end of the tunnel.\n\nIn my session, I verified the dashboard from inside the VPS with:\n\n```\ncurl -fsS --max-time 10 http://127.0.0.1:9119/api/status\n```\n\nHermes documents GET /api/status as its readiness endpoint. A successful response shows that the web server is reachable locally on the VPS. It does not, by itself, prove that the later browser connection or dashboard WebSockets will work, but it is the right first check. [2]\n\nYou can also confirm that something is listening on the expected address and port:\n\n```\nss -ltnp | grep ':9119'\n```\n\nThe important detail is the listening address. For this design, it should be 127.0.0.1:9119, not 0.0.0.0:9119.\n\nOpen a second terminal on your local computer — not another shell inside the VPS — and run:\n\n```\nssh -N -T \\  -o ExitOnForwardFailure=yes \\  -o ServerAliveInterval=60 \\  -L 127.0.0.1:9119:127.0.0.1:9119 \\  your-user@your-vps\n```\n\nReplace your-user@your-vps with the same SSH destination you normally use. It can be a hostname, an IP address, or an alias defined in ~/.ssh/config.\n\nIf your VPS uses a different SSH port or identity file, use the same options you use for a normal login:\n\n```\nssh -p 2222 -i ~/.ssh/id_ed25519 \\  -N -T \\  -o ExitOnForwardFailure=yes \\  -o ServerAliveInterval=60 \\  -L 127.0.0.1:9119:127.0.0.1:9119 \\  your-user@your-vps\n```\n\nThe terminal will appear to do nothing. That is expected. The -N option tells SSH not to execute a remote command, while -T disables pseudo-terminal allocation. This connection exists only to carry forwarded traffic. OpenSSH defines -L as a local listener whose connections travel through the secure channel before the SSH server connects to the specified destination. [3]\n\nKeep this SSH process running while you use the dashboard.\n\nOn your local computer, open:\n\n```\nhttp://127.0.0.1:9119\n```\n\nThe URL looks local because it is local. Your browser connects to the SSH client listening on your computer’s port 9119. SSH transports those bytes to the VPS, where the SSH server connects to 127.0.0.1:9119 from the VPS side.\n\nThat last sentence explains the apparent paradox. There are two different meanings of 127.0.0.1 in the forwarding command:\n\n```\n-L 127.0.0.1:9119:127.0.0.1:9119   └──── local side ────┘ └ remote destination ┘\n```\n\nThe first address belongs to your local computer. The second is interpreted from the VPS.\n\nThe four values are:\n\nValueMeaningFirst 127.0.0.1Listen only on the local computer's loopback interfaceFirst 9119Local port used by the browserSecond 127.0.0.1Destination as seen from the VPSSecond 9119Port where the Hermes dashboard is listening on the VPS\n\nI prefer writing the first 127.0.0.1 explicitly. OpenSSH normally restricts a local forward to local use, but an explicit bind makes the intent visible and prevents the tunnel from accidentally becoming a LAN-accessible listener through a configuration change. [3]\n\nWith this setup, port 9119 does not need to be opened in the VPS firewall or cloud security group. The only publicly reachable service required for the workflow is the SSH service you already use to administer the server.\n\nThe dashboard traffic is carried inside the encrypted SSH connection. The Hermes process continues to accept dashboard connections only through the VPS loopback interface.\n\nThis does not mean the dashboard has no security consequences. It can manage sensitive settings and credentials and can run agent commands. Anyone who can use your authenticated SSH session and local forwarded port may be able to reach it. Protect the local computer, use SSH keys carefully, and close the tunnel when you finish. Hermes also supports authenticated non-loopback deployments, including OAuth and self-hosted OpenID Connect, for situations where the dashboard genuinely needs to be reachable as a remote service. [2]\n\nIf this is a regular workflow, place the connection details in your local ~/.ssh/config:\n\n```\nHost hermes-vps    HostName your.vps.example    User your-user    IdentityFile ~/.ssh/id_ed25519    LocalForward 127.0.0.1:9119 127.0.0.1:9119    ExitOnForwardFailure yes    ServerAliveInterval 60    ServerAliveCountMax 3\n```\n\nThen start the tunnel with:\n\n```\nssh -N -T hermes-vps\n```\n\nExitOnForwardFailure makes SSH exit if it cannot establish the requested listener—for example, because local port 9119 is already occupied. The keepalive settings help the client detect a server that has become unresponsive. OpenSSH notes that ExitOnForwardFailure covers failure to establish the forwarding listener; it does not guarantee that the final destination service will remain reachable. [4]\n\nThat distinction matters. A tunnel can be established successfully even if the Hermes dashboard later stops.\n\nFirst, confirm that the tunnel command is still running locally. Then SSH into the VPS normally and test the dashboard there:\n\n```\ncurl -fsS http://127.0.0.1:9119/api/status\n```\n\nIf this fails on the VPS, the problem is not the tunnel. Start or restart the Hermes dashboard and check its output.\n\nThe local and remote ports do not have to match. Keep Hermes on remote port 9119, but choose another port for the browser side:\n\n```\nssh -N -T \\  -o ExitOnForwardFailure=yes \\  -L 127.0.0.1:9120:127.0.0.1:9119 \\  your-user@your-vps\n```\n\nThen open:\n\n```\nhttp://127.0.0.1:9120\n```\n\nA successful /api/status response verifies only the readiness endpoint. Hermes uses separate WebSocket endpoints for interactive dashboard features. Check the Hermes dashboard output and your browser's developer console for WebSocket errors, and make sure you are using a current Hermes release. The official documentation explicitly warns that the readiness probe verifies less than the live chat connection. [2]\n\nThe VPS SSH server may disallow TCP forwarding, or your account/key may have forwarding restrictions. This is controlled on the server side. Ask the administrator to permit only the forwarding that is appropriate for the account rather than weakening unrelated SSH controls.\n\nAdd the keepalive options shown earlier:\n\n```\nServerAliveInterval 60ServerAliveCountMax 3\n```\n\nThey help the SSH client recognize a dead connection instead of leaving a stale tunnel in place. They do not restart the tunnel automatically.\n\nStarting hermes dashboard in an interactive VPS shell is convenient for a quick session. When that shell closes, the dashboard process may also stop.\n\nFor regular use, run it under a process supervisor such as systemd or inside a persistent terminal session such as tmux. The official Hermes documentation recommends keeping a remote dashboard under a persistent process manager when it should survive logout or reboot. [2]\n\nWhichever mechanism you choose, preserve the same network boundary:\n\n```\nhermes dashboard --host 127.0.0.1 --port 9119 --no-open\n```\n\nPersistence and exposure are separate decisions. A service can start automatically without listening on a public interface.\n\nWhen an application on a VPS tells you to open a localhost URL, remember that localhost always means **this machine**.\n\nThis pattern is useful far beyond Hermes. It works for development servers, database administration tools, notebook environments, observability consoles, and other private web interfaces that should not be published merely for occasional remote access.\n\nThe key is to keep the service private, make the forwarding direction explicit, and verify each side independently:\n\nOne command creates the bridge:\n\n```\nssh -N -T \\  -o ExitOnForwardFailure=yes \\  -L 127.0.0.1:9119:127.0.0.1:9119 \\  your-user@your-vps\n```\n\nThe dashboard stays on the server. The browser stays on your computer. SSH safely connects the two.\n\n[1] Nous Research, “Hermes Agent Documentation,” *Hermes Agent*. Accessed September 15, 2026. [https://hermes-agent.nousresearch.com/docs/](https://hermes-agent.nousresearch.com/docs/)\n\n[2] Nous Research, “Hermes Web Dashboard,” *Hermes Agent Documentation*. Accessed September 15, 2026. [https://hermes-agent.nousresearch.com/docs/user-guide/features/web-dashboard](https://hermes-agent.nousresearch.com/docs/user-guide/features/web-dashboard)\n\n[3] OpenBSD Project, “ssh(1): OpenSSH remote login client,” *OpenBSD Manual Pages*. Accessed September 15, 2026. [https://man.openbsd.org/ssh](https://man.openbsd.org/ssh)\n\n[4] OpenBSD Project, “ssh_config(5): OpenSSH client configuration file,” *OpenBSD Manual Pages*. Accessed September 15, 2026. [https://man.openbsd.org/ssh_config](https://man.openbsd.org/ssh_config)\n\n[Securely Access a Hermes Dashboard on a VPS with an SSH Tunnel](https://pub.towardsai.net/securely-access-a-hermes-dashboard-on-a-vps-with-an-ssh-tunnel-f1a6df7115e4) was originally published in [Towards AI](https://pub.towardsai.net) on Medium, where people are continuing the conversation by highlighting and responding to this story.", "url": "https://wpnews.pro/news/securely-access-a-hermes-dashboard-on-a-vps-with-an-ssh-tunnel", "canonical_source": "https://pub.towardsai.net/securely-access-a-hermes-dashboard-on-a-vps-with-an-ssh-tunnel-f1a6df7115e4?source=rss----98111c9905da---4", "published_at": "2026-09-16 20:01:01+00:00", "updated_at": "2026-09-16 20:22:59.388413+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "ai-products"], "entities": ["Hermes Agent", "Nous Research", "Hermes dashboard", "SSH", "GET /api/status"], "alternates": {"html": "https://wpnews.pro/news/securely-access-a-hermes-dashboard-on-a-vps-with-an-ssh-tunnel", "markdown": "https://wpnews.pro/news/securely-access-a-hermes-dashboard-on-a-vps-with-an-ssh-tunnel.md", "text": "https://wpnews.pro/news/securely-access-a-hermes-dashboard-on-a-vps-with-an-ssh-tunnel.txt", "jsonld": "https://wpnews.pro/news/securely-access-a-hermes-dashboard-on-a-vps-with-an-ssh-tunnel.jsonld"}}