Nous Research의 Hermes Agent를 Apple Silicon(M1/arm64) Mac에서 Docker 전용으로 설치·실행하는 절차입니다. 공식 문서: https://hermes-agent.nousresearch.com/docs/user-guide/docker

이 환경의 실제 구성

  • Compose 파일: ~/projects/your-project/hermes/docker-compose.yml (mattermost와 같은 레벨)
  • 데이터 디렉터리: ~/.hermes (컨테이너의 /opt/data에 마운트)
  • hermes 명령: 호스트에 네이티브 설치 안 함 → alias로 docker exec 연결 (아래 7번 참고)

개요

  • Hermes는 모든 상태(설정·API 키·세션·메모리·스킬)를 /opt/data 한 곳에 저장합니다.
  • 이 디렉터리를 호스트의 ~/.hermes에 마운트하므로, 컨테이너는 지워도 ~/.hermes만 있으면 그대로 복구됩니다.
  • 이미지는 멀티 아키텍처로 배포되어 M1에서 --platform 지정 없이 자동으로 arm64 레이어를 받습니다.

필수 / 선택 요약

단계 필수 여부 비고
0. Docker 설치 확인 ✅ 필수 Docker Desktop (Apple Silicon)
1. 데이터 폴더 + setup 마법사 ✅ 필수 (최초 1회) API 키 저장
2. docker run으로 실행 ☑️ 택1 간단 실행
3. Docker Compose로 실행 ☑️ 택1 (권장) 관리 편의
4. 대화형 CLI 선택 채팅 테스트
5. 점검 · 업그레이드 선택 필요 시

주의: 2번과 3번은 둘 중 하나만. 같은 ~/.hermes에 gateway 컨테이너를 동시에 2개 띄우면 세션 파일이 손상됩니다.

최소 경로: 0 → 1 → (2 또는 3)


0. 사전 준비 (필수)

Docker Desktop Apple Silicon 버전이 설치되어 있어야 합니다.

docker --version
docker compose version

두 명령이 모두 정상 출력되면 준비 완료.


1. 데이터 디렉터리 생성 + 초기 설정 마법사 (필수, 최초 1회)

mkdir -p ~/.hermes

docker run -it --rm \
  -v ~/.hermes:/opt/data \
  nousresearch/hermes-agent setup
  • API 키(예: ANTHROPIC_API_KEY, OPENAI_API_KEY)를 대화형으로 입력 → ~/.hermes/.env에 저장됩니다.
  • 모델은 컨텍스트 64k 토큰 이상이 필요합니다.
  • 최초 1회만 실행하면 됩니다.

2. Gateway(백그라운드 서비스)로 실행 — 2·3번 중 택1

docker run -d \
  --name hermes \
  --restart unless-stopped \
  -v ~/.hermes:/opt/data \
  -p 8642:8642 \
  --memory=4g --cpus=2 --shm-size=1g \
  nousresearch/hermes-agent gateway run
  • 8642 : OpenAI 호환 API / 헬스체크 포트
  • --shm-size=1g : 브라우저 툴(Playwright) 사용 시 필요
  • M1 메모리 여유가 있으면 --memory=4g 권장

3. Docker Compose로 실행 (권장) — 2·3번 중 택1

~/projects/your-project/hermes/docker-compose.yml 파일을 만듭니다. (같은 폴더에 이 가이드도 함께 둡니다.)

services:
  hermes:
    image: nousresearch/hermes-agent:latest
    container_name: hermes
    restart: unless-stopped
    command: gateway run
    ports:
      - "8642:8642"    # OpenAI 호환 gateway API / 헬스체크
      - "9119:9119"    # 웹 대시보드
    volumes:
      - ~/.hermes:/opt/data   # 데이터 영속화 (점 있는 .hermes)
    environment:
      - HERMES_DASHBOARD=1
      - HERMES_DASHBOARD_HOST=127.0.0.1   # localhost 전용 → 인증 불필요
    shm_size: "1g"    # 브라우저 툴(Playwright)용 — 서비스 최상위 키
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: "2.0"

참고: deploy.resources.limits는 Swarm 모드에서만 강제됩니다. 일반 docker compose up에서 실제 제한을 걸려면 mem_limit: 4g / cpus: 2.0를 서비스 최상위에 두세요.

실행:

cd ~/projects/your-project/hermes
docker compose up -d

4. 대화형 CLI로 사용해보기 (선택)

# 새 임시 세션
docker run -it --rm -v ~/.hermes:/opt/data nousresearch/hermes-agent

# 이미 실행 중인 컨테이너에 접속
docker exec -it hermes /opt/hermes/.venv/bin/hermes

5. 점검 · 업그레이드 (선택, 필요 시)

# 로그 확인
docker logs hermes

# 진단
docker exec -it hermes hermes doctor

# 업그레이드 (Compose)
docker compose pull && docker compose up -d

# 업그레이드 (docker run)
docker pull nousresearch/hermes-agent:latest
docker rm -f hermes
docker run -d ... nousresearch/hermes-agent gateway run

설정은 자동 마이그레이션되며, 사전에 타임스탬프 백업이 생성됩니다.


6. 트러블슈팅 — hermes 명령이 안 될 때

docker compose up -d로 컨테이너는 떴는데, 호스트에서 hermes를 치면 아래 에러가 날 수 있습니다.

/Users/<user>/.local/bin/hermes: line 4:
  /Users/<user>/.hermes/hermes-agent/venv/bin/hermes: No such file or directory

원인: hermes를 치면 실행되는 건 Docker 컨테이너가 아니라, 과거에 네이티브 설치(install.sh 원라이너)를 시도하다 만 흔적인 호스트의 깨진 stub(~/.local/bin/hermes)입니다. 가리키는 venv 경로가 없어서 실패합니다.

핵심: Docker 방식과 네이티브 방식은 완전히 별개입니다. Docker로 띄웠으면 Hermes는 컨테이너 안에서 돌고, 호스트의 hermes 명령과는 무관합니다.

올바른 사용법 (컨테이너 안에서 실행):

# 컨테이너 상태 확인
docker ps --filter name=hermes

# 대화형 CLI 접속
docker exec -it hermes /opt/hermes/.venv/bin/hermes

7. Docker 전용 정리 (네이티브 흔적 제거 + alias)

Docker 방식만 쓸 경우, 혼동을 유발하는 깨진 네이티브 stub을 지우고 hermesdocker exec로 연결합니다.

# ① 깨진 네이티브 stub 삭제 (Docker 데이터 ~/.hermes 는 건드리지 않음)
rm -f ~/.local/bin/hermes

# ② hermes 명령을 Docker 컨테이너로 연결하는 alias 등록
echo "alias hermes='docker exec -it hermes /opt/hermes/.venv/bin/hermes'" >> ~/.zshrc
source ~/.zshrc

주의: ~/.local/bin/hermes(깨진 stub)와 ~/.hermes(Docker 데이터 디렉터리)는 다릅니다. 지우는 건 stub 파일뿐이며, 데이터 디렉터리 ~/.hermes(config·세션·skills)는 절대 삭제하지 마세요.

등록 후에는 그냥 hermes로 CLI에 접속됩니다.

hermes            # = docker exec -it hermes /opt/hermes/.venv/bin/hermes
hermes doctor     # 진단
hermes --tui      # TUI 인터페이스

8. 트러블슈팅 — Mattermost가 계속 retrying 일 때

Docker로 띄운 Hermes 게이트웨이에서 Mattermost 봇이 연결되지 않고 계속 재시도(failed to reconnect)만 하는 경우가 있습니다.

증상

게이트웨이 로그(docker logs hermes 또는 ~/.hermes/logs/gateway.log)에 반복되는 에러:

Mattermost: failed to authenticate — check MATTERMOST_TOKEN and MATTERMOST_URL
MM API GET users/me network error: Cannot connect to host localhost:8065 ...
  Connect call failed ('127.0.0.1', 8065)

gateway_state.json(~/.hermes/gateway_state.json)을 보면 platforms.mattermost.state"retrying" 입니다.

원인

.envMATTERMOST_URLhttp://localhost:8065/ 로 되어 있으면, Hermes 컨테이너 입장에서 localhost컨테이너 자신(127.0.0.1) 을 가리킵니다. Mattermost 서버는 호스트 쪽(또는 별도 컨테이너)에 떠 있으므로 컨테이너 내부 루프백으로는 닿지 않습니다. 즉 설정 자체는 되어 있지만 주소가 틀린 상태입니다.

핵심: Docker 컨테이너 안의 localhost ≠ 호스트. 호스트 쪽 서비스는 host.docker.internal 로 접근해야 합니다 (아래 M1 참고 사항 표 참고).

해결 절차

  1. Mattermost 서버 실제 주소 확인 (컨테이너 안에서)

    # 호스트 쪽 8065가 열려 있는지
    docker exec -it hermes bash -c \
      'cat < /dev/null > /dev/tcp/host.docker.internal/8065 && echo OPEN || echo CLOSED'
    
  2. .env 의 URL 수정 (~/.hermes/.env 는 컨테이너 /opt/data/.env)

    - MATTERMOST_URL=http://localhost:8065/
    + MATTERMOST_URL=http://host.docker.internal:8065/
    

    MATTERMOST_TOKEN, MATTERMOST_ALLOWED_USERS, MATTERMOST_HOME_CHANNEL 도 함께 들어 있어야 정상 동작합니다.

  3. 게이트웨이 재시작.env 는 시작 시점에만 읽히므로 반영하려면 재시작 필요. s6(슈퍼바이저)가 자동으로 새 설정으로 띄웁니다.

    # 게이트웨이 pid 확인 후 kill (s6가 재시작)
    docker exec -it hermes bash -c 'kill $(pgrep -f "hermes gateway run")'
    # 또는 호스트에서 컨테이너 재시작
    docker restart hermes
    
  4. 연결 확인

    docker logs hermes 2>&1 | grep -i mattermost | tail
    

    아래 로그가 보이면 성공:

    Mattermost: authenticated as @hermes-bot on http://host.docker.internal:8065
    ✓ mattermost connected
    Mattermost: WebSocket connected and authenticated
    

    또는 상태 파일 확인:

    docker exec -it hermes cat /opt/data/gateway_state.json | \
      python3 -c 'import json,sys;print(json.load(sys.stdin)["platforms"]["mattermost"]["state"])'
    # connected 가 출력되면 OK
    

주의

  • 컨테이너를 완전 재생성(docker compose down 후 이미지 재 pull 등)하면 ~/.hermes/.env 가 초기화될 수 있습니다. .env 가 호스트의 ~/.hermes 에 마운트되어 있으면 보존되지만, 이미지를 지우는 게 아니라면 영속 볼륨/바인드 마운트로 ~/.hermes 가 유지되는지 한 번 더 확인하세요.
  • localhost / 127.0.0.1 대신 반드시 host.docker.internal 로 지정해야 합니다 (Ollama 항목과 동일 원리).

9. 로컬 LLM(Ollama) 연결하기

Docker로 띄운 Hermes를 호스트의 Ollama 로컬 모델로 구동할 수 있습니다. 인터넷 연결 없이, 무료로, 프라이빗하게 에이전트를 돌릴 수 있습니다.

사전 확인

호스트에서 Ollama가 구동 중이고 모델이 설치되어 있어야 합니다.

# 호스트에서 Ollama 상태 / 설치된 모델 확인
ollama list
# gemma4:e2b 같은 모델이 없으면 설치
ollama pull gemma4:e2b

컨테이너 안에서 Ollama 포트(11434)가 닿는지도 확인합니다 (127.0.0.1이 아니라 host.docker.internal):

docker exec -it hermes bash -c \
  'cat < /dev/null > /dev/tcp/host.docker.internal/11434 && echo OPEN || echo CLOSED'

설정

~/.hermes/config.yamlmodel 섹션을 Ollama(OpenAI 호환 엔드포인트)로 변경합니다. 호스트 쪽 서비스이므로 URL은 host.docker.internal 입니다.

model:
  default: gemma4:e2b
  provider: custom                       # Ollama는 OpenAI 호환 커스텀 엔드포인트
  base_url: http://host.docker.internal:11434/v1
  api_key: ollama                        # Ollama는 키 미사용(더미값이라도 필요)
  context_length: 65536                  # Hermes 최소 64K 요구 → 강제 상향

hermes config set 으로도 동일하게 지정 가능:

docker exec -it hermes /opt/hermes/.venv/bin/hermes config set model.default gemma4:e2b
docker exec -it hermes /opt/hermes/.venv/bin/hermes config set model.provider custom
docker exec -it hermes /opt/hermes/.venv/bin/hermes config set model.base_url http://host.docker.internal:11434/v1
docker exec -it hermes /opt/hermes/.venv/bin/hermes config set model.api_key ollama
docker exec -it hermes /opt/hermes/.venv/bin/hermes config set model.context_length 65536

적용

모델 설정은 세션 시작 시점에 읽히므로, 변경을 반영하려면 새 세션으로 들어가야 합니다(현재 세션은 바꾸기 전 모델을 그대로 씀).

hermes          # 새 세션 → 이제 gemma4:e2b 로컬 모델로 대답
# 또는 게이트웨이 경유 시 컨테이너 재시작
docker restart hermes

연결 테스트(컨테이너 밖 호스트에서):

docker exec -it hermes /opt/hermes/.venv/bin/hermes chat -q 'say OK in one word'
# => OK  (정상 응답 시 로컬 모델 연결 성공)

알아둘 점

  • context_length 는 64K 이상으로 강제합니다. Hermes가 64K 미만 컨텍스트를 거부하기 때문입니다. 실제 모델 윈도우보다 크게 잡아도 Ollama가 알아서 처리하므로 동작엔 문제 없습니다.
  • thinking 모델 주의: Gemma 4 계열처럼 추론(reasoning)을 출력하는 모델은 max_tokens 가 작으면 추론에 토큰을 다 써서 실제 답이 비어 나올 수 있습니다. 충분한 토큰을 주면 정상 응답합니다(테스트 완료).
  • 모델 용량: gemma4:e2b(5.1B)는 가벼워 코드 생성·긴 추론·복잡한 툴 사용엔 한계가 있을 수 있습니다. 더 큰 모델이 필요하면 ollama pull <모델> 로 받아 model.default 만 바꾸면 됩니다.
  • 복귀: 다시 클라우드 모델을 쓰려면 model.provider/base_url/default 를 원래 값(nous + Nous inference URL)으로 되돌리세요.

M1(Apple Silicon) 참고 사항

항목 내용
아키텍처 오류 시 docker run --platform linux/arm64 ... 로 명시 (보통 불필요)
로컬 추론 서버(Ollama 등) 호스트에서 구동 시 base_url: http://host.docker.internal:11434/v1 사용 (127.0.0.1 아님). Hermes에 연결하는 전체 절차는 섹션 9 참고
메신저 플랫폼(Mattermost 등) 봇 URL도 http://host.docker.internal:8065 사용 (localhost/127.0.0.1 아님). 자세한 트러블슈팅은 섹션 8 참고
동시 실행 금지 같은 ~/.hermes에 gateway 컨테이너 2개를 동시에 띄우지 말 것 (세션 손상)
메모리 브라우저 툴 사용 시 16GB RAM M1이 안정적

데이터 영속화 구조 (~/.hermes = 컨테이너의 /opt/data)

경로 내용
.env API 키 · 시크릿
config.yaml 설정
sessions/ 대화 이력
memories/ 영속 메모리
skills/ 설치된 확장
logs/ 런타임 로그

가장 짧은 실전 순서 (Compose 방식)

# 0) 확인
docker --version && docker compose version

# 1) 최초 설정 (API 키 입력)
mkdir -p ~/.hermes
docker run -it --rm -v ~/.hermes:/opt/data nousresearch/hermes-agent setup

# 3) compose 파일이 있는 폴더에서 실행
cd ~/projects/your-project/hermes
docker compose up -d

# 7) Docker 전용 정리 (한 번만)
rm -f ~/.local/bin/hermes
echo "alias hermes='docker exec -it hermes /opt/hermes/.venv/bin/hermes'" >> ~/.zshrc
source ~/.zshrc

# 사용
hermes

참고 링크