Hermes Guide
Hermes Agent with docker-compose
A docker-compose file is the fastest self-hosted way to run Hermes Agent — one YAML, one docker compose up -d, gateway online. This guide gives you a working compose file, explains each block, covers the credentials and TLS setup people usually get wrong, and points at OpenClaw Launch for when you'd rather not run it yourself.
Prerequisites
- A Linux host (Debian/Ubuntu works) with 2 GB of RAM minimum, 4 GB recommended
- Docker Engine 24+ and the compose v2 plugin
- A public hostname pointed at the host (for TLS). Not strictly required if you only want local use
- An OpenRouter / Anthropic / OpenAI API key
- A Telegram bot token if you're going to pair Telegram (most people do)
Directory Layout
Keep everything under one folder so you can move it or back it up in one tar:
/opt/hermes/ docker-compose.yml hermes.json # agent config credentials/ # channel sessions live here data/ # memory, skills state logs/The docker-compose.yml
A minimal working file:
services:
hermes:
image: ghcr.io/nousresearch/hermes-agent:latest
container_name: hermes
restart: unless-stopped
ports:
- "127.0.0.1:8642:8642" # gateway + web UI (bind localhost; put Caddy in front)
environment:
OPENROUTER_API_KEY: "${OPENROUTER_API_KEY}"
TELEGRAM_BOT_TOKEN: "${TELEGRAM_BOT_TOKEN}"
volumes:
- ./hermes.json:/app/hermes.json:ro
- ./credentials:/root/.hermes/credentials
- ./data:/root/.hermes/data
- ./logs:/root/.hermes/logs
Things to call out:
127.0.0.1:8642— bind to localhost only. Never publish the gateway on0.0.0.0without TLS in front.- Credentials volume — the
credentials/directory MUST exist before first boot. Telegram pairing silently drops messages if it can't write sessions. - Config as read-only — mount
hermes.jsonwith:roso the container can't accidentally rewrite it on you. - Pin the image — for production use a version tag (e.g.
v2026.4.16) instead of:latest.
The hermes.json
A minimal agent config with Telegram, a single model, and the gateway exposed:
{
"gateway": {
"host": "0.0.0.0",
"port": 8642,
"auth": { "token": "CHANGE-ME-TO-A-LONG-RANDOM-STRING" },
"controlUi": { "allowInsecureAuth": true }
},
"models": {
"default": "openrouter/anthropic/claude-sonnet-4.6",
"providers": {
"openrouter": { "apiKey": "${OPENROUTER_API_KEY}" }
}
},
"channels": {
"telegram": {
"enabled": true,
"token": "${TELEGRAM_BOT_TOKEN}",
"dmPolicy": "pairing"
}
},
"plugins": {
"entries": {
"telegram": { "enabled": true }
}
}
}
If you later add WhatsApp, Discord, WeChat, or Feishu, flip them on here and add a matching plugins.entries.X.enabled: true — both are required for a channel to actually start.
First Boot
mkdir -p /opt/hermes/credentials /opt/hermes/data /opt/hermes/logs
cd /opt/hermes
cp docker-compose.yml hermes.json .
export OPENROUTER_API_KEY=...
export TELEGRAM_BOT_TOKEN=...
docker compose up -d
docker compose logs -f hermes
A healthy log ends with the gateway listening on 8642 and the Telegram plugin connected. If you see “credentials dir missing” or repeated channels login warnings, the credentials/ volume mount isn't set up — fix it and restart.
Adding TLS with Caddy
Put Caddy in the same compose file and let it auto-issue a cert:
caddy:
image: caddy:2
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
And a one-line Caddyfile:
hermes.example.com {
reverse_proxy hermes:8642
}
Point DNS at the host, docker compose up -d, and the web UI is reachable at https://hermes.example.com/ui with auto-renewing TLS.
Common Pitfalls
- Running as
:latestin production — an upstream change can break your config between restarts. Always pin. - Skipping the credentials mount — Telegram pairing will appear to work, then silently drop every message.
- Running without a reverse proxy — the gateway speaks plain HTTP. Tokens will leak if you skip TLS.
- Editing
hermes.jsonon a running container — some sections (gateway.auth, plugins) require a restart. Chat-safe hot-reload covers channels, models, agents, and that's mostly it. - Forgetting to rotate
gateway.auth.token— the default example token is famous. Generate a long random string on first boot and never commit it.
Backup
One tar covers you:
tar czf /opt/backups/hermes-$(date +%F).tar.gz \
-C /opt/hermes credentials data hermes.json
credentials/ is the sensitive part — it holds the session state for each chat channel. Keep those backups encrypted.
Skip It: OpenClaw Launch
The compose file above is fine for a weekend project. Run it in production and you inherit TLS renewal, image pinning, channel plugin installs, credentials backups, monitoring, and the inevitable “why did the container OOM at 3am” debugging.
Hermes hosting on OpenClaw Launch is the same Hermes Agent gateway — same config, same channels, same skills — on managed infrastructure with a warm pool, auto-TLS, backups, and a 10-second deploy. $6/mo on Lite after a $3 first month.
Next Steps
- Deploy Hermes Agent — step-by-step self-hosted install
- Hermes Agent web UI — what's in the dashboard
- Hermes Agent memory — where memory lives and how to back it up
- Hermes hosting on OpenClaw Launch — hosted in 10 seconds