Docker reference

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 DockerDocker as Hermes's terminal backend
What it meansThe whole agent (gateway, CLI, optional dashboard) runs inside the official containerHermes runs natively on your machine, but the commands it executes run inside a sandbox container
Why people want itServer deployment, isolation from the host's Python, one-command upgradesKeep the agent's shell commands off your host
How to set it upThe official image with a volume at /opt/data — this pageterminal.backend: docker plus terminal.docker_* keys in config.yaml
Where state livesThe mounted host directoryYour 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

1. One-time interactive setup (writes keys to ~/.hermes/.env)
bash
$mkdir -p ~/.hermes
$docker run -it --rm -v ~/.hermes:/opt/data nousresearch/hermes-agent setup
2. docker-compose.yml — gateway only
yaml
services:
hermes:
image: nousresearch/hermes-agent:latest
container_name: hermes
restart: unless-stopped
command: gateway run
volumes:
- ~/.hermes:/opt/data
3. Start and check
bash
$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 --portal once 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.
Sources disagree: The repository's own 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 (or PUID/PGID) to match. Don't make the directory world-readable — it contains credentials.
  • Backups: back up this directory with hermes backup run inside the container, not by copying state.db on its own — see Hermes backup and restore.
  • Tools you apt install inside a running container disappear when it is recreated. The docs suggest npx/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 doctor flags it.
  • NFS, SMB, and generic FUSE mounts are not detected — set database.journal_mode: delete yourself on those.
The two fixes in the official Docker guide
bash
# 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:

docker-compose.yml
yaml
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:

Profiles in one container (official docs)
bash
$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 stop stays 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 /init breaks setup and leaves zombie processes. If you must, add init: true.

Ports, the dashboard, and remote access

PortWhatOff by default?Before exposing it
8642OpenAI-compatible API server and health endpointYes — needs API_SERVER_ENABLED=trueBeyond the container's loopback, also set API_SERVER_HOST=0.0.0.0 and an API_SERVER_KEY
9119Web dashboardYes — needs HERMES_DASHBOARD=1An 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.

Our inference: The docs' Compose example sets 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

Pull and recreate (official docs)
bash
$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.yaml automatically and writes timestamped backups of config.yaml and .env first. Set HERMES_SKIP_CONFIG_MIGRATION=1 to 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 (every docker exec fails 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.

Not tested by this site: This page reconciles the official Docker guide, the repository's Compose file, and release notes. We have not run these containers on each host type, so we make no claims that Docker is easier, safer, or more reliable than a native install for your case.

Primary sources

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