Back to Blog
HermesDockerSelf-HostingTutorial

How to Run Hermes Agent in Docker (Self-Hosted)

Deploy Hermes Agent in Docker with persistent volumes, docker-compose, and a production-ready setup. Covers data, secrets, ports, and upgrades.

By Hermify Team||7 min read
A dark server room with a single rack lit in green, evoking a quiet self-hosted AI agent running 24/7

Why Docker Is the Default Way to Run Hermes Agent

Hermes Agent ships as a Docker container as its first-class deployment target. The image bundles the gateway, the dashboard, the runtime dependencies, and a sane default configuration so you do not have to wrestle with Python versions, system libraries, or PATH issues on the host. You bring a host with Docker installed, a small persistent volume for state, and your provider API key. The container does the rest.

A typical self-hosted setup looks like this:

  • One gateway container exposing port 8642 for the OpenAI-compatible API and the health endpoint.
  • One persistent named volume for sessions, memory, learned skills, and configuration.
  • One .env file with provider keys and Telegram credentials.
  • Optionally, a sidecar dashboard container reading the same data directory in read-only mode.

Everything else - upgrades, restarts, log rotation - is handled by Docker itself. This post walks through that setup end to end, then shows the production-ready docker-compose layout and the gotchas worth knowing before you put the agent on a public host.

If you have not chosen between hosting it yourself and a managed setup, read self-hosting vs managed Hermes Agent first. The rest of this guide assumes you have decided to run the container yourself.

Prerequisites

You need:

  • A host with Docker 24+ installed (Linux VPS, macOS via Docker Desktop, or Windows via WSL2).
  • At least 1 vCPU and 2 GB of RAM. The official recommendation is 2 vCPU and 8 GB for comfortable concurrent use.
  • A provider API key (OpenAI, Anthropic, OpenRouter, or any OpenAI-compatible endpoint).
  • About 2 GB of free disk space for the image, plus growth room for the data volume.

A $5 VPS from any reasonable provider clears the minimum. The agent is I/O-light and CPU-light when not actively reasoning - most of its day is spent idle waiting for Telegram messages or scheduled tasks.

Step 1 - Create the Data Directory

The container persists everything to /data inside the image. On the host, decide where that directory lives. The convention is ~/.hermes/data:

mkdir -p ~/.hermes/data

This single directory holds session history, vector memory, learned skills, encrypted secrets, and the user config. Back this up and you have backed up the entire agent. Lose it and you start from scratch - the container itself is ephemeral.

Step 2 - First-Run Setup Wizard

Run the container interactively the first time so it can prompt you for keys and write them to ~/.hermes/.env:

docker run -it --rm \
  -v ~/.hermes:/root/.hermes \
  -v ~/.hermes/data:/data \
  ghcr.io/nousresearch/hermes-agent:latest setup

The wizard asks for:

  • The default LLM provider (OpenAI, Anthropic, OpenRouter, custom).
  • The provider API key.
  • Optional Telegram bot token and allowed-users list.
  • Optional voice provider keys (only if you plan to enable voice mode).

The values are written to ~/.hermes/.env on the host. Treat that file as a secret - chmod 600 ~/.hermes/.env and never commit it.

A terminal showing the Hermes Agent Docker setup wizard prompting for an OpenAI API key, with the new .env file path visible at the top

Step 3 - Run the Persistent Gateway

Once the wizard has finished, the long-running form of the same container starts the gateway:

docker run -d \
  --name hermes \
  --restart unless-stopped \
  -p 8642:8642 \
  --env-file ~/.hermes/.env \
  -v ~/.hermes/data:/data \
  ghcr.io/nousresearch/hermes-agent:latest gateway

Breakdown of each flag:

  • -d runs the container detached, in the background.
  • --restart unless-stopped brings it back automatically after host reboots and crashes.
  • -p 8642:8642 exposes the OpenAI-compatible API and the /health endpoint.
  • --env-file ~/.hermes/.env injects provider keys without baking them into the image.
  • -v ~/.hermes/data:/data is the persistence line - delete this line and the agent forgets everything every restart.

Verify it is healthy:

curl http://localhost:8642/health
# {"status":"ok","gateway":"running"}

If you are running on a VPS that you want to reach from your laptop, do not bind the port to 0.0.0.0 directly. Put a reverse proxy (Caddy, Nginx, Traefik) in front with HTTPS, or only expose the port over Tailscale or WireGuard. The OpenAI-compatible API has no auth by default - it trusts the network it is on.

Step 4 - Use docker-compose for Production

For anything beyond a quick test, switch to docker-compose.yaml. It makes the configuration reviewable, restartable as a unit, and easy to extend with the optional dashboard sidecar:

services:
  gateway:
    image: ghcr.io/nousresearch/hermes-agent:latest
    container_name: hermes-gateway
    restart: unless-stopped
    command: gateway
    ports:
      - "127.0.0.1:8642:8642"
    env_file:
      - ./.env
    volumes:
      - hermes_data:/data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8642/health"]
      interval: 30s
      timeout: 5s
      retries: 3
    deploy:
      resources:
        limits:
          memory: 1G

  dashboard:
    image: ghcr.io/nousresearch/hermes-agent:latest
    container_name: hermes-dashboard
    restart: unless-stopped
    command: dashboard
    ports:
      - "127.0.0.1:8643:8643"
    volumes:
      - hermes_data:/data:ro
    depends_on:
      gateway:
        condition: service_healthy

volumes:
  hermes_data:

A few details worth noting:

  • The dashboard container mounts the data volume read-only (:ro). It only reads sessions and memory to render the UI, never writes them. That is what makes running both safely possible.
  • The gateway port is bound to 127.0.0.1 on the host. Public exposure is the reverse proxy's job, not Docker's.
  • healthcheck lets depends_on wait for the gateway before starting the dashboard.
  • A 1 GB memory limit is comfortable for most personal-scale workloads. Bump it for high-traffic use.

Bring the stack up with docker compose up -d and tail logs with docker compose logs -f.

A simplified architecture diagram showing the Docker host with two containers, gateway and dashboard, sharing a single named volume mounted read-only on the dashboard side

Step 5 - Upgrades

The container is the unit of upgrade. To move to a new release:

docker compose pull
docker compose up -d

Compose recreates the gateway with the new image while keeping the named volume intact. Memory, skills, and Telegram connections come back exactly as they were. Pin to a specific tag instead of latest for production - ghcr.io/nousresearch/hermes-agent:0.42 rather than :latest - so upgrades are explicit.

Before any upgrade, snapshot the volume:

docker run --rm \
  -v hermes_data:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/hermes-$(date +%F).tar.gz -C /data .

Restoring is the same command in reverse. This is faster and safer than rolling back the image alone.

Common Pitfalls

Two gateway containers on the same volume. Hermes session and memory stores assume a single writer. Running two gateway containers against the same /data will corrupt files within minutes. The dashboard sidecar is fine because it is read-only.

Missing --env-file. Without it, the container starts but fails the first LLM call with a 401. Check docker logs hermes if responses never arrive.

Binding to 0.0.0.0:8642 on a public VPS. The API has no built-in auth. Always front it with a reverse proxy that requires HTTPS plus either basic auth or a network-level restriction (Tailscale, firewall rules).

Anonymous volumes. If you forget the -v ~/.hermes/data:/data line, Docker creates an anonymous volume. It survives restarts but is hard to find and easy to prune accidentally. Always use a named volume or a host bind.

Telegram bot reconnection. When you upgrade, the bot reconnects automatically. If it does not, check that TELEGRAM_BOT_TOKEN is still in .env and that the container has internet egress.

For Telegram-specific issues, Hermes Agent Telegram troubleshooting covers the messaging side in more depth.

Skip the Container Plumbing

Running Hermes in Docker is straightforward, but you still own the host: backups, TLS certs, log rotation, OS patches, and the upgrade cadence. For a personal agent that is fine - a Sunday afternoon of setup and maybe ten minutes a month afterward.

If you would rather skip all of that, Hermify runs your Hermes agent in an isolated managed container, with encrypted-at-rest secrets, automatic upgrades, daily volume snapshots, and Telegram connected through the dashboard in two taps. You bring a provider key; the platform handles everything below.

Sources

Run Your Own Hermes Agent

Bring your API key, connect Telegram, and get a self-improving AI agent live in 60 seconds.

Get Started