ARCH-HERMES-AGENTS01: Hermes agents on agents01¶
One host, many disposable agents. The containers are cattle — the state
is the bind mount. Everything an agent is (config, memory, skills, sessions,
secrets) lives on the host under /opt/hermes-<name>/data; everything the
container image or apt installs is reproducible from bootstrap.sh.
Host facts (agents01)¶
| Fact | Value |
|---|---|
| Public IP | 92.222.245.89 |
| Hostname | agents01 (with s) |
| SSH access | ssh -i <key> root@92.222.245.89 — root only (ubuntu@ is denied) |
| Resources | ~8 GB RAM, 40 GB disk, Docker 29.x |
| Docker network | hermes-net — shared by all services + nginx |
Shared services on the host (not agent-owned)¶
Any Hermes instance reaches them via host.docker.internal (or container
name on hermes-net):
| Service | Endpoint | Use |
|---|---|---|
| searxng | http://host.docker.internal:8888 |
SEARXNG_URL env (web search) |
| firecrawl / crw | http://host.docker.internal:3000 |
FIRECRAWL_API_URL env (scraping) |
| camofox-mcp | http://host.docker.internal:9378/mcp |
CAMOFOX_MCP_URL env (browser automation) |
| lightpanda / crw-camofox | internal | browser backends for the above |
Hermes instances (validated 2026-09-01)¶
| Instance | Dashboard (host) | API (host) | Public URL |
|---|---|---|---|
| hermes-carlos | 9123 | 8646 | carlos.wetopi.net (HTTPS) |
| hermes-joan | 9124 | 8647 | joan.wetopi.net (HTTPS, LE cert) |
| hermes-josep | 9125 | 8648 | josep.wetopi.net (HTTPS, LE cert) |
Both joan/josep share ONE certificate (live/joan.wetopi.net/, SAN:
joan + josep, HTTP-01 webroot, expires 2026-11-30, auto-renew via the
certbot container). Explicit A records for both subdomains → 92.222.245.89
were created 2026-09-01 (the wildcard still points at .76).
Inside every container the ports are always 9119 (dashboard) and 8642 (API server); only the host-side ports differ.
Instance layout — where persistence actually lives¶
/opt/hermes-<name>/data → /opt/data (ALL agent state, rw bind)
/opt/hermes-<name>/project → /home/hermes (workspace, rw bind)
/opt/hermes-<name>/.env → API_SERVER_KEY (0600, per-instance secret)
What lives inside data/ (= the container's /opt/data):
config.yaml, profile.yaml, memories/, skills/, profiles/,
sessions/, state.db, secrets/, bootstrap.sh.
Consequences:
restart=always+ Docker restarting on boot → instances survive host reboots; bind mounts remount automatically.docker rm+ recreate is safe: all state is on the host. What is NOT preserved is the container layer (apt packages,/usr/local/binbinaries) —bootstrap.sh(persisted insidedata/) reinstalls those on start.- Losing
data/loses the agent. Back it up like any stateful volume.
Deploy procedure¶
Parametrized script at /opt/deploy-hermes-instance.sh on agents01
(validated template lives in the lead profile skill wetopi-hermes-hosts):
Steps for a NEW instance (the script automates most of this):
start— creates layout, generates.env, runs container (nousresearch/hermes-agent:latest,--restart always), joinshermes-net, waits for s6.- Copy a known-good
bootstrap.shinto the freshdata/(from/opt/hermes-carlos/data/bootstrap.sh) and run thebootstrapaction — fresh instances have none. - Copy the
dashboard:basic_authblock from a working instance'sconfig.yamlanddocker restart— without it the dashboard refuses to bind publicly (see pitfalls). - Configure model/providers (fresh instances ship a placeholder
OPENAI_API_KEYand no LLM access). - Add the nginx vhost (below) and, once DNS points at .89, issue the cert and enable the HTTPS block.
nginx routing pattern¶
Files: /opt/composes/nginx/conf.d/<name>.conf (compose in
/opt/composes/nginx/docker-compose.yml; certs volume shared with the
certbot container, webroot /var/www/certbot).
- Port 80 server: acme-challenge location +
proxy_pass http://hermes-<name>:9119with websocket upgrade headers (the dashboard needsUpgrade/Connectionand long read/send timeouts). - Port 443 server: same proxy,
ssl_certificate /etc/nginx/certs/live/<name>.wetopi.net/fullchain.pem— ship it COMMENTED until certbot has issued the cert, then uncomment and reload. - Wildcard
*.wetopi.netcurrently points at 92.222.245.76; each agent subdomain needs an explicit A record → 92.222.245.89 before HTTP-01 validation can succeed. - Apply with
docker exec nginx-proxy nginx -t && docker exec nginx-proxy nginx -s reload.
Auth requirement (dashboard)¶
Current hermes-agent images refuse to bind the dashboard to 0.0.0.0
without a registered auth provider. The working pattern (all three
instances): dashboard.basic_auth (username + password_hash) in each
instance's config.yaml. Hash via
python -c "from plugins.dashboard_auth.basic import hash_password; print(hash_password('...'))".
Credentials are per-agent and live only in each config.yaml — never in
docs.