Prerequisites
- A Linux server or desktop with Docker and the Compose plugin. Docker Desktop on macOS or Windows works, with the volume caveat under troubleshooting.
- Memory for the model: Hermes' Ollama guide asks for 24 GB of RAM or more for gemma4:31b, the model it recommends because the agent works through tool calls.
- A bot token for Telegram, Discord or Slack: the gateway talks to you through a chat platform.
- Optional: a cloud API key (Anthropic, OpenRouter...) if you would rather not run the model yourself.
Steps
- Create the folders
Hermes keeps all its state in one directory, mounted into the container at /opt/data: config.yaml, .env with the API keys, the sessions database state.db, memories and logs. The official image itself is stateless.
mkdir -p ~/agent-stack ~/.hermes cd ~/agent-stack - Write the compose file
Two services on Compose's default network: Ollama serves the model and Hermes Agent runs as the chat gateway. Hermes' Docker guide says the gateway's port 8642 is only needed for its API and dashboard, so no port is published, and Hermes reaches Ollama by its service name. OLLAMA_CONTEXT_LENGTH raises Ollama's default context (4,096 tokens) to the 64,000 Hermes asks for, and OLLAMA_KEEP_ALIVE keeps the model loaded for a gateway that answers at any hour. The tags are pinned: v0.22.2 is the Hermes Agent release of 15 October 2026 and 0.40.6 the Ollama image on Docker Hub on 18 October 2026. Until then this page used a Hermes tag that does not exist (2026.4.4), HERMES_* settings Hermes does not document, and bundled Qdrant, which Hermes does not use without a plugin, and Caddy, which this stack does not need since nothing faces the internet.
cat > docker-compose.yml <<'EOF' services: ollama: image: ollama/ollama:0.40.6 container_name: ollama restart: unless-stopped environment: OLLAMA_CONTEXT_LENGTH: "64000" OLLAMA_KEEP_ALIVE: "24h" volumes: - ollama:/root/.ollama hermes: image: nousresearch/hermes-agent:v0.22.2 container_name: hermes restart: unless-stopped command: gateway run volumes: - ~/.hermes:/opt/data depends_on: - ollama volumes: ollama: EOF - Pull the model
Hermes' Ollama guide recommends gemma4:31b, about 20 GB on disk, because it calls tools reliably; the smaller models it lists can chat but cannot call tools, so the agent could not act.
docker compose up -d ollama docker compose exec ollama ollama pull gemma4:31b docker compose exec ollama ollama list - Run Hermes' setup once
The wizard writes ~/.hermes/config.yaml and ~/.hermes/.env. Choose Custom Endpoint, with http://ollama:11434/v1 as the base URL (the service name, not localhost), no API key and gemma4:31b as the model, then add your chat platform: the gateway needs one. The same model settings can go straight into config.yaml instead.
docker compose run --rm hermes setup # or, in ~/.hermes/config.yaml: model: default: "gemma4:31b" provider: "custom" base_url: "http://ollama:11434/v1" - Start the gateway
In the official image the gateway runs under the s6 supervisor, which restarts it if it crashes. Besides docker logs, its rotated log stays on the volume in ~/.hermes/logs/gateways/default/current. Hermes' security docs ask for tight permissions on the .env that holds your keys.
docker compose up -d docker compose logs -f hermes chmod 600 ~/.hermes/.env - Optional: the web dashboard, over an SSH tunnel
The dashboard runs in the same container when HERMES_DASHBOARD=1. Inside the container it listens on all interfaces, so Hermes refuses to start it without an authentication provider; the username and password provider is meant for a trusted network or a VPN, not the open internet. Publish its ports (8642 for the gateway, 9119 for the dashboard, as in Hermes' example) on the host's loopback only, and reach them through SSH or Tailscale. The password and the session secret come from a .env file next to the compose file.
# add to the hermes service in docker-compose.yml: ports: - "127.0.0.1:8642:8642" - "127.0.0.1:9119:9119" environment: HERMES_DASHBOARD: "1" HERMES_DASHBOARD_BASIC_AUTH_USERNAME: "admin" HERMES_DASHBOARD_BASIC_AUTH_PASSWORD: ${HERMES_DASHBOARD_PASSWORD} HERMES_DASHBOARD_BASIC_AUTH_SECRET: ${HERMES_DASHBOARD_SECRET} # then, in ~/agent-stack: printf 'HERMES_DASHBOARD_PASSWORD=%s\nHERMES_DASHBOARD_SECRET=%s\n' \ "$(openssl rand -hex 16)" "$(openssl rand -hex 32)" > .env chmod 600 .env docker compose up -d # from your laptop: ssh -L 9119:127.0.0.1:9119 you@your-server # then open http://localhost:9119
Troubleshooting
- Hermes can't reach Ollama
- Inside the stack, services answer to their names: the base URL is http://ollama:11434/v1, not http://localhost:11434/v1. Check that docker compose exec ollama ollama list shows the model.
- The agent chats but never runs a tool, or loses the thread
- The model must support tool calls (Hermes' guide names gemma4:31b) and Ollama must give it at least 64,000 tokens of context: without OLLAMA_CONTEXT_LENGTH, Ollama's default is 4,096.
- Answers take minutes on a CPU-only box
- Hermes' Ollama guide expects about 2 to 5 tokens per second for a 31B model on a CPU. Give requests more time with HERMES_API_TIMEOUT=1800 in ~/.hermes/.env, or use a smaller model with tool calls, a GPU, or a cloud provider.
- Warnings about state.db on Docker Desktop (macOS or Windows)
- Bind mounts that cross Docker Desktop's VM (virtiofs, 9p) can corrupt a SQLite database in WAL mode. Hermes creates a fresh state.db in rollback mode there and warns about existing ones; the docs' other fix is a named volume for /opt/data instead of ~/.hermes.
- Session or memory files look corrupted
- Never run two Hermes containers on the same data directory: Hermes' Docker guide says its session files and memory stores do not support concurrent writers.
Where to go from here
This stack already follows Hermes' security policy for untrusted input: the whole agent runs inside its official image, so its shell commands run in the container, which only sees ~/.hermes. Updating means pulling a newer tag and recreating the container, since ~/.hermes keeps everything; pin the next release rather than latest and read its notes first. Prefer a cloud model? Run hermes setup again, pick the provider and remove the ollama service.
Sources
The steps and figures on this page come from these pages, read on 2026-10-18. When a command here and the project's docs disagree, the docs win.
- Hermes Agent docs: Hermes Docker setup (image, /opt/data, gateway run, ports, dashboard, compose example)
- Hermes Agent docs: local Ollama setup (custom endpoint, gemma4:31b, 64,000-token context, timeout)
- Hermes Agent docs: security (API keys in ~/.hermes/.env)
- Hermes Agent SECURITY.md (v0.22.2): run the whole agent in its Docker image for untrusted input
- Docker Hub: nousresearch/hermes-agent tags (v0.22.2)
- Ollama docs: Docker
- Ollama docs: FAQ (OLLAMA_CONTEXT_LENGTH, OLLAMA_KEEP_ALIVE)
- Docker Hub: ollama/ollama tags (0.40.6)