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
- 대시보드: http://localhost:9119 (localhost 바인딩이라 인증 불필요)
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을 지우고 hermes를 docker 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" 입니다.
원인
.env 의 MATTERMOST_URL 이 http://localhost:8065/ 로 되어 있으면,
Hermes 컨테이너 입장에서 localhost 는 컨테이너 자신(127.0.0.1) 을
가리킵니다. Mattermost 서버는 호스트 쪽(또는 별도 컨테이너)에 떠 있으므로
컨테이너 내부 루프백으로는 닿지 않습니다. 즉 설정 자체는 되어 있지만
주소가 틀린 상태입니다.
핵심: Docker 컨테이너 안의
localhost≠ 호스트. 호스트 쪽 서비스는host.docker.internal로 접근해야 합니다 (아래 M1 참고 사항 표 참고).
해결 절차
-
Mattermost 서버 실제 주소 확인 (컨테이너 안에서)
# 호스트 쪽 8065가 열려 있는지 docker exec -it hermes bash -c \ 'cat < /dev/null > /dev/tcp/host.docker.internal/8065 && echo OPEN || echo CLOSED' -
.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도 함께 들어 있어야 정상 동작합니다. -
게이트웨이 재시작 —
.env는 시작 시점에만 읽히므로 반영하려면 재시작 필요. s6(슈퍼바이저)가 자동으로 새 설정으로 띄웁니다.# 게이트웨이 pid 확인 후 kill (s6가 재시작) docker exec -it hermes bash -c 'kill $(pgrep -f "hermes gateway run")' # 또는 호스트에서 컨테이너 재시작 docker restart hermes -
연결 확인
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.yaml 의 model 섹션을 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