# Securely Access a Hermes Dashboard on a VPS with an SSH Tunnel

> Source: <https://pub.towardsai.net/securely-access-a-hermes-dashboard-on-a-vps-with-an-ssh-tunnel-f1a6df7115e4?source=rss----98111c9905da---4>
> Published: 2026-09-16 20:01:01+00:00

*The dashboard stays on the VPS loopback interface while SSH securely forwards it to the local browser. Image created by the author using AI.*

Hermes 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]

*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.*

I 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.

That creates a small networking puzzle.

The 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.

The cleaner solution is SSH local port forwarding:

```
Local browser127.0.0.1:9119       │       │ encrypted SSH connection       ▼VPS loopback interface127.0.0.1:9119       │       ▼Hermes dashboard
```

The result feels local: I open a localhost URL in my browser. Underneath, SSH carries the connection to the dashboard listening on the VPS.

This article explains the setup, the meaning of the command, and the mistakes that commonly make it fail.

Hermes 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]

The distinction between these two bind addresses is important:

Binding 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.

Hermes 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]

Connect to the VPS and start the dashboard with an explicit loopback address:

```
hermes dashboard \  --host 127.0.0.1 \  --port 9119 \  --no-open
```

Each option has a specific purpose:

Keep 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.

In my session, I verified the dashboard from inside the VPS with:

```
curl -fsS --max-time 10 http://127.0.0.1:9119/api/status
```

Hermes 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]

You can also confirm that something is listening on the expected address and port:

```
ss -ltnp | grep ':9119'
```

The important detail is the listening address. For this design, it should be 127.0.0.1:9119, not 0.0.0.0:9119.

Open a second terminal on your local computer — not another shell inside the VPS — and run:

```
ssh -N -T \  -o ExitOnForwardFailure=yes \  -o ServerAliveInterval=60 \  -L 127.0.0.1:9119:127.0.0.1:9119 \  your-user@your-vps
```

Replace 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.

If your VPS uses a different SSH port or identity file, use the same options you use for a normal login:

```
ssh -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
```

The 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]

Keep this SSH process running while you use the dashboard.

On your local computer, open:

```
http://127.0.0.1:9119
```

The 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.

That last sentence explains the apparent paradox. There are two different meanings of 127.0.0.1 in the forwarding command:

```
-L 127.0.0.1:9119:127.0.0.1:9119   └──── local side ────┘ └ remote destination ┘
```

The first address belongs to your local computer. The second is interpreted from the VPS.

The four values are:

ValueMeaningFirst 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

I 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]

With 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.

The dashboard traffic is carried inside the encrypted SSH connection. The Hermes process continues to accept dashboard connections only through the VPS loopback interface.

This 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]

If this is a regular workflow, place the connection details in your local ~/.ssh/config:

```
Host 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
```

Then start the tunnel with:

```
ssh -N -T hermes-vps
```

ExitOnForwardFailure 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]

That distinction matters. A tunnel can be established successfully even if the Hermes dashboard later stops.

First, confirm that the tunnel command is still running locally. Then SSH into the VPS normally and test the dashboard there:

```
curl -fsS http://127.0.0.1:9119/api/status
```

If this fails on the VPS, the problem is not the tunnel. Start or restart the Hermes dashboard and check its output.

The local and remote ports do not have to match. Keep Hermes on remote port 9119, but choose another port for the browser side:

```
ssh -N -T \  -o ExitOnForwardFailure=yes \  -L 127.0.0.1:9120:127.0.0.1:9119 \  your-user@your-vps
```

Then open:

```
http://127.0.0.1:9120
```

A 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]

The 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.

Add the keepalive options shown earlier:

```
ServerAliveInterval 60ServerAliveCountMax 3
```

They help the SSH client recognize a dead connection instead of leaving a stale tunnel in place. They do not restart the tunnel automatically.

Starting hermes dashboard in an interactive VPS shell is convenient for a quick session. When that shell closes, the dashboard process may also stop.

For 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]

Whichever mechanism you choose, preserve the same network boundary:

```
hermes dashboard --host 127.0.0.1 --port 9119 --no-open
```

Persistence and exposure are separate decisions. A service can start automatically without listening on a public interface.

When an application on a VPS tells you to open a localhost URL, remember that localhost always means **this machine**.

This 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.

The key is to keep the service private, make the forwarding direction explicit, and verify each side independently:

One command creates the bridge:

```
ssh -N -T \  -o ExitOnForwardFailure=yes \  -L 127.0.0.1:9119:127.0.0.1:9119 \  your-user@your-vps
```

The dashboard stays on the server. The browser stays on your computer. SSH safely connects the two.

[1] Nous Research, “Hermes Agent Documentation,” *Hermes Agent*. Accessed September 15, 2026. [https://hermes-agent.nousresearch.com/docs/](https://hermes-agent.nousresearch.com/docs/)

[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)

[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)

[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)

[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.
