xiaowei-system/skills/devops/hermes-debug/references/docker-hermes-istoreos.md

8.7 KiB
Executable File
Raw Blame History

Docker Hermes (linkease/hermes) — iStoreOS 部署排查

背景

192.168.123.125 = iStoreOS (OpenWrt) + Dockerlinkease/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 API8787 端口也承载)

容器环境变量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.yamlprofile 里的 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识别错误类型

# 类型 Aenv 没传进去(最常见)
WARNING: resolve_runtime_provider failed: No inference provider configured.
RuntimeError: No LLM provider configured. Run `hermes model` to select a provider.

# 类型 Btoken 无效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 configuredNo LLM provider configured
  • 类型 B日志里没有 provider 错误,但 API 调用返回 Invalid token

⚠️ env 变量不会从 .env 文件自动读取

常见误解:在 /mnt/usb4-1/hermes/data/.hermes/.env/data/.hermes/.hermes/.env 创建文件agent 就会读取。

实际行为

  1. 容器内 ~/.hermes/(即 /root/.hermes/)是 tmpfs重启后清空
  2. 持久化的 .env 文件在 /data/.hermes/ 挂载目录里,但 WebUI agent 不主动读取它
  3. 在运行中的容器里 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 假性成功特征

这是调试的核心教训:

  1. POST /api/chat/start 总是返回 200 + stream_idHTTP 层先成功)
  2. WebUI agent 在后台验证 provider 配置,验证失败时直接丢弃 stream,不报错给用户
  3. 轮询 /api/chat/stream?stream_id=xxx 时 stream 已经不存在,返回 {"error":"stream not found"}
  4. 日志里唯一的蛛丝马迹:/api/chat/startms 值极小13-20ms因为 agent 同步验证后立即失败

关键诊断stream 404 不代表 AI 没回复

即使 /api/chat/stream 返回 404AI 可能已经处理并保存了回复。验证方法:

# 查 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 JSONSSH 到 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完全正确的 keynew-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 数据库里。

可能原因

  1. token 是旧的/已过期
  2. new-api 重启后数据库 token 丢失
  3. 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/ 重启会清空,必须重建时传入