Ubuntu 서버에서 Mattermost의 채널마다 전담 Hermes 에이전트를 붙이는 전 과정을, 처음부터 차근차근 따라 할 수 있도록 정리한 가이드입니다. M1 Mac에서 검증·구축한 내용(Hermes × Mattermost — 채널별 다중 에이전트)을 Ubuntu 서버 환경으로 이식한 글입니다.
전제 환경 (기존 Ubuntu base 글 기준)
- 서버: Ubuntu, amd64, root 계정
- Mattermost: 이미 Docker로 구동 중, 도커 네트워크 이름
mattermost- Hermes 데이터:
/root/.hermes→ 컨테이너/opt/data- Hermes compose:
/root/hermes/docker-compose.yml, 컨테이너명hermes- Hermes:
mattermost네트워크에 합류 → Mattermost 접근 주소http://mattermost:8065/✅ 검증 완료 (2026-07-14, 서버 your-server): 이 가이드대로 default(@agents-bot 보존) + sales/finance/dev/qna 4개 채널 에이전트를 실제 구축·기동, 봇 응답까지 확인함. 아래 명령·주의사항은 그 실전에서 정리된 것.
전체 그림
Ubuntu 서버
└─ Docker
├─ 네트워크: mattermost
├─ 컨테이너: docker-mattermost-1, docker-postgres-1, nginx_mattermost
└─ 컨테이너: hermes (s6-svscan PID1 — 프로필별 게이트웨이 감독)
├─ 프로필 default (@agents-bot) ← base 글에서 만든 기존 봇 (보존)
├─ 프로필 sales (@sales-bot) → 영업 채널
├─ 프로필 finance (@finance-bot) → 재무 채널
├─ 프로필 dev (@dev-bot) → 개발 채널
└─ 프로필 qna (@qna-bot) → 고객응대 채널
핵심 개념: 컨테이너를 여러 개 띄우는 게 아니라, 하나의 hermes 컨테이너 안에서 "프로필"을 여러 개 만들고, 각 프로필의 게이트웨이를 s6가 감독합니다. 프로필마다 자체 .env(봇 토큰)·성격·메모리를 격리 보관합니다.
Phase 0. 전제 확인 — base 설치가 끝났는가
이 가이드는 단일 봇(default 프로필)이 이미 응답하는 상태에서 시작합니다. 아직이라면 먼저 Hermes Agent — Ubuntu 서버 Docker 설치 + Mattermost 연동를 완료하세요. 완료 기준:
# hermes 컨테이너 실행 중
docker ps --filter name=hermes # Up ... 이면 OK
# Mattermost 연결됨
docker exec hermes cat /opt/data/gateway_state.json \
| python3 -c 'import json,sys;print(json.load(sys.stdin)["platforms"]["mattermost"]["state"])'
# => connected 이면 OK
그리고 편의 alias(호스트에서 hermes 한 단어로 실행):
grep -q "alias hermes=" ~/.bashrc || \
echo "alias hermes='docker exec -it hermes /opt/hermes/.venv/bin/hermes'" >> ~/.bashrc
source ~/.bashrc
⚠️ default 프로필은 절대 삭제·변경하지 마세요. 새 채널은 항상 프로필 "추가"로만 진행합니다.
Phase 1. 왜 프로필별 에이전트인가 (개념)
- 문맥 분리: 채널마다 전담 에이전트 → 영업/개발/재무 문맥이 안 섞임 → 답 품질↑ (64k 컨텍스트 한계 우회).
- 무료/작은 모델에 유리: 각자 다룰 범위가 좁아 RAG 파이프라인 없이도 잘 동작.
- 역할·권한 분리: 프로필마다 성격(
SOUL.md)·모델·봇을 다르게. - 한 컨테이너로 관리: 컨테이너 N개보다 리소스·운영이 단순. 재시작 시 전부 자동 복구.
Hermes 이미지는 s6-overlay(컨테이너 init/프로세스 감독자) 위에 지어져, 한 컨테이너 안 다중 게이트웨이를 원래 지원합니다. 프로필별 게이트웨이가 런타임에 s6 서비스 gateway-<name>으로 등록됩니다.
Phase 2. Ubuntu 환경의 차이 (M1 Mac 대비)
| 항목 | M1 Mac | Ubuntu 서버 (이 글) |
|---|---|---|
| 데이터 경로 | ~/.hermes |
/root/.hermes |
| 프로필 경로(호스트) | ~/.hermes/profiles/<name>/ |
/root/.hermes/profiles/<name>/ |
| 셸/alias 파일 | ~/.zshrc |
~/.bashrc |
| Mattermost 주소 | host.docker.internal:8065 |
http://mattermost:8065/ (도커 네트워크 공유) |
| 아키텍처 | arm64 | amd64 (--platform 불필요) |
프로필을
--clone으로 만들면 default의.env를 복제하므로MATTERMOST_URL=http://mattermost:8065/가 자동으로 상속됩니다. 새 프로필에선 토큰과 채널 ID만 바꾸면 됩니다.
Phase 3. 채널마다 전용 봇 계정 만들기 (Mattermost)
채널 1개 : 봇 1개 : 프로필 1개 원칙. 같은 토큰을 재사용하면 한 메시지에 봇이 중복 응답하므로, 채널마다 별도 봇을 만듭니다.
각 채널(영업/재무/개발/고객응대)에 대해 반복:
-
관리자 로그인 →
System Console → Integrations → Bot Accounts→ Enable Bot Account Creation = true -
메인 화면 → 좌상단 메뉴 →
Integrations → Bot Accounts → Add Bot Account -
폼 입력:
항목 값 예시 비고 Username sales-bot/finance-bot/dev-bot/qna-bot봇 핸들 Display Name 영업봇등선택 Role Member대화 에이전트엔 충분 post:all ✅ Enabled DM + 채널 응답 가능 -
Create Bot Account → 다음 화면의
Token:즉시 복사 (이 화면에서만 보임).
결과적으로 봇 4개와 토큰 4개를 확보하게 됩니다.
Phase 4. 각 채널의 ID 확보
MATTERMOST_HOME_CHANNEL에는 채널 ID(26자)를 넣습니다. handle(URL 슬러그)·표시이름 아님.
방법 A — 브라우저: 채널명 클릭 → View Info → Channel ID 복사.
방법 B — 터미널 (mmctl, 컨테이너 내부 무인증):
docker exec docker-mattermost-1 mmctl --local team list
docker exec docker-mattermost-1 mmctl --local channel list <팀이름> --json \
| python3 -c 'import json,sys;[print(c["display_name"], c["id"]) for c in json.load(sys.stdin)]'
확보한 값을 정리해둡니다 (예):
sales 채널ID=b9ee… 봇토큰=…
finance 채널ID=q6re… 봇토큰=…
dev 채널ID=b15a… 봇토큰=…
qna 채널ID=f5xr… 봇토큰=…
Phase 5. 프로필 생성 + 설정
⚠️ Ubuntu 서버 필수 주의 — root 소유권 함정. Ubuntu에서
docker exec hermes ...는 root로 실행됩니다. 그대로profile create하면 프로필 파일이 root 소유로 생기고, 실제 게이트웨이는 s6가hermes사용자로 띄우므로 hermes가 로그·상태 파일을 못 써서 게이트웨이가 뜨자마자 조용히 죽습니다(gateway list에 not running, 로그 파일도 안 생김). Mac Docker Desktop에선 안 드러나는 리눅스 서버 특유의 문제.해법 2가지 (택1):
- (권장) 처음부터 hermes 사용자로 실행: 모든
docker exec hermes …를docker exec -u hermes hermes …로.- (사후 교정) 이미 root로 만들었으면 chown:
docker exec hermes chown -R hermes:hermes /opt/data/profiles /opt/data/logs
5-1. 프로필 생성 (default 복제)
# 권장: -u hermes 로 실행 (root 소유권 문제 원천 차단)
docker exec -u hermes hermes /opt/hermes/.venv/bin/hermes profile create sales \
--clone --description "영업 채널 담당 에이전트. 영업/CRM 문의 응대."
--clone= default의config.yaml·.env·SOUL.md·skills복제 →MATTERMOST_URL등 공통값 자동 상속.- 생성 위치:
/root/.hermes/profiles/sales/(호스트에서 직접 편집 가능).
5-2. 전용 봇 토큰 + 채널 ID 주입
호스트에서 그 프로필의 .env를 직접 편집:
nano /root/.hermes/profiles/sales/.env
아래 두 줄만 이 프로필 전용 값으로 교체 (나머지 URL/ALLOWED_USERS는 그대로 둠):
MATTERMOST_TOKEN=<sales 봇 토큰>
MATTERMOST_HOME_CHANNEL=<sales 채널 ID>
MATTERMOST_ALLOWED_USERS는 default와 동일하게 두면 같은 사용자 화이트리스트를 씁니다. 채널별로 다르게 하려면 여기서 조정.
5-3. finance / dev / qna 반복
같은 방식으로 나머지 3개 프로필도 생성·설정 (권장: -u hermes):
docker exec -u hermes hermes /opt/hermes/.venv/bin/hermes profile create finance --clone --description "재무 채널 담당."
docker exec -u hermes hermes /opt/hermes/.venv/bin/hermes profile create dev --clone --description "개발 채널 담당."
docker exec -u hermes hermes /opt/hermes/.venv/bin/hermes profile create qna --clone --description "고객응대 채널 담당."
# 각각 /root/.hermes/profiles/<name>/.env 에서 TOKEN + HOME_CHANNEL 교체
5-4. (root로 만들었다면) 소유권 교정 — 기동 전 필수
만약 5-1~5-3에서 -u hermes 없이 root로 프로필을 만들었다면, 기동 전에 반드시 소유권을 hermes로 되돌립니다. 안 하면 게이트웨이가 조용히 죽습니다(위 경고 참고):
docker exec hermes chown -R hermes:hermes /opt/data/profiles /opt/data/logs
실제 Ubuntu 서버(your-server) 구축 시 이 단계가 없어서 4개 게이트웨이가 전부 not running이었고, chown 후 정상 기동됨. root로 만들었으면 이 줄을 꼭 실행.
Phase 6. 게이트웨이 기동
프로필마다 게이트웨이를 s6 감독 서비스로 띄웁니다. docker exec -d(detached) 로 실행하세요 — 프롬프트가 바로 돌아옵니다.
docker exec -d hermes /opt/hermes/.venv/bin/hermes -p sales gateway run --replace
docker exec -d hermes /opt/hermes/.venv/bin/hermes -p finance gateway run --replace
docker exec -d hermes /opt/hermes/.venv/bin/hermes -p dev gateway run --replace
docker exec -d hermes /opt/hermes/.venv/bin/hermes -p qna gateway run --replace
-d없이 실행하면→ gateway is now running under s6 supervision메시지 출력 후 프롬프트가 안 돌아오고 매달릴 수 있습니다(터미널이 앞단 프로세스에 붙어 대기). 이때 게이트웨이는 이미 s6로 떠 있으므로,Ctrl+C로 빠져나와도 게이트웨이는 안 죽습니다(s6가 감독·유지). 새 창에서gateway list로 확인 가능.-d를 붙이면 이 매달림이 없어 깔끔합니다. 게이트웨이는 어차피 s6로 넘어가 동일하게 동작합니다.
기동 확인:
docker exec hermes /opt/hermes/.venv/bin/hermes gateway list
기대 결과 (5개 모두 running):
Gateways:
✓ default (current) — PID …
✓ sales — PID …
✓ finance — PID …
✓ dev — PID …
✓ qna — PID …
각 프로필이 올바른 봇으로 붙었는지:
for N in sales finance dev qna; do
echo -n "$N → "; docker exec hermes sh -c \
"grep -E 'authenticated as' /opt/data/profiles/$N/logs/gateway.log | tail -1"
done
Phase 7. 봇을 채널에 초대 + 검증
게이트웨이가 붙어도, 봇이 채널 멤버가 아니면 메시지를 못 받습니다.
각 봇을 담당 채널에 초대:
- Mattermost에서 해당 채널 → 채널명 클릭 → Add Members → 봇 검색(
@sales-bot등) 추가.
초대 후 검증 (채널에서 봇 멘션 → 실시간 로그 관찰):
docker exec hermes sh -c 'tail -f /opt/data/profiles/sales/logs/gateway.log' \
| grep --line-buffered -iE "inbound message|response ready|Sending response"
채널에서 @sales-bot 안녕? 보내면 아래 흐름이 찍히면 성공:
inbound message: … chat=<채널ID> msg='안녕?'
response ready: … response=… chars
[Mattermost] Sending response … to <채널ID>
Channel directory built: 0 target(s)로그는 능동 추적 대상 수일 뿐, 멘션 반응과 무관합니다. 봇이 채널 멤버이면 응답합니다.
Phase 8. 재시작 생존성 (자동 복구)
프로필 게이트웨이를 running 상태로 두면, 컨테이너 재시작·크래시 후 부팅 리컨실러(cont-init.d/02-reconcile-profiles)가 자동으로 다시 띄웁니다 (각 프로필의 gateway_state.json을 읽어 판단).
확인:
cd /root/hermes && docker compose restart hermes
# 잠시 후
docker exec hermes /opt/hermes/.venv/bin/hermes gateway list # 5개 다시 running 이면 OK
즉 별도 systemd 설정 없이도, 한 번 켜둔 채널 에이전트들은 서버/컨테이너 재시작 후 전부 자동 복구됩니다.
Phase 9. 운영 노트
9-1. 메모리
- Hermes 컨테이너: 게이트웨이 1개 ~270MB → 5개 ~720MB (1개당 약 +110MB, 클라우드 모델 기준).
- compose의
mem_limit: 4g가 상한. 채널을 많이 늘리면 상향 고려. 서버 여유 메모리 확인:free -h docker stats --no-stream --format 'table {{.Name}}\t{{.MemUsage}}'
9-2. 모델
- 프로필별로 다른/더 빠른 모델 지정 가능:
docker exec hermes /opt/hermes/.venv/bin/hermes -p sales config set model.default <모델> - 무료 모델은 응답이 느릴 수 있음(수십 초). 트래픽 몰리는 채널은 모델 교체 검토.
9-3. 성격 부여
- 각 프로필의
SOUL.md를 채널 성격에 맞게 수정:nano /root/.hermes/profiles/sales/.env # 참고: 성격은 SOUL.md nano /root/.hermes/profiles/sales/SOUL.md # 영업봇답게 # 반영하려면 해당 프로필 게이트웨이 재시작 (아래)
9-4. 프로필 게이트웨이 재시작 / 관리
# 프로필 게이트웨이만 재시작: 해당 python PID kill → s6 자동 부활
docker exec hermes sh -c 'kill $(pgrep -f "hermes -p sales gateway run")'
# 상태 / 목록
docker exec hermes /opt/hermes/.venv/bin/hermes gateway list
docker exec hermes /opt/hermes/.venv/bin/hermes profile list
# 프로필 삭제 (s6 슬롯 자동 정리) — default엔 절대 쓰지 말 것
docker exec hermes /opt/hermes/.venv/bin/hermes profile delete <name> -y
9-5. 로그 위치
- 프로필별:
/root/.hermes/profiles/<name>/logs/gateway.log - default:
/root/.hermes/logs/ - s6 캡처:
/root/.hermes/logs/gateways/<name>/current
요약 체크리스트
- Phase 0: base 설치 완료 확인 (
gateway_state.json= connected),hermesalias(~/.bashrc) - Phase 3: 채널마다 봇 계정 생성 (
sales-bot등, post:all), 토큰 4개 복사 - Phase 4: 채널 ID 4개 확보 (View Info 또는
mmctl) - Phase 5:
-u hermes로profile create <name> --clone× 4, 각.env에 TOKEN + HOME_CHANNEL 주입 - Phase 5-4: (root로 만들었다면)
chown -R hermes:hermes /opt/data/profiles /opt/data/logs - Phase 6:
docker exec -d로-p <name> gateway run --replace× 4 →gateway list5개 running - Phase 7: 각 봇을 담당 채널에 Add Members → 멘션 테스트로 응답 확인
- Phase 8:
docker compose restart hermes후 5개 자동 복구 확인 - Phase 9: (선택) 모델 교체,
SOUL.md성격, 메모리 점검
자주 겪는 문제
| 증상 | 원인 | 해결 |
|---|---|---|
| 봇이 채널에서 무응답 | 봇이 채널 멤버 아님 | Add Members로 초대 |
| 한 메시지에 여러 봇 응답 | 여러 프로필이 같은 토큰 | 프로필마다 별도 봇/토큰 |
gateway run이 멈춤(hang) |
-d 없이 앞단 실행 |
docker exec -d … 로 기동 (Ctrl+C해도 s6가 유지) |
| 프로필 게이트웨이가 뜨자마자 not running, 로그 파일도 없음 | root로 만든 프로필 파일을 hermes가 못 씀 | docker exec hermes chown -R hermes:hermes /opt/data/profiles /opt/data/logs 후 재기동. 이후엔 -u hermes로 생성 |
Refusing to run … as root |
--no-supervise를 root로 실행 |
--no-supervise 빼고 감독 경로로 실행(s6가 hermes로 띄움) |
프로필이 mattermost 못 찾음 |
URL이 host.docker.internal | .env를 http://mattermost:8065/ 로 |
| 재시작 후 프로필 게이트웨이 안 뜸 | 기동 전 gateway_state=stopped | 한 번 gateway run으로 running 만든 뒤 재시작 |
전 채널 봇이 동시에 Provider authentication failed |
root로 CLI를 돌려 auth.json이 root 소유가 됨 → 게이트웨이가 못 읽고 빈 스토어로 기동 |
chown -R hermes:hermes /opt/data 후 재기동. 상세: ../03-troubleshooting/2026-07-21-01-… |
전 채널 봇이 동시에 model provider failed after retries |
사용 중인 무료 모델이 provider에서 사라짐(404) | 호출 가능한 모델로 config set model.default (프로필마다 실행) 후 재기동 |
참고
- Hermes Agent — Ubuntu 서버 Docker 설치 + Mattermost 연동 — base(단일 봇) Ubuntu 설치
- Hermes × Mattermost — 채널별 다중 에이전트 — M1 Mac 기준 다중 에이전트 구축 기록(개념·검증 상세)
- 봇 전체 무응답 — 무료 모델 소멸(404) + auth.json 권한 사고(401) — 봇 전체 무응답 장애 기록.
root 소유권 함정이
auth.json(로그인 세션)까지 미친 사례 + 무료 모델 소멸(404) 대응 - Hermes Agent — Docker (공식)