8.7 KiB
Executable File
Docker Hermes (linkease/hermes) — iStoreOS 部署排查
背景
192.168.123.125 = iStoreOS (OpenWrt) + Docker,跑 linkease/hermes:latest 容器。
连接凭据:root / xue.2538
架构识别
该容器不是纯 Gateway,而是 Hermes WebUI(带 Web 界面)。
| 组件 | 说明 |
|---|---|
| WebUI | http://host:8787 — 有密码保护的 Web 界面(/login 重定向) |
| Health | http://host:8787/health — 无需认证,返回 {"status":"ok",...} |
| API endpoints | /api/* — 需要认证(返回 {"error":"Authentication required"}) |
| Gateway | 容器内部 Hermes Gateway API(8787 端口也承载) |
容器环境变量(docker inspect hermes):
HERMES_HOME=/data/.hermes
HERMES_AGENT_DIR=/opt/hermes-agent
HERMES_WEBUI_HOST=0.0.0.0
HERMES_WEBUI_PORT=8787
HERMES_WEBUI_STATE_DIR=/data/.hermes/webui
HERMES_WEBUI_AGENT_DIR=/workspace
HERMES_WEBUI_DEFAULT_WORKSPACE=/workspace
配置文件挂载:
/mnt/usb4-1/hermes/data/ → 容器内 /data/.hermes
WebUI 密码重置(已验证)
当 WebUI session 过期或密码丢失时,清空 password_hash 即可:
# SSH 到 iStoreOS
ssh root@192.168.123.125
# 密码:xue.2538
# 清空密码 hash
sed -i 's/"password_hash": "[^"]*"/"password_hash": ""/' /mnt/usb4-1/hermes/data/webui/settings.json
# 验证
grep password_hash /mnt/usb4-1/hermes/data/webui/settings.json
# 期望输出:"password_hash": ""
# 重启容器使生效
docker restart hermes
清空后打开 http://192.168.123.125:8787,会提示设置新密码。
故障排查
查容器状态
docker ps -a --filter name=hermes
docker port hermes
查容器内进程
docker exec hermes ps aux
查看 WebUI settings
cat /mnt/usb4-1/hermes/data/webui/settings.json
查看 sessions
cat /mnt/usb4-1/hermes/data/webui/sessions/_index.json
查看 config.yaml(profile 里的 API 配置)
cat /mnt/usb4-1/hermes/data/profiles/nsa/config.yaml
常见问题
| 症状 | 排查 |
|---|---|
/health 返回 ok 但 /api/* 需要认证 |
正常,API 端点需要 auth |
WebUI 访问强转 /login |
密码过期或 session 失效,清 password_hash |
| API 调用无反应 | 确认 config.yaml 里有正确的 model.api_key + model.base_url |
| No messaging platforms | 正常——这个容器只跑 WebUI + API Worker,没有配置飞书/Telegram |
对外角色
192.168.123.125 的 Hermes 是 API Worker(不是对话 bot):
- 它的 config.yaml 只有
model.api_key+model.base_url(指向 192.168.123.11:3030) - 它不接飞书/微信/Telegram
- 它专门给其他 Hermes 实例提供模型调用
如果需要在这个容器上启用飞书,需要额外配置 ~/.hermes/.env 中的 FEISHU_APP_ID/FEISHU_APP_SECRET,并重启容器。
WebUI Chat 无反应(核心调试经验)
症状:WebUI 登录正常,发送消息后立即返回 stream_id,但轮询 /api/chat/stream?stream_id=xxx 返回 {"error":"stream not found"}。
根因定位
Step 1:发消息时抓日志
# 发消息前清日志
docker logs hermes --since 30s > /tmp/before.txt
# 在 WebUI 发消息
docker logs hermes 2>&1 | tail -30
Step 2:识别错误类型
# 类型 A:env 没传进去(最常见)
WARNING: resolve_runtime_provider failed: No inference provider configured.
RuntimeError: No LLM provider configured. Run `hermes model` to select a provider.
# 类型 B:token 无效(new-api 不认)
# curl 测试:curl -s -H "Authorization: Bearer sk-xxx" http://192.168.123.11:3030/v1/models
# 返回 {"error":{"message":"Invalid token"...}}
类型 A vs 类型 B 区分:
- 类型 A:日志里有
No inference provider configured或No LLM provider configured - 类型 B:日志里没有 provider 错误,但 API 调用返回 Invalid token
⚠️ env 变量不会从 .env 文件自动读取
常见误解:在 /mnt/usb4-1/hermes/data/.hermes/.env 或 /data/.hermes/.hermes/.env 创建文件,agent 就会读取。
实际行为:
- 容器内
~/.hermes/(即/root/.hermes/)是 tmpfs,重启后清空 - 持久化的
.env文件在/data/.hermes/挂载目录里,但 WebUI agent 不主动读取它 - 在运行中的容器里
docker exec ... cat > /root/.hermes/.env写入,重启容器后依然丢失
唯一可靠方式:重建容器时用 -e 传入环境变量
正确的 docker run 命令(带 env 传参)
docker stop hermes
docker rm hermes
docker run -d \
--name hermes \
--restart unless-stopped \
-p 8787:8787 \
-v /mnt/usb4-1/hermes/data:/data/.hermes \
-v /mnt/usb4-1/hermes/workspace:/workspace \
-e HOME=/data/.hermes \
-e OPENROUTER_API_KEY=sk-0ExNiLblJvIWBDpkS50fwOBw4MmqLyKdHJK5iQtlw9dOMWBP \
-e OPENROUTER_BASE_URL=http://192.168.123.11:3030/v1 \
-e MODEL_NAME=minimaxai/minimax-m2.7 \
-e HERMES_RUNTIME=openrouter \
linkease/hermes:latest
验证 env 是否生效:
docker exec hermes sh -c "env | grep OPENROUTER"
# 期望:
# OPENROUTER_API_KEY=sk-xxx
# OPENROUTER_BASE_URL=http://192.168.123.11:3030/v1
# HERMES_RUNTIME=openrouter
WebUI Chat API 假性成功特征
这是调试的核心教训:
POST /api/chat/start总是返回 200 +stream_id(HTTP 层先成功)- WebUI agent 在后台验证 provider 配置,验证失败时直接丢弃 stream,不报错给用户
- 轮询
/api/chat/stream?stream_id=xxx时 stream 已经不存在,返回{"error":"stream not found"} - 日志里唯一的蛛丝马迹:
/api/chat/start的ms值极小(13-20ms),因为 agent 同步验证后立即失败
关键诊断:stream 404 不代表 AI 没回复
即使 /api/chat/stream 返回 404,AI 可能已经处理并保存了回复。验证方法:
# 查 session API 的 token 计数
curl -s http://192.168.123.125:8787/api/sessions | python3 -c "
import sys,json
d=json.load(sys.stdin)
for s in d['sessions']:
print(f'session={s[\"session_id\"]} messages={s[\"message_count\"]} '
f'input_tokens={s[\"input_tokens\"]} output_tokens={s[\"output_tokens\"]}')"
# 有 input_tokens/output_tokens 且 > 0 = AI 真正调用了模型
直接读 session JSON(SSH 到 NAS):
cat /mnt/usb4-1/hermes/data/webui/sessions/<session_id>.json
# 看 messages 数组是否有 user/assistant 对话
从日志确认真正成功:
/api/chat/start响应ms > 1000= 真正在调用模型/api/chat/start响应ms < 50= 验证阶段就失败了(查 env)
容器内 API 连通性测试(简洁方法):
# SSH 到 NAS 后,用 wget 代替 curl(避免引号转义地狱)
ssh root@192.168.123.125 \
"docker exec hermes sh -c 'wget -qO- http://192.168.123.11:3030/v1/models \
--header=\"Authorization: Bearer sk-0ExNiLblJvIWBDpkS50fwOBw4MmqLyKdHJK5iQtlw9dOMWBP\" \
--timeout=5' 2>&1 | head -c 200"
注意:之前容器日志里的 Invalid token 错误是从容器内部 curl 测试时 Authorization header 格式化失败导致的,不是 token 真的无效。从外部服务器直接测 sk-0ExNiLblJvIWBDpkS50fwOBw4MmqLyKdHJK5iQtlw9dOMWBP 是 完全正确的 key,new-api 正常返回模型列表。
new-api Invalid token 问题的真正排查流程
当怀疑 token 无效时,不要在容器内测试(引号转义复杂容易出错)。从外部服务器测:
# 在本机(牧尘的服务器)执行
curl -s -H "Authorization: Bearer sk-0ExNiLblJvIWBDpkS50fwOBw4MmqLyKdHJK5iQtlw9dOMWBP" \
http://192.168.123.11:3030/v1/models | head -c 200
# 正常返回模型列表 JSON
# Invalid token 返回 {"error":{"message":"Invalid token"...}}
如果外部测正常但容器内失败 = 容器传参有问题(不是 token 问题)。
症状:curl 测试 http://192.168.123.11:3030/v1/models 返回 {"error":{"message":"Invalid token"...}}
含义:token 不在 192.168.123.11 这台机器的 new-api 数据库里。
可能原因:
- token 是旧的/已过期
- new-api 重启后数据库 token 丢失
- token 在不同 new-api 实例间复制时没有正确导入
解决:在 192.168.123.11 的 new-api 管理后台(端口 3000)重新设置同一个 token。
重启后 env 丢失的持久化方案
如果需要在重启后保持 env 配置,有两种方案:
方案 A(推荐):修改容器启动脚本(如果 NAS 支持) 在 NAS 的容器管理界面或 docker-compose.yml 里设置 env 变量。
方案 B:启动时自动恢复
# 通过 docker run 的 --env-file 或在启动脚本里执行
# 注意容器内 ~/.hermes/ 重启会清空,必须重建时传入