4.7 KiB
Host Gateway API Server Configuration — Hermes WebUI Hybrid
The Problem
WebUI shows "Check HERMES_WEBUI_GATEWAY_BASE_URL and Gateway API server health".
Gateway systemd service shows active (running) but port 8642 isn't listening.
Root Cause
api_server is a gateway platform (enum Platform.API_SERVER = "api_server"), not a standalone service. It activates only when configured — either via config.yaml or env vars. On a host-native (systemd) setup, env vars from the Docker .env file are NOT propagated.
Fix — Two Options
Option A: config.yaml (Recommended)
# At ROOT level of /home/estorozhenko/.hermes/config.yaml
platforms:
api_server:
enabled: true
host: 0.0.0.0
port: 8642
key: "7c8a2d9f4e1b3a5c6d7e8f9a0b1c2d3e4f5a6b7c"
⚠️ Field name note: The field must be key (not api_key). The adapter reads extra.get("key", os.getenv("API_SERVER_KEY", "")). A field named api_key in the YAML is silently ignored because the bridge only moves key into the extra dict.
Option B: systemd unit env vars
Environment="API_SERVER_ENABLED=true"
Environment="API_SERVER_HOST=0.0.0.0"
Environment="API_SERVER_KEY=7c8a2d9f4e1b3a5c6d7e8f9a0b1c2d3e4f5a6b7c"
Then daemon-reload + restart.
How the Code Works
From gateway/config.py:
_load_env_overrides(line ~2128): readsAPI_SERVER_ENABLED,API_SERVER_KEY,API_SERVER_HOST,API_SERVER_PORT,API_SERVER_CORS_ORIGINSfrom env- Platform connected checker (line ~846): requires
keyinextrawithmin_length=16 - YAML bridging (line ~1471): moves
port,key,host,cors_origins,model_namefrom the platform dict intoextraso PlatformConfig preserves them _has_usable_api_server_key(line ~822): checks key is a string ≥ 16 chars
Without a valid key (≥16 chars), the platform won't be marked connected and the adapter won't start — no listener on 8642, no error message.
Key Debugging Lesson: Multi-Source Divergence
The API server key lives in four independent sources that must all agree:
| Source | Where | How it's set |
|---|---|---|
config.yaml |
platforms.api_server.key |
Edited directly |
~/.hermes/.env |
API_SERVER_KEY=... |
hermes config set gateway.api_server_key ... or manual edit |
| systemd unit | Environment="API_SERVER_KEY=..." |
hermes gateway install --force or manual edit |
docker .env for webui |
API_SERVER_KEY=... |
Docker compose env-file |
Common failure modes:
- config.yaml says one thing,
.envsays another →.envwins (os.environis overwritten at startup), so even though systemd'sEnvironment=and config.yaml agree, the process env is different. This is the most frequent root cause of "401 with correct key". - systemd shows key A,
.envshows key B → process starts with systemd's env, but then load_gateway_config reads.envand callsos.environ["API_SERVER_KEY"] = B, overwriting A.
To fix: pick ONE canonical value and set it identically in all four sources. The simplest approach: pick a single key string (e.g. 40 hex chars), put it in config.yaml's key: field, and ensure ~/.hermes/.env, the systemd unit, and docker .env all match.
How to Verify All Sources
# 1. Config YAML
grep -A1 'key:' ~/.hermes/config.yaml | grep -v extra
# 2. User .env (read_file blocked — use terminal/xxd)
grep API_SERVER_KEY ~/.hermes/.env
# 3. Systemd service
grep API_SERVER_KEY /etc/systemd/system/hermes-gateway.service
# 4. Docker compose .env
grep API_SERVER_KEY /opt/hermes/docker/.env
# 5. Live process env (verify the actual value the gateway uses)
SYSTEMD_PID=$(systemctl show hermes-gateway.service -p MainPID | grep -oP '\d+')
cat /proc/$SYSTEMD_PID/environ | tr '\0' '\n' | grep API_SERVER_KEY
All five should show the identical value. If step 5 (live process) differs from 1-4, then something is overwriting the key at runtime — likely step 2.
Verification
# Confirm listener
ss -tlnp | grep 8642
# Health check
curl -s http://localhost:8642/health
# → {"status": "ok", "platform": "hermes-agent", "version": "0.19.0"}
# From inside webui container
docker exec hermes-webui curl -s http://host.docker.internal:8642/health
# Check gateway logs for platform startup
journalctl -u hermes-gateway.service --no-pager -n 10 | grep -i api
Env Vars Expected by WebUI
In docker-compose.yml the webui expects:
- HERMES_WEBUI_GATEWAY_API_KEY=${API_SERVER_KEY:-}
- HERMES_API_URL=http://host.docker.internal:8642
- HERMES_WEBUI_GATEWAY_BASE_URL=http://host.docker.internal:8642
The API_SERVER_KEY env var must be exported or set in the .env file that docker-compose reads.