# 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) ```yaml # 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 ```ini 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`: 1. **`_load_env_overrides`** (line ~2128): reads `API_SERVER_ENABLED`, `API_SERVER_KEY`, `API_SERVER_HOST`, `API_SERVER_PORT`, `API_SERVER_CORS_ORIGINS` from env 2. **Platform connected checker** (line ~846): requires `key` in `extra` with `min_length=16` 3. **YAML bridging** (line ~1471): moves `port`, `key`, `host`, `cors_origins`, `model_name` from the platform dict into `extra` so PlatformConfig preserves them 4. **`_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, `.env` says another** → `.env` wins (`os.environ` is overwritten at startup), so even though systemd's `Environment=` 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, `.env` shows key B** → process starts with systemd's env, but then load_gateway_config reads `.env` and calls `os.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 ```bash # 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 ```bash # 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: ```yaml - 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.