본문으로 건너뛰기

Hermes Agent - Docker

Docker는 Hermes Agent와 두 가지 방식으로 만납니다.

  1. Hermes를 Docker 안에서 실행 - agent 자체가 container 안에서 실행됩니다. 이 페이지의 주된 내용입니다.
  2. Docker를 terminal backend로 사용 - agent는 host에서 실행되지만 모든 command를 하나의 persistent Docker sandbox container 안에서 실행합니다. 이 container는 tool call, /new, subagent를 지나 Hermes process가 살아 있는 동안 유지됩니다. 자세한 내용은 Configuration → Docker Backend를 참고하세요.

이 페이지는 1번을 다룹니다. container는 모든 user data(config, API key, session, skill, memory)를 host에서 /opt/data로 mount한 단일 directory에 저장합니다. image 자체는 stateless이므로, 새 version을 pull해 upgrade해도 configuration은 사라지지 않습니다.

빠른 시작

Hermes Agent를 처음 실행한다면 host에 data directory를 만들고, setup wizard를 실행하기 위해 container를 interactive mode로 시작합니다.

mkdir -p ~/.hermes
docker run -it --rm \
-v ~/.hermes:/opt/data \
nousresearch/hermes-agent setup

이 명령은 setup wizard로 들어갑니다. wizard는 API key를 묻고 ~/.hermes/.env에 기록합니다. 이 작업은 한 번만 하면 됩니다. 이 시점에서 gateway가 사용할 chat system도 함께 설정하는 것을 강력히 권장합니다.

gateway mode로 실행

설정이 끝나면 persistent gateway(Telegram, Discord, Slack, WhatsApp 등)로 container를 background에서 실행합니다.

docker run -d \
--name hermes \
--restart unless-stopped \
-v ~/.hermes:/opt/data \
-p 8642:8642 \
nousresearch/hermes-agent gateway run

port 8642는 gateway의 OpenAI-compatible API server와 health endpoint를 노출합니다. chat platform만 사용한다면 선택 사항이지만, dashboard나 external tool이 gateway에 접근해야 한다면 필요합니다.

참고: API server는 API_SERVER_ENABLED=true일 때만 켜집니다. container 안에서 127.0.0.1을 넘어 노출하려면 API_SERVER_HOST=0.0.0.0API_SERVER_KEY도 설정하세요. API_SERVER_KEY는 최소 8자여야 하며, openssl rand -hex 32로 생성할 수 있습니다. 예:

docker run -d \
--name hermes \
--restart unless-stopped \
-v ~/.hermes:/opt/data \
-p 8642:8642 \
-e API_SERVER_ENABLED=true \
-e API_SERVER_HOST=0.0.0.0 \
-e API_SERVER_KEY=your_api_key_here \
-e API_SERVER_CORS_ORIGINS='*' \
nousresearch/hermes-agent gateway run

internet-facing machine에서 port를 여는 것은 보안 위험입니다. 위험을 이해하지 못했다면 열지 마세요.

dashboard 실행

built-in web dashboard는 gateway와 같은 container 안에서 optional side-process로 실행됩니다. HERMES_DASHBOARD=1을 설정하고 gateway의 8642와 함께 9119 port를 노출합니다.

docker run -d \
--name hermes \
--restart unless-stopped \
-v ~/.hermes:/opt/data \
-p 8642:8642 \
-p 9119:9119 \
-e HERMES_DASHBOARD=1 \
nousresearch/hermes-agent gateway run

entrypoint는 main command를 exec하기 전에 background에서 hermes dashboard를 시작합니다. dashboard는 non-root hermes user로 실행됩니다. docker logs에서 dashboard output은 [dashboard] prefix가 붙으므로 gateway log와 구분하기 쉽습니다.

Environment variableDescriptionDefault
HERMES_DASHBOARDmain command와 함께 dashboard를 띄우려면 1(또는 true / yes)로 설정(unset - dashboard not started)
HERMES_DASHBOARD_HOSTdashboard HTTP server bind address0.0.0.0
HERMES_DASHBOARD_PORTdashboard HTTP server port9119
HERMES_DASHBOARD_TUIin-browser Chat tab(PTY/WebSocket을 통한 embedded hermes --tui)을 노출하려면 1로 설정(unset)

기본값 HERMES_DASHBOARD_HOST=0.0.0.0은 host가 published port를 통해 dashboard에 접근하려면 필요합니다. 이 경우 entrypoint는 자동으로 --insecurehermes dashboard에 전달합니다. dashboard를 container 내부 접근으로만 제한하고 싶다면(예: sidecar reverse proxy 뒤) 127.0.0.1로 override하세요.

노트

dashboard side-process는 supervised되지 않습니다. crash되면 container가 restart될 때까지 내려간 상태로 남습니다. 별도 container로 dashboard를 실행하는 것은 지원하지 않습니다. dashboard의 gateway-liveness detection은 gateway process와 shared PID namespace가 필요합니다.

interactive 실행(CLI chat)

실행 중인 data directory를 대상으로 interactive chat session을 열려면:

docker run -it --rm \
-v ~/.hermes:/opt/data \
nousresearch/hermes-agent

이미 실행 중인 container 안에 terminal을 열었다면(예: Docker Desktop), 다음만 실행하면 됩니다.

/opt/hermes/.venv/bin/hermes

Persistent volumes

/opt/data volume은 모든 Hermes state의 single source of truth입니다. host의 ~/.hermes/ directory에 mapping되며 다음을 포함합니다.

PathContents
.envAPI key와 secret
config.yaml모든 Hermes configuration
SOUL.mdagent personality/identity
sessions/conversation history
memories/persistent memory store
skills/installed skills
cron/scheduled job definition
hooks/event hooks
logs/runtime logs
skins/custom CLI skins
경고

같은 data directory를 대상으로 Hermes gateway container 두 개를 동시에 실행하지 마세요. session file과 memory store는 concurrent write access를 전제로 설계되지 않았습니다.

Multi-profile support

Hermes는 multiple profiles를 지원합니다. profile은 별도 ~/.hermes/ directory이며, 하나의 설치에서 서로 독립적인 agent(SOUL, skill, memory, session, credential)를 실행할 수 있게 합니다. 하지만 Docker에서 실행할 때는 Hermes의 built-in multi-profile 기능을 권장하지 않습니다.

권장 pattern은 profile마다 container 하나를 두고, 각 container가 host의 고유 directory를 /opt/data로 bind-mount하는 것입니다.

# Work profile
docker run -d \
--name hermes-work \
--restart unless-stopped \
-v ~/.hermes-work:/opt/data \
-p 8642:8642 \
nousresearch/hermes-agent gateway run

# Personal profile
docker run -d \
--name hermes-personal \
--restart unless-stopped \
-v ~/.hermes-personal:/opt/data \
-p 8643:8642 \
nousresearch/hermes-agent gateway run

Docker에서는 profile보다 separate container가 나은 이유:

  • Isolation - 각 container는 자체 filesystem, process table, resource limit을 갖습니다. 한 profile의 crash, dependency change, runaway session이 다른 profile에 영향을 주지 않습니다.
  • Independent lifecycle - 각 agent를 따로 upgrade, restart, pause, roll back할 수 있습니다. docker restart hermes-workhermes-personal에 영향을 주지 않습니다.
  • Clean port and network separation - 각 gateway가 고유 host port에 bind합니다. chat platform이나 API server 사이에 cross-talk 위험이 없습니다.
  • Simpler mental model - container 자체가 profile입니다. backup, migration, permission이 모두 bind-mounted directory를 따라가며, 추가 --profile flag를 기억할 필요가 없습니다.
  • Concurrent-write risk 회피 - 같은 data directory를 대상으로 gateway 두 개를 실행하지 말라는 위 warning은 single container 안의 profile에도 여전히 적용됩니다.

Docker Compose에서는 profile마다 service 하나를 선언하고 container_name, volumes, ports를 다르게 지정하면 됩니다.

services:
hermes-work:
image: nousresearch/hermes-agent:latest
container_name: hermes-work
restart: unless-stopped
command: gateway run
ports:
- "8642:8642"
volumes:
- ~/.hermes-work:/opt/data

hermes-personal:
image: nousresearch/hermes-agent:latest
container_name: hermes-personal
restart: unless-stopped
command: gateway run
ports:
- "8643:8642"
volumes:
- ~/.hermes-personal:/opt/data

environment variable forwarding

API key는 container 안의 /opt/data/.env에서 읽습니다. environment variable을 직접 전달할 수도 있습니다.

docker run -it --rm \
-v ~/.hermes:/opt/data \
-e ANTHROPIC_API_KEY="sk-ant-..." \
-e OPENAI_API_KEY="sk-..." \
nousresearch/hermes-agent

직접 전달한 -e flag는 .env의 값을 override합니다. key를 disk에 두고 싶지 않은 CI/CD나 secrets-manager integration에서 유용합니다.

Docker Compose 예제

gateway와 dashboard를 함께 persistent deployment로 운영하려면 docker-compose.yaml이 편리합니다.

services:
hermes:
image: nousresearch/hermes-agent:latest
container_name: hermes
restart: unless-stopped
command: gateway run
ports:
- "8642:8642" # gateway API
- "9119:9119" # dashboard (only reached when HERMES_DASHBOARD=1)
volumes:
- ~/.hermes:/opt/data
environment:
- HERMES_DASHBOARD=1
# Uncomment to forward specific env vars instead of using .env file:
# - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
# - OPENAI_API_KEY=${OPENAI_API_KEY}
# - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
deploy:
resources:
limits:
memory: 4G
cpus: "2.0"

docker compose up -d로 시작하고, docker compose logs -f로 log를 확인합니다. dashboard output은 [dashboard] prefix가 붙으므로 gateway log와 쉽게 구분됩니다.

resource limits

Hermes container는 중간 정도의 resource가 필요합니다. 권장 최소값:

ResourceMinimumRecommended
Memory1 GB2-4 GB
CPU1 core2 cores
Disk(data volume)500 MB2+ GB(session/skill이 쌓이며 증가)

browser automation(Playwright/Chromium)이 가장 memory를 많이 쓰는 기능입니다. browser tool이 필요 없다면 1GB로 충분합니다. browser tool을 활성화한다면 최소 2GB를 할당하세요.

Docker에서 limit 설정:

docker run -d \
--name hermes \
--restart unless-stopped \
--memory=4g --cpus=2 \
-v ~/.hermes:/opt/data \
nousresearch/hermes-agent gateway run

Dockerfile이 하는 일

공식 image는 debian:13.4 기반이며 다음을 포함합니다.

  • Python 3와 모든 Hermes dependency(uv pip install -e ".[all]")
  • Node.js + npm(browser automation과 WhatsApp bridge용)
  • Chromium이 포함된 Playwright(npx playwright install --with-deps chromium --only-shell)
  • system utility로 ripgrep, ffmpeg, git, tini
  • docker-cli - container 안에서 실행되는 agent가 host Docker daemon을 drive할 수 있게 합니다. opt-in하려면 /var/run/docker.sock을 bind-mount합니다. docker build, docker run, container inspection 등에 사용합니다.
  • openssh-client - container 안에서 SSH terminal backend를 사용할 수 있게 합니다. SSH backend는 system ssh binary를 shell out하므로, 이 패키지가 없으면 containerized install에서 조용히 실패했습니다.
  • WhatsApp bridge(scripts/whatsapp-bridge/)

entrypoint script(docker/entrypoint.sh)는 첫 실행 때 data volume을 bootstrap합니다.

  • directory structure(sessions/, memories/, skills/ 등) 생성
  • .env가 없으면 .env.example.env copy
  • config.yaml이 없으면 default copy
  • SOUL.md가 없으면 default copy
  • manifest-based 방식으로 bundled skills sync(user edit 보존)
  • HERMES_DASHBOARD=1이면 background side-process로 hermes dashboard 실행(dashboard 실행 참고)
  • 그 뒤 사용자가 전달한 argument로 hermes 실행
경고

/opt/hermes/docker/entrypoint.sh를 command chain에 유지하지 않을 것이라면 image entrypoint를 override하지 마세요. entrypoint는 gateway state file이 생성되기 전에 root privilege를 hermes user로 낮춥니다. 공식 image 안에서 hermes gateway run을 root로 시작하는 것은 기본적으로 거부됩니다. /opt/data에 root-owned file을 남겨 이후 dashboard나 gateway start를 망가뜨릴 수 있기 때문입니다. 그 위험을 의도적으로 감수할 때만 HERMES_ALLOW_ROOT_GATEWAY=1을 설정하세요.

upgrading

latest image를 pull하고 container를 다시 만듭니다. data directory는 그대로 유지됩니다.

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

Docker Compose를 쓰면:

docker compose pull
docker compose up -d

skill 및 credential file

Docker를 execution environment로 사용할 때(위 방식들이 아니라, agent가 Docker sandbox 안에서 command를 실행하는 경우 - Configuration → Docker Backend 참고), Hermes는 모든 tool call에 하나의 long-lived container를 재사용합니다. 또한 skills directory(~/.hermes/skills/)와 skill이 선언한 credential file을 read-only volume으로 자동 bind-mount합니다. 따라서 skill script, template, reference가 별도 설정 없이 sandbox 안에서 사용 가능하며, container가 Hermes process lifetime 동안 유지되므로 설치한 dependency나 작성한 file이 다음 tool call에도 남아 있습니다.

SSH와 Modal backend에서도 같은 sync가 일어납니다. 각 command 전에 skill과 credential file이 rsync 또는 Modal mount API로 upload됩니다.

local inference server에 연결(vLLM, Ollama 등)

Hermes를 Docker에서 실행하고 inference server(vLLM, Ollama, text-generation-inference 등)는 host 또는 다른 container에서 실행하는 경우 networking에 특히 주의해야 합니다.

두 service를 같은 Docker network에 둡니다. 가장 신뢰할 수 있는 방식입니다.

services:
vllm:
image: vllm/vllm-openai:latest
container_name: vllm
command: >
--model Qwen/Qwen2.5-7B-Instruct
--served-model-name my-model
--host 0.0.0.0
--port 8000
ports:
- "8000:8000"
networks:
- hermes-net
deploy:
resources:
reservations:
devices:
- capabilities: [gpu]

hermes:
image: nousresearch/hermes-agent:latest
container_name: hermes
restart: unless-stopped
command: gateway run
ports:
- "8642:8642"
volumes:
- ~/.hermes:/opt/data
networks:
- hermes-net

networks:
hermes-net:
driver: bridge

그런 다음 ~/.hermes/config.yaml에서 hostname으로 container name을 사용합니다.

model:
provider: custom
model: my-model
base_url: http://vllm:8000/v1
api_key: "none"
핵심 사항
  • hostname은 localhost127.0.0.1이 아니라 container name(vllm)을 사용하세요. localhost는 Hermes container 자체를 가리킵니다.
  • model 값은 vLLM에 전달한 --served-model-name과 일치해야 합니다.
  • api_key는 비어 있지 않은 아무 문자열이면 됩니다. vLLM은 header를 요구하지만 기본적으로 값을 검증하지 않습니다.
  • base_url 끝에 trailing slash를 붙이지 마세요.

standalone Docker run(no Compose)

inference server가 Docker가 아니라 host에서 직접 실행 중이라면, macOS/Windows에서는 host.docker.internal을 사용하고 Linux에서는 --network host를 사용합니다.

macOS / Windows:

docker run -d \
--name hermes \
-v ~/.hermes:/opt/data \
-p 8642:8642 \
nousresearch/hermes-agent gateway run
# config.yaml
model:
provider: custom
model: my-model
base_url: http://host.docker.internal:8000/v1
api_key: "none"

Linux(host networking):

docker run -d \
--name hermes \
--network host \
-v ~/.hermes:/opt/data \
nousresearch/hermes-agent gateway run
# config.yaml
model:
provider: custom
model: my-model
base_url: http://127.0.0.1:8000/v1
api_key: "none"
경고

--network host를 사용하면 -p flag는 무시됩니다. 모든 container port가 host에 직접 노출됩니다.

connectivity 확인

Hermes container 안에서 inference server에 접근 가능한지 확인합니다.

docker exec hermes curl -s http://vllm:8000/v1/models

served model list가 들어 있는 JSON response가 보여야 합니다. 실패하면 다음을 확인하세요.

  1. 두 container가 같은 Docker network에 있는지 확인합니다. (docker network inspect hermes-net)
  2. inference server가 127.0.0.1이 아니라 0.0.0.0에서 listen 중인지 확인합니다.
  3. port number가 일치하는지 확인합니다.

Ollama

Ollama도 같은 방식으로 동작합니다. Ollama가 host에서 실행 중이면 macOS/Windows에서는 host.docker.internal:11434, Linux에서는 --network host127.0.0.1:11434를 사용합니다. Ollama가 같은 Docker network의 자체 container에서 실행 중이라면:

model:
provider: custom
model: llama3
base_url: http://ollama:11434/v1
api_key: "none"

문제 해결

container가 즉시 종료됨

log를 확인하세요. docker logs hermes 일반적인 원인:

  • .env file이 없거나 잘못됨 - 먼저 interactive mode로 실행해 setup을 완료하세요.
  • 노출된 port가 충돌함

"Permission denied" 오류

container entrypoint는 gosu를 통해 non-root hermes user(UID 10000)로 privilege를 낮춥니다. host의 ~/.hermes/가 다른 UID 소유라면 HERMES_UID/HERMES_GID를 host user에 맞추거나, data directory가 writable인지 확인하세요.

chmod -R 755 ~/.hermes

browser tool이 작동하지 않음

Playwright는 shared memory가 필요합니다. Docker run command에 --shm-size=1g를 추가하세요.

docker run -d \
--name hermes \
--shm-size=1g \
-v ~/.hermes:/opt/data \
nousresearch/hermes-agent gateway run

network issue 뒤 gateway가 다시 연결되지 않음

--restart unless-stopped flag가 대부분의 transient failure를 처리합니다. gateway가 stuck 상태라면 container를 재시작하세요.

docker restart hermes

container health 확인

docker logs --tail 50 hermes          # Recent logs
docker run -it --rm nousresearch/hermes-agent:latest version # Verify version
docker stats hermes # Resource usage