Hermes Agent in Docker
Nous Research publishes an official image, nousresearch/hermes-agent. Mount one host directory at /opt/data, run setup once interactively, then run the container in the background with gateway run and a restart policy. All of your state lives in that mounted directory; the image itself holds none, so you update by pulling a newer image and recreating the container — hermes update is not how Docker installs update.
The three things tutorials most often leave out: on Docker Desktop (macOS/Windows) a bind mount can corrupt the session database, browser tools need more shared memory than Docker's default, and two containers must never share one data directory.
Checked against official Nous Research sources on September 26, 2026 (Hermes Agent v0.21.5).
Two different things called “Hermes + Docker”
| Hermes runs in Docker | Docker as Hermes's terminal backend | |
|---|---|---|
| What it means | The whole agent (gateway, CLI, optional dashboard) runs inside the official container | Hermes runs natively on your machine, but the commands it executes run inside a sandbox container |
| Why people want it | Server deployment, isolation from the host's Python, one-command upgrades | Keep the agent's shell commands off your host |
| How to set it up | The official image with a volume at /opt/data — this page | terminal.backend: docker plus terminal.docker_* keys in config.yaml |
| Where state lives | The mounted host directory | Your normal ~/.hermes |
Several ranking tutorials mix these up. If you only want the agent's commands sandboxed, you don't need to containerize Hermes; see the official Configuration → Docker Backend docs. The rest of this page is about running Hermes itself in a container.
Setup and a persistent gateway
$mkdir -p ~/.hermes$docker run -it --rm -v ~/.hermes:/opt/data nousresearch/hermes-agent setup
services:hermes:image: nousresearch/hermes-agent:latestcontainer_name: hermesrestart: unless-stoppedcommand: gateway runvolumes:- ~/.hermes:/opt/data
$docker compose up -d$docker compose logs -f$docker exec -it hermes hermes # chat inside the running container
- A gateway with no ports published is enough for Telegram, Discord, and other chat platforms: they connect outward. Publish ports only for the API server or dashboard (below).
- Nous Portal sign-in works inside the container: run
hermes setup --portalonce and the token persists in the volume. - The docs warn against pasting these commands into browser-based VPS consoles, which can mangle
:,@, and=. Use SSH. - Images are built for amd64 and arm64. Tags:
latest/stable(release-gated),main(development builds), and versioned tags; use an image digest for an exact pin.
docker-compose.yml differs from the docs' Compose example: it builds the image locally (build: .), uses network_mode: host, and runs the dashboard as a second container bound to 127.0.0.1. The docs example pulls nousresearch/hermes-agent:latest and runs the dashboard inside the gateway container. Both are official; the example above follows the docs' pull-the-image approach.What lives in /opt/data
/opt/data is the container's HERMES_HOME — the single source of truth. It holds .env (API keys), config.yaml, SOUL.md, state.db and sessions, memories/, skills/, cron/, profiles/, logs/, and home/ (the HOME that tool subprocesses such as git and ssh see). The application under /opt/hermes is read-only to the runtime user.
- Permissions: processes run as UID 10000. If your host directory belongs to another user, set
HERMES_UID/HERMES_GID(orPUID/PGID) to match. Don't make the directory world-readable — it contains credentials. - Backups: back up this directory with
hermes backuprun inside the container, not by copyingstate.dbon its own — see Hermes backup and restore. - Tools you
apt installinside a running container disappear when it is recreated. The docs suggestnpx/uvx, a derived image, or a sidecar container for durable tools.
The SQLite trap on Docker Desktop, Podman, and OrbStack
Hermes keeps sessions in SQLite (/opt/data/state.db) in WAL mode by default. WAL needs shared memory that stays consistent between processes, and bind mounts that cross a VM boundary don't provide it: virtiofs (Docker Desktop and Podman on macOS, OrbStack) and 9p/drvfs (Docker Desktop on Windows). The official docs say concurrent writers on those mounts can silently corrupt the database while it still passes an integrity check. A Linux host with a normal bind mount is not affected.
- Since v2026.9.14 (v0.21.3) a new database on such a mount is created in rollback mode automatically, with a warning.
- An existing WAL database on such a mount is not converted live; every process logs an error and
hermes doctorflags it. - NFS, SMB, and generic FUSE mounts are not detected — set
database.journal_mode: deleteyourself on those.
# Option A: named volume (lives on the Docker VM's own filesystem; WAL works)$docker run ... -v hermes-data:/opt/data nousresearch/hermes-agent gateway run$# Option B: keep the bind mount, convert once with every Hermes process stopped$docker exec hermes python3 -c "import sqlite3; print(sqlite3.connect('/opt/data/state.db').execute('PRAGMA journal_mode=DELETE').fetchone()[0])"# then in /opt/data/config.yaml:# database:# journal_mode: delete
A named volume is not a folder you can open in Finder or Explorer; reach its files through the container (docker exec) or docker cp. Background on the wider state.db problems in v0.21.0–v0.21.1 is on the backup page.
Browser tools need shared memory
Browser automation (Playwright/Chromium) needs more shared memory than Docker's default. The official troubleshooting fix is --shm-size=1g on docker run, or in Compose:
services:hermes:shm_size: "1g"
The Docker guide's recommended minimums for the container are 1 GB RAM and 1 CPU core without browser tools, and at least 2 GB with them (2–4 GB recommended); its Compose example caps the container at 4 GB and 2 CPUs.
One data directory, one writer — and many profiles
Never run two Hermes gateway containers against the same data directory. The docs say session and memory stores are not designed for concurrent writers from separate containers. To run several agents, use profiles inside one container:
$docker exec hermes hermes profile create research # gets its own supervised gateway$docker exec hermes hermes -p research gateway start$docker exec hermes hermes gateway status
- The image runs s6-overlay as PID 1. Each profile gets its own supervised gateway that restarts within seconds if it crashes, with rotated logs at
logs/gateways/<profile>/current. - After a container restart or image upgrade, every gateway whose last state was running comes back; only one you stopped with
hermes gateway stopstays down. docker exec hermes hermes …automatically drops from root to the runtime user, so files it writes stay readable by the gateway.- Separate containers per profile still make sense for per-workload memory limits, different image versions, or network separation — each with its own data directory.
- Don't override the image's
entrypoint: skipping s6's/initbreaks setup and leaves zombie processes. If you must, addinit: true.
Ports, the dashboard, and remote access
| Port | What | Off by default? | Before exposing it |
|---|---|---|---|
8642 | OpenAI-compatible API server and health endpoint | Yes — needs API_SERVER_ENABLED=true | Beyond the container's loopback, also set API_SERVER_HOST=0.0.0.0 and an API_SERVER_KEY |
9119 | Web dashboard | Yes — needs HERMES_DASHBOARD=1 | An auth provider (username/password, Nous Portal OAuth, or your own OIDC) |
Inside the container the dashboard binds 0.0.0.0 by default so a published port can reach it. Any non-loopback bind requires an auth provider, and without one the dashboard refuses to start. The old --insecure escape hatch is gone; HERMES_DASHBOARD_INSECURE is now ignored. The docs tie that change to a June 2026 campaign in which scanners reached exposed dashboards and planted SSH-key backdoors through the agent.
HERMES_DASHBOARD=1 and publishes 9119 but sets no auth variables. By the rules above, its dashboard will not start until you add a provider, for example HERMES_DASHBOARD_BASIC_AUTH_USERNAME/_PASSWORD. Separately, a plain "9119:9119" mapping publishes on every host interface; "127.0.0.1:9119:9119" keeps it on the host's loopback for an SSH tunnel. That second point is standard Docker behavior, not something the Hermes docs state.Updating
$docker compose pull$docker compose up -d$# or without Compose$docker pull nousresearch/hermes-agent:latest$docker rm -f hermes$docker run -d --name hermes --restart unless-stopped -v ~/.hermes:/opt/data nousresearch/hermes-agent gateway run
- On start, the new image migrates
config.yamlautomatically and writes timestamped backups ofconfig.yamland.envfirst. SetHERMES_SKIP_CONFIG_MIGRATION=1to inspect before it does. - Recreating is safe for your data because it lives in the volume; it discards anything installed into the container by hand.
- Images built before late August 2026 could lock the runtime user out of
/opt/hermes(everydocker execfails with Permission denied). Pulling a current image fixes it. - Taking a backup before a major version jump costs one command.
Docker on a VPS, and local models
Docker is one of three documented ways to run Hermes on a server; provisioning, firewalling, and choosing between Docker and a native install with a systemd service are covered in the VPS guide. On a Linux VPS the SQLite bind-mount trap above does not apply.
To reach Ollama or another inference server from inside the container, use host.docker.internal on macOS/Windows, host networking on Linux, or a shared Compose network with the service name (for example http://ollama:11434/v1). Requirements for the model itself are on Hermes local models.
Primary sources
- Hermes Docker Setup — official docs
- Repository docker-compose.yml
- Web Dashboard authentication — official docs
- Configuration → Docker terminal backend — official docs
- Platform Support (Docker tier) — official docs
- Hermes Agent v0.21.3 release notes (image tag v2026.9.14)
- Docker Hub — nousresearch/hermes-agent
HermesAgentAI.org is an independent educational documentation resource and community guide. It is not affiliated with, sponsored by, or endorsed by Nous Research or FlyHermes. Hermes Agent is released under the MIT License by Nous Research.
Where to go next
Desktop app and the one-line installer, if Docker isn't a requirement.
Deploy the container image to Cloud Run Instances with GCS FUSE persistence.
Server setup, firewalling, and the native systemd alternative.
Protect and move the /opt/data directory.
Auth providers and safe remote access.