hermes-agent Docker & Self-Hosted Deployment

GitHub

The agent that grows with you

256,242 stars Python Python 1 file ยท ~453,578 tokens #ai#ai-agent#ai-agents#anthropic#chatgpt#claude#claude-code#codex
RAW Compose
1. Pull Image (DOCKERHUB) docker pull library/hermes-agent
2. Docker Run (1-Click Launch) docker run -d --name hermes-agent --restart always hermes-agent
3. Podman Run podman run -d --name hermes-agent --restart always hermes-agent
4. Skopeo Inspect (Zero-Pull Manifest) skopeo inspect docker://docker.io/library/hermes-agent:latest
5. ORAS Pull (OCI Artifact) oras pull hermes-agent
6. Compose Deployment docker compose up -d
docker-compose.yml
Download .yml
#
# docker-compose.yml for Hermes Agent
#
# Usage:
#   HERMES_UID=$(id -u) HERMES_GID=$(id -g) docker compose up -d
#
# Set HERMES_UID / HERMES_GID to the host user that owns ~/.hermes so
# files created inside the container stay readable/writable on the host.
# The s6-overlay stage2 hook remaps the internal `hermes` user to these
# values via usermod/groupmod; each supervised service then drops to that
# user via `s6-setuidgid`.
#
# Security notes:
#   - The dashboard service binds to 127.0.0.1 by default. It stores API
#     keys; exposing it on LAN without auth is unsafe. If you want remote
#     access, use an SSH tunnel or put it behind a reverse proxy that
#     adds authentication โ€” do NOT pass --insecure --host 0.0.0.0.
#   - If you override entrypoint, keep `/init` as the first command in
#     the chain (or let docker use the image's default ENTRYPOINT,
#     which is `["/init", "/opt/hermes/docker/main-wrapper.sh"]`).
#     `/init` is s6-overlay's PID 1 โ€” it runs the cont-init.d scripts
#     (chown, profile reconcile, dashboard toggle) and sets up the
#     supervision tree before any service starts. Bypassing it skips
#     all of that setup and the gateway will not work correctly.
#   - The gateway's API server is off unless you uncomment API_SERVER_KEY
#     and API_SERVER_HOST. See docs/user-guide/api-server.md before doing
#     this on an internet-facing host.
#
services:
  gateway:
    build: .
    image: hermes-agent
    container_name: hermes
    restart: unless-stopped
    network_mode: host
    volumes:
      - ~/.hermes:/opt/data
    environment:
      - HERMES_UID=${HERMES_UID:-10000}
      - HERMES_GID=${HERMES_GID:-10000}
      # To expose the OpenAI-compatible API server beyond localhost,
      # uncomment BOTH lines (API_SERVER_KEY is mandatory for auth):
      # - API_SERVER_HOST=0.0.0.0
      # - API_SERVER_KEY=${API_SERVER_KEY}
      # Microsoft Teams โ€” uncomment and fill in to enable Teams gateway.
      # Register your bot at https://dev.botframework.com/ to get these values.
      # - TEAMS_CLIENT_ID=${TEAMS_CLIENT_ID}
      # - TEAMS_CLIENT_SECRET=${TEAMS_CLIENT_SECRET}
      # - TEAMS_TENANT_ID=${TEAMS_TENANT_ID}
      # - TEAMS_ALLOWED_USERS=${TEAMS_ALLOWED_USERS}
      # - TEAMS_PORT=${TEAMS_PORT:-3978}
      # Google Chat โ€” uncomment and fill in to enable the Google Chat gateway.
      # See website/docs/user-guide/messaging/google_chat.md for the full setup.
      # The SA JSON path must point to a file mounted into the container โ€”
      # add a volume entry above (e.g. ``- ~/.hermes/google-chat-sa.json:/secrets/google-chat-sa.json:ro``)
      # then set GOOGLE_CHAT_SERVICE_ACCOUNT_JSON to that mount path.
      # - GOOGLE_CHAT_PROJECT_ID=${GOOGLE_CHAT_PROJECT_ID}
      # - GOOGLE_CHAT_SUBSCRIPTION_NAME=${GOOGLE_CHAT_SUBSCRIPTION_NAME}
      # - GOOGLE_CHAT_SERVICE_ACCOUNT_JSON=${GOOGLE_CHAT_SERVICE_ACCOUNT_JSON}
      # - GOOGLE_CHAT_ALLOWED_USERS=${GOOGLE_CHAT_ALLOWED_USERS}
    command: ["gateway", "run"]

  dashboard:
    image: hermes-agent
    container_name: hermes-dashboard
    restart: unless-stopped
    network_mode: host
    depends_on:
      - gateway
    volumes:
      - ~/.hermes:/opt/data
    environment:
      - HERMES_UID=${HERMES_UID:-10000}
      - HERMES_GID=${HERMES_GID:-10000}
    # Localhost-only. For remote access, tunnel via `ssh -L 9119:localhost:9119`.
    command: ["dashboard", "--host", "127.0.0.1", "--no-open"]