Docker로 Hermes WebUI 배포하기 — 내가 겪은 8가지 오류와 해결 방법
요약
Hermes Agent를 위한 Hermes WebUI를 Docker Compose로 배포할 때 발생하는 주요 오류와 해결 방법을 다룹니다. 특히 UID/GID 불일치로 인한 권한 문제와 볼륨 마운트 시 발생하는 디렉토리 덮어쓰기 문제를 중점적으로 설명합니다.
핵심 포인트
- macOS와 Linux 간 UID/GID 불일치 해결법 제시
- .env 파일을 통한 사용자 권한 설정 방법 안내
- Docker 볼륨 마운트 시 호스트 디렉토리 우선순위 문제 설명
- Hermes WebUI의 셀프 호스팅 환경 구축 가이드
Docker로 Hermes WebUI 배포하기 — 내가 겪은 8가지 오류와 해결 방법
Hermes Agent를 위한 웹 UI가 필요했습니다. Docker Compose는 간단해 보였습니다. 8가지 오류를 거친 끝에, 저는 작동하는 배포 환경을 갖게 되었고 — 여러분이 겪지 않도록 제가 겪은 상처들을 모아 정리해 보려 합니다.
Hermes WebUI란 무엇인가?
Hermes WebUI는 Hermes Agent를 위한 셀프 호스팅(self-hosted) 웹 인터페이스입니다. Hermes Agent는 14만 개 이상의 GitHub 스타를 보유하고 있으며, OpenRouter를 통해 하루 2.9조 개의 토큰을 처리하는 오픈 소스 AI 에이전트 프레임워크입니다. 이는 Docker 컨테이너 내에서 에이전트와 채팅하고, 대화를 관리하며, 사용량을 모니터링할 수 있는 브라우저 기반의 대시보드입니다.
5분 만에 끝나는 정상 경로 (Happy Path)
오류를 살펴보기 전에, 원래 되어야 하는 과정은 다음과 같습니다:
git clone https://github.com/Jakeshadow/hermes-webui-docker-examples.git
cd hermes-webui-docker-examples/single-container
# API 키가 포함된 .env 파일을 생성합니다 (.env.example 참고)
...
http://localhost:3000을 열면 Hermes Agent와 채팅할 수 있습니다. 이는 Linux를 사용하는 대부분의 사람들에게 실제로 잘 작동합니다. 하지만 macOS, RHEL을 사용하거나 약간이라도 커스텀한 설정을 하고 있다면 — 마음 단단히 먹으세요.
오류 #1: UID/GID 불일치 (조용한 살인자)
증상: 컨테이너는 정상적으로 시작됩니다. 영구 데이터(persistent data)를 위해 볼륨(volume)을 마운트합니다. 하지만 컨테이너가 데이터에 쓸 수 없습니다 — 권한 거부(permission denied)가 발생하거나, 더 최악의 경우 컨테이너는 쓰지만 호스트(host)에서 파일을 볼 수 없습니다.
근본 원인: Docker 컨테이너는 UID 1000(표준 Linux 사용자)으로 실행됩니다. macOS 사용자는 UID 501로 실행됩니다. Linux 사용자는 UID가 1000일 수 있지만, GID는 무엇이든 될 수 있습니다. 컨테이너가 UID 1000으로 파일을 쓰면, 호스트 사용자는 이를 읽을 수 없습니다.
해결 방법 — .env 파일에 WANTED_UID와 WANTED_GID를 설정하세요:
# .env
WANTED_UID=501
WANTED_GID=20
macOS에서 UID/GID를 확인하려면:
id -u # 보통 501
id -g # 보통 20
Linux에서 확인하려면:
id -u # 보통 1000
id -g # 보통 1000
엔트리포인트 (entrypoint) 스크립트가 이 변수들을 가져와 컨테이너 내부에 일치하는 사용자를 생성합니다. 더 이상 권한 문제로 씨름할 필요가 없습니다.
오류 #2: 비어 있는 마운트된 디렉토리 (Empty Mounted Directories)
증상: ./data:/app/data와 같이 마운트했을 때, 컨테이너는 시작되지만 앱이 정상적으로 실행되는 것처럼 보임에도 불구하고 호스트의 ./data 디렉토리는 비어 있는 상태로 유지됩니다.
근본 원인: Docker 볼륨 마운트 (volume mounts)는 컨테이너 생성 시 한 방향으로 작동합니다. 만약 비어 있는 호스트 디렉토리를 비어 있지 않은 컨테이너 경로에 마운트하면, 비어 있는 호스트 디렉토리가 "승리"합니다. 즉, 호스트의 빈 디렉토리가 컨테이너 안에 있던 내용을 덮어쓰고 가려버립니다.
해결 방법: 호스트에 예상되는 디렉토리 구조를 먼저 생성하거나, 마운트 "이후"에 엔트리포인트 스크립트가 초기화를 처리하도록 합니다. Hermes WebUI의 경우, 동반 리포지토리(companion repo)에 이를 처리하는 scripts/init-data.sh가 포함되어 있습니다. 다음을 한 번 실행하세요:
./scripts/init-data.sh
docker compose up -d
Docker 볼륨 마운트 동작에 대한 심층적인 내용은 hermesdocker.com의 상세 페이지를 확인하세요.
오류 #3: docker_mount_cwd_to_workspace 권한 오류
증상: 3개 컨테이너로 구성된 프로덕션 설정을 사용 중인데, 워크스페이스 (workspace) 마운트 시 Permission denied: /workspace와 같은 오류가 발생합니다. 게이트웨이 (gateway) 컨테이너가 호스트에 분명히 존재하는 파일에 접근할 수 없는 상황입니다.
근본 원인: 이것은 이중 문제입니다. 첫째, 오류 #1에서 언급한 UID/GID 문제가 여기서도 적용됩니다. 둘째, 3개 컨테이너 설정에서 마운트가 컨테이너 경계를 넘을 때 Docker 소켓 프록시 (socket proxy)가 올바른 파일 권한을 상속받지 못합니다.
해결 방법: .env 파일이 웹 UI뿐만 아니라 "모든" 컨테이너에 대해 일치하는 UID/GID를 가지고 있는지 확인하세요. 3개 컨테이너 설정에서는 다음과 같습니다:
# webui, gateway, 그리고 hermes-agent 컨테이너 모두에 적용됨
WANTED_UID=1000
WANTED_GID=1000
그 다음 다시 빌드하세요:
docker compose down
docker compose up -d --build
오류 #4: RHEL/Fedora에서의 SELinux
증상 (Symptoms): 모든 설정이 올바르게 보이지만, 컨테이너가 마운트된 볼륨(mounted volumes)에 전혀 접근할 수 없습니다. 로그에는 avc: denied 메시지가 나타납니다.
근본 원인 (Root cause): 호스트 디렉터리의 SELinux 레이블(labels)이 컨테이너의 접근을 차단합니다.
해결 방법 — docker-compose.yml의 볼륨 마운트(volume mounts)에 :Z를 추가하세요:
volumes:
- ./data:/app/data:Z
- ./workspace:/workspace:Z
:Z 플래그는 Docker에게 컨테이너 접근을 위해 디렉터리의 레이블을 다시 지정(relabel)하도록 지시합니다. 여러 컨테이너가 동일한 볼륨을 공유하는 경우에는 :z를 사용하고, 하나의 컨테이너만 독점적으로 사용하는 경우에는 :Z를 사용하세요.
왜 Open WebUI 대신 이것을 선택했는가
결정을 내리기 전에 Hermes WebUI와 Open WebUI를 비교했습니다. 요약하자면 다음과 같습니다: Open WebUI는 기능이 풍부하지만 무겁습니다. 하나의 컨테이너에 RAG, 문서 파싱(document parsing), 웹 검색 엔진이 모두 포함되어 있습니다. 반면 Hermes WebUI는 집중되어 있습니다. 에이전트 채팅 인터페이스(agent chat interface)를 전문적으로 수행하며, 단일 Docker 명령부터 프로덕션급 멀티 컨테이너(multi-container) 설정까지 확장 가능한 세 가지 배포 모드를 제공합니다.
세 가지 모드가 중요합니다:
- 단일 컨테이너 (Single-container):
docker compose up -d한 번으로 실행되며, 테스트에 완벽합니다. - 이중 컨테이너 (Dual-container): 더 깔끔한 격리(isolation)를 위해 웹 UI를 게이트웨이(gateway)와 분리합니다.
- 삼중 컨테이너 (Three-container): 격리된 게이트웨이, 에이전트 런타임(agent runtime), 웹 UI를 갖춘 완전한 프로덕션 설정입니다.
전체 비교 분석 내용을 원하신다면, Hermes WebUI vs Open WebUI 전용 페이지를 참조하세요.
요약 (The Takeaway)
Docker는 배포를 매우 단순해 보이게 만들지만, 밤 11시에 권한 오류(permission error)를 마주하기 전까지만 그렇습니다. 제가 겪은 8가지 오류는 모두 세 가지 근본 원인으로 귀결됩니다: 호스트와 컨테이너 간의 사용자 ID(user ID) 불일치, 볼륨 마운트(volume mount)의 방향성, 그리고 엔터프라이즈 배포판에서의 SELinux입니다. 이 세 가지만 해결하면 문제없을 것입니다.
모든 작동 가능한 Docker Compose 파일(단일, 이중, 삼중 컨테이너 모드)은 GitHub 동반 리포지토리(companion repo)에 있습니다. 이를 클론(clone)하고 .env를 설정하여, 제가 이미 대신 겪은 디버깅 과정을 건너뛰세요.
즐거운 배포 되시길 바랍니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기