Skip to content

[Feature]: Dashboard chat websocket endpoints reject same-host reverse proxy deployments with client_host_not_loopback #18415

@seanmantey

Description

@seanmantey

Problem or Use Case

I’m running Hermes dashboard behind a Traefik reverse proxy and the dashboard UI works great, but Chat fails because the dashboard websocket endpoints are rejected with 4403 client_host_not_loopback.

Environment

  • Hermes Agent version: v0.12.0 (2026.4.30)
  • Dashboard launched via a systemd user service
  • Reverse proxy: Traefik
  • Hermes agent, hermes dashboard and Traefik proxy are on the same host server
  • Browser connects to:
    • https://hermes.local.anondomain.com
  • Traefik proxies to:
    • http://127.0.0.1:9119
  • Dashboard access, via proxy, limited to authenticated users by Authentik.

Symptoms

Browser console shows websocket failures for:

  • /api/ws
  • /api/events
  • /api/pty

Example frontend error:

  • events feed disconnected — tool calls may not appear

What I've tested

  • Dashboard dependencies are installed and working

  • Normal dashboard pages load correctly

  • Tried different dashboard arguments including:

    • --host 127.0.0.1 --port 9119 --no-open
    • --host 0.0.0.0 --port 9119 --no-open --insecure
  • Set Traefik passHostHeader: false

  • Verified upstream requests from the Traefik proxy use:

    • Host: 127.0.0.1:9119

TCPDUMP packet capture / proxy evidence

Traefik forwards websocket upgrade requests like:

http
GET /api/ws?... HTTP/1.1
Host: 127.0.0.1:9119
Connection: Upgrade
Upgrade: websocket
X-Forwarded-For: 192.168.xx.xx # anonymised laptop IP
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Real-Ip: 127.0.0.1

Hermes responds with 403 Forbidden.

Added temporary logging to Hermes web server

I temporarily added logging to hermes_cli/web_server.py and captured:

Dashboard websocket close: endpoint=/api/ws code=4403 reason=client_host_not_loopback ctx={
  'path': '/api/ws',
  'client_host': '192.168.10.70',
  'client_port': 0,
  'host': '127.0.0.1:9119',
  'origin': 'https://hermes.local.anondomain.com', # anonymised
  'x_forwarded_for': '192.168.xx.xx', # anonymised laptop IP
  'x_real_ip': '127.0.0.1',
  'x_forwarded_host': '',
  'x_forwarded_proto': 'https',
  'x_forwarded_port': '443',
  'upgrade': 'websocket',
  'connection': 'Upgrade',
  'has_token': True,
  'token_prefix': '3M2pQKH_',
  'channel': ''
}

Similar entries occur for:

  • /api/events
  • /api/pty

Root cause

The dashboard websocket handlers reject when:

client_host = ws.client.host if ws.client else ""
if client_host and client_host not in _LOOPBACK_HOSTS:
    await ws.close(code=4403)

In a reverse proxy deployment, ws.client.host becomes the original browser IP rather than loopback, so chat is unusable even when the reverse proxy is on the same host and the upstream target is 127.0.0.1.

Proposed Solution

Please make Hermes dashboard chat usable behind a trusted reverse proxy, for example by one of:

  1. making the loopback-only websocket restriction configurable
  2. disabling proxy-derived client-IP enforcement for dashboard websocket endpoints
  3. using a different trust model when the dashboard is intentionally run with --insecure
  4. allowing trusted same-host reverse proxy deployments explicitly

Alternatives Considered

I've tried many different configurations to 'trick' the Hermes web server to no avail.
I don't want to add a messaging gateway to all Hermes profiles (those with sandboxed BE's already have messaging) or to install a desktop and browser on the server to access dashboard chat. There may be different proxies that can handle it differently but I believe this is a sensible change that other users may need.

Feature Type

Configuration option

Scope

None

Contribution

  • I'd like to implement this myself and submit a PR

Debug Report (optional)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existsarea/configConfig system, migrations, profilescomp/cliCLI entry point, hermes_cli/, setup wizardtype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions