注:服务器部署Hermes超详细指南,由于过于详细,所以分为三部分;结尾有踩坑点说明。

Hermes Agent 云服务器部署(一):基础环境、Docker 镜像、目录挂载与模型配置
Hermes Agent 云服务器部署(二):微信 Weixin Gateway 与 Docker Compose 常驻运行
Hermes Agent 云服务器部署(三):面试题库、Cron 定时任务与故障排查

1. 安装基础工具

最开始在服务器上执行:

sudo apt update && sudo apt install -y git docker.io docker-compose-v2

命令解释

sudo apt update

更新 Ubuntu 软件包索引。

它不会升级软件本身,只是刷新系统能看到的软件包版本列表。后续安装软件前通常都要先执行它。

sudo apt install -y git docker.io docker-compose-v2

安装三个工具:

工具 作用
git 用于拉取 GitHub 仓库源码
docker.io Ubuntu 软件源里的 Docker 引擎
docker-compose-v2 Docker Compose v2,用于用 compose.yml 管理容器

其中 -y 表示自动回答 yes,避免安装过程中反复确认。


2. 将当前用户加入 docker 组

执行:

sudo usermod -aG docker $USER
newgrp docker

命令解释

sudo usermod -aG docker $USER

把当前用户加入 docker 用户组。

默认情况下,普通用户执行 Docker 命令可能需要加 sudo,例如:

sudo docker ps

加入 docker 组之后,当前用户可以直接执行:

docker ps

参数说明:

参数 含义
usermod 修改用户信息
-aG docker 追加加入 docker 组
$USER 当前登录用户

注意这里的 -a 很重要,表示“追加”。如果没有 -a,可能会覆盖用户原来的组。

newgrp docker

让当前 shell 立即应用新的用户组。

正常情况下,加入用户组后需要退出 SSH 再重新登录才生效。newgrp docker 可以让当前会话立即使用新组权限。


3. 拉取 Hermes Agent 源码

执行:

git clone https://gitclone.com/github.com/NousResearch/hermes-agent.git
cd hermes-agent

命令解释

git clone https://gitclone.com/github.com/NousResearch/hermes-agent.git

从 GitHub 镜像站拉取 Hermes Agent 源码。

这里使用的是:

gitclone.com/github.com/NousResearch/hermes-agent.git

而不是直接使用:

github.com/NousResearch/hermes-agent.git

原因是国内云服务器直接访问 GitHub 可能较慢或失败,使用镜像站可以提高成功率。

cd hermes-agent

进入刚刚 clone 下来的源码目录。


4. 是否需要删除源码目录?

当时已经拉取了源码目录:

/root/hermes-agent

但后续我们采用的是官方 Docker 镜像:

nousresearch/hermes-agent:latest

因此源码目录不是必须的。

不过在 Docker 镜像成功拉取之前,不建议删除源码,因为如果 Docker Hub 一直拉不下来,还可以用源码本地构建作为备选方案。

结论

镜像没拉成功前:

先不要删除 /root/hermes-agent

镜像成功拉取、setup 成功、微信网关跑通后,可以删除:

cd /root
rm -rf /root/hermes-agent

命令解释

cd /root

切换到 root 用户主目录。

rm -rf /root/hermes-agent

删除源码目录。

参数说明:

参数 含义
rm 删除文件或目录
-r 递归删除目录
-f 强制删除,不逐个确认

注意:

rm -rf

是危险命令,必须确认路径正确后再执行。

删除 /root/hermes-agent 不会删除 Hermes 的配置、API Key、微信登录状态、cron 任务。真正要保留的是:

/root/.hermes

5. 创建 Hermes 数据目录

执行:

mkdir -p ~/.hermes
chmod 700 ~/.hermes

后来因为当前用户是 root,所以实际路径是:

/root/.hermes

命令解释

mkdir -p ~/.hermes

创建 Hermes 的数据目录。

其中:

~

表示当前用户的 home 目录。

如果当前用户是 root:

~ = /root

所以:

~/.hermes

等价于:

/root/.hermes

参数:

参数 含义
mkdir 创建目录
-p 如果父目录不存在就一起创建;如果目录已存在也不报错
chmod 700 ~/.hermes

设置目录权限为 700

权限含义:

数字 含义
7 所有者可读、可写、可执行
0 同组用户无权限
0 其他用户无权限

也就是说,只有 root 用户自己能访问这个目录。

这么做的原因是 .hermes 目录后续会保存:

  • API Key
  • Hermes 配置文件
  • 微信登录状态
  • 会话数据
  • cron 定时任务
  • skills
  • 面试题文件

所以权限应该收紧。


6. 拉取 Hermes Agent Docker 镜像

执行:

docker pull nousresearch/hermes-agent:latest

命令解释

docker pull

从镜像仓库下载 Docker 镜像。

nousresearch/hermes-agent:latest

表示下载 NousResearch 发布的 Hermes Agent 最新镜像。

镜像名拆解:

部分 含义
nousresearch Docker Hub 组织名
hermes-agent 镜像名
latest 标签,表示最新版本

7. Docker Hub 拉取超时问题

第一次拉取时遇到类似错误:

failed to resolve reference "docker.io/nousresearch/hermes-agent:latest"
failed to do request
dial tcp ...:443: i/o timeout

这个错误表示服务器访问 Docker Hub 超时。

不是镜像名写错,也不是 Hermes 项目有问题,而是网络连不上 Docker Hub。


8. 配置腾讯云 Docker 镜像加速

因为服务器看起来是腾讯云机器,所以配置腾讯云内网 Docker 镜像源:

mkdir -p /etc/docker

cp /etc/docker/daemon.json /etc/docker/daemon.json.bak.$(date +%Y%m%d%H%M%S) 2>/dev/null || true

cat > /etc/docker/daemon.json <<'EOF'
{
  "registry-mirrors": [
    "https://mirror.ccs.tencentyun.com"
  ],
  "dns": [
    "119.29.29.29",
    "223.5.5.5",
    "8.8.8.8"
  ]
}
EOF

systemctl daemon-reload
systemctl restart docker

命令解释

mkdir -p /etc/docker

创建 Docker 配置目录。

Docker daemon 的配置文件通常在:

/etc/docker/daemon.json

如果 /etc/docker 不存在,这条命令会创建它。


cp /etc/docker/daemon.json /etc/docker/daemon.json.bak.$(date +%Y%m%d%H%M%S) 2>/dev/null || true

备份原有 Docker 配置文件。

拆解说明:

cp /etc/docker/daemon.json ...

复制原配置文件。

/etc/docker/daemon.json.bak.$(date +%Y%m%d%H%M%S)

生成带时间戳的备份文件名。

例如:

daemon.json.bak.20260508143025
$(date +%Y%m%d%H%M%S)

执行 date 命令并插入结果,格式是:

年月日时分秒
2>/dev/null

把错误输出丢弃。

如果原来的 daemon.json 不存在,cp 会报错。这里把报错隐藏掉。

|| true

即使前面的 cp 失败,也让整条命令返回成功。

这样做是为了避免“没有旧配置文件”时中断流程。


cat > /etc/docker/daemon.json <<'EOF'
...
EOF

把中间的 JSON 内容写入 /etc/docker/daemon.json

这是 shell heredoc 写法。

写入内容为:

{
  "registry-mirrors": [
    "https://mirror.ccs.tencentyun.com"
  ],
  "dns": [
    "119.29.29.29",
    "223.5.5.5",
    "8.8.8.8"
  ]
}

字段解释:

字段 作用
registry-mirrors Docker 镜像加速地址
dns Docker daemon 使用的 DNS 服务器

DNS 说明:

DNS 说明
119.29.29.29 腾讯 DNS
223.5.5.5 阿里 DNS
8.8.8.8 Google DNS

systemctl daemon-reload

让 systemd 重新加载服务配置。

虽然这里只改了 Docker 的 daemon.json,但重启服务前执行一下没有坏处。

systemctl restart docker

重启 Docker 服务,让新的镜像源配置生效。


9. 检查 Docker 镜像源是否生效

执行:

docker info | sed -n '/Registry Mirrors/,+10p'

命令解释

docker info

查看 Docker daemon 的详细信息。

sed -n '/Registry Mirrors/,+10p'

只打印包含 Registry Mirrors 的那一行,以及后面的 10 行。

如果配置成功,应该能看到:

Registry Mirrors:
 https://mirror.ccs.tencentyun.com/

10. 再次拉取镜像

配置镜像源后,再执行:

docker pull nousresearch/hermes-agent:latest

中间曾经出现过:

error from registry: unknown error

但再次重试后成功:

Digest: sha256:634f9b15c02d4693f9c48c6763152efc0af75670de1b77d22c54e4333d730bab
Status: Downloaded newer image for nousresearch/hermes-agent:latest
docker.io/nousresearch/hermes-agent:latest

说明

Docker 拉镜像时会分层下载。

即使最后一步失败,前面已经下载完成的 layer 通常会保留。再次执行 docker pull 时会复用已下载的层,不一定从头开始。

所以遇到这种中途失败,不要急着执行:

docker system prune

因为这会清理缓存,可能导致重新下载。


11. 检查镜像是否完整可用

执行:

docker image inspect nousresearch/hermes-agent:latest >/dev/null 2>&1 && echo "IMAGE_OK" || echo "IMAGE_NOT_READY"

命令解释

docker image inspect nousresearch/hermes-agent:latest

查看本地是否存在这个镜像,以及镜像元数据是否完整。

>/dev/null

把标准输出丢弃。

2>&1

把错误输出也重定向到标准输出,也就是一起丢弃。

&& echo "IMAGE_OK"

如果前面的 docker image inspect 成功,就输出:

IMAGE_OK
|| echo "IMAGE_NOT_READY"

如果前面的命令失败,就输出:

IMAGE_NOT_READY

最终用来判断镜像是否已经完整可用。


12. 运行 Hermes 初始化向导

镜像成功后,执行:

docker run -it --rm \
  -v /root/.hermes:/opt/data \
  -e TZ=Asia/Shanghai \
  nousresearch/hermes-agent setup

命令解释

docker run

创建并运行一个新的容器。

-it

表示交互式运行。

拆开看:

参数 含义
-i 保持标准输入打开
-t 分配一个伪终端

因为 setup 是交互式向导,所以必须加 -it

--rm

容器退出后自动删除容器本身。

注意:这不会删除挂载到宿主机的 /root/.hermes 数据。

-v /root/.hermes:/opt/data

挂载目录。

这是非常关键的一行。

含义是:

宿主机 /root/.hermes  映射到  容器内 /opt/data

所以 Hermes 在容器里看到的:

/opt/data

实际上就是服务器上的:

/root/.hermes

后续所有配置、API Key、cron、微信登录状态等都会存放在这里。

-e TZ=Asia/Shanghai

设置容器环境变量 TZ 为上海时区。

这会影响日志时间、cron 定时任务时间等。

nousresearch/hermes-agent

使用 Hermes Agent 镜像。

setup

传给 Hermes 镜像的命令,表示进入初始化向导。


13. Quick setup 与 Full setup

初始化时出现:

How would you like to set up Hermes?

 → Quick setup — provider, model & messaging (recommended)
   Full setup — configure everything

选择:

Quick setup

原因

当前目标是尽快跑通:

  1. 模型调用
  2. 微信聊天
  3. 后续 cron 定时任务

不需要一开始配置所有高级选项。

Quick setup 会引导配置:

  • provider
  • model
  • messaging platform

对于首次部署更合适。


14. 选择模型 Provider

Hermes 显示了很多 provider,例如:

1. Nous Portal
2. OpenRouter
...
6. Xiaomi MiMo
...
15. DeepSeek
...

如果使用小米模型,选择:

6

也就是:

Xiaomi MiMo

如果使用 DeepSeek,选择:

15

也就是:

DeepSeek

15. 小米 MiMo 模型选择问题

最初考虑的模型包括:

mimo-v2.5-pro
mimo-v2-pro
mimo-v2.5
mimo-v2-omni
mimo-v2-flash

当时建议轻量任务优先使用:

mimo-v2-flash

原因是当前场景主要是:

  • 微信文字聊天
  • 定时提醒
  • 抽取面试题
  • 简单批改

理论上不需要最强模型。

但是实际运行后出现错误:

Provider: xiaomi
Model: mimo-v2-flash
Endpoint: https://token-plan-cn.xiaomimimo.com/v1
Error: HTTP 400: Not supported model mimo-v2-flash

错误解释

这说明当前 API Key 对应的 endpoint:

https://token-plan-cn.xiaomimimo.com/v1

不支持:

mimo-v2-flash

不是 Hermes 坏了,也不是 API Key 一定错了,而是模型名和当前 API endpoint 或套餐不匹配。

处理方式

将模型从:

mimo-v2-flash

改为更稳妥的:

mimo-v2-pro

或者如果当前小米 Token Plan 支持:

mimo-v2.5-pro

也可以使用它。

推荐顺序

对于当前微信 Agent 场景,建议按这个顺序尝试:

mimo-v2-pro
mimo-v2.5-pro
mimo-v2.5
mimo-v2-omni

如果 mimo-v2-flash 被 endpoint 明确拒绝,就不要继续使用它。


16. 进入终端聊天界面测试模型

setup 后进入终端聊天界面:

Welcome to Hermes Agent! Type your message or /help for commands.

输入:

你好

如果模型配置错误,会出现类似:

HTTP 400: Not supported model mimo-v2-flash

如果模型配置正确,会正常回复中文。

终端聊天界面的意义

终端聊天只验证:

Hermes Agent 能不能调用模型

它不代表微信网关已经正常运行。

后续微信能不能回复,还要单独配置和启动 gateway。


17. 退出终端聊天界面

在终端聊天界面中,可以输入:

/exit

或者按:

Ctrl + C

退出聊天。

注意

退出终端聊天不会影响 Docker 镜像和 /root/.hermes 配置。

但是如果你运行的是临时前台 gateway,按 Ctrl+C 会停止 gateway。


18. /root/.hermes 和 /opt/data 的关系

后续多次遇到疑问:

为什么在服务器上创建 /root/.hermes/interview,
却让 Hermes 读取 /opt/data/interview?

原因是 Docker volume 映射:

-v /root/.hermes:/opt/data

或者在 compose 文件中:

volumes:
  - /root/.hermes:/opt/data

含义是:

服务器宿主机路径:/root/.hermes
容器内部路径:    /opt/data

所以:

宿主机路径 容器内路径
/root/.hermes /opt/data
/root/.hermes/interview /opt/data/interview
/root/.hermes/interview/questions.md /opt/data/interview/questions.md

重要结论

在 SSH 里编辑文件,用:

/root/.hermes/...

在 Hermes 提示词或 cron 任务里,让 Agent 读取:

/opt/data/...

19. 容器的 /opt 不是服务器的 /root

曾经有一个疑问:

容器的 /opt 目录就是我的 /root 目录吗?

答案是:

不是

只有明确挂载的这一段路径有关联:

/root/.hermes  <=>  /opt/data

容器里的:

/opt

不是服务器的:

/root

容器里的:

/opt/data

才是服务器的:

/root/.hermes

其他容器目录和宿主机没有直接关系。


20. 检查实际挂载路径

可以用下面命令查看容器实际挂载:

docker inspect hermes --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

命令解释

docker inspect hermes

查看名为 hermes 的容器详细信息。

--format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

只输出挂载信息。

正常应该看到:

/root/.hermes -> /opt/data

这表示宿主机 /root/.hermes 已经挂载到容器内 /opt/data


21. 在服务器上进入 Hermes 数据目录

推荐直接在宿主机进入:

cd /root/.hermes
ls -la

命令解释

cd /root/.hermes

进入 Hermes 数据目录。

ls -la

显示目录内容。

参数说明:

参数 含义
-l 以长格式显示
-a 显示隐藏文件

因为 .hermes 本身是隐藏目录,所以查看 /root 时要用:

ls -la /root

否则普通:

ls /root

可能看不到 .hermes


22. 进入容器查看 /opt/data

如果需要进入容器查看:

docker exec -it hermes sh

进入后:

cd /opt/data
ls -la

退出容器:

exit

命令解释

docker exec -it hermes sh

在正在运行的 hermes 容器中启动一个 shell。

部分 含义
docker exec 在已运行容器里执行命令
-it 交互式终端
hermes 容器名称
sh 启动 shell

注意:容器里可能没有 nanovim,所以编辑文件通常还是在宿主机 /root/.hermes 中完成。


23. 不进入容器直接查看容器内文件

可以执行:

docker exec -it hermes sh -lc 'ls -la /opt/data'

命令解释

docker exec -it hermes

进入正在运行的 hermes 容器执行命令。

sh -lc 'ls -la /opt/data'

在容器内启动 shell,并执行:

ls -la /opt/data

其中:

参数 含义
-l 让 shell 以 login-like 方式处理环境
-c 执行后面的字符串命令

24. 本阶段最终状态

完成第 1 阶段后,应该达到这些结果:

Docker 镜像已成功拉取

docker image inspect nousresearch/hermes-agent:latest >/dev/null 2>&1 && echo "IMAGE_OK" || echo "IMAGE_NOT_READY"

输出:

IMAGE_OK

Hermes 数据目录存在

ls -ld /root/.hermes

可以看到目录存在。

模型可以正常回复

执行:

docker run -it --rm \
  -v /root/.hermes:/opt/data \
  -e TZ=Asia/Shanghai \
  nousresearch/hermes-agent chat -q "你好,用一句中文回复我。"

如果能返回中文回复,说明模型/API 已经配置成功。

已理解路径映射

宿主机:/root/.hermes
容器内:/opt/data

后续:

  • SSH 编辑文件用 /root/.hermes
  • Hermes 读取文件用 /opt/data

25. 第 1 部分常用命令汇总

查看 Docker 镜像

docker images | grep hermes

检查 Hermes 镜像是否可用

docker image inspect nousresearch/hermes-agent:latest >/dev/null 2>&1 && echo "IMAGE_OK" || echo "IMAGE_NOT_READY"

查看 Docker 镜像源

docker info | sed -n '/Registry Mirrors/,+10p'

运行 Hermes setup

docker run -it --rm \
  -v /root/.hermes:/opt/data \
  -e TZ=Asia/Shanghai \
  nousresearch/hermes-agent setup

测试模型回复

docker run -it --rm \
  -v /root/.hermes:/opt/data \
  -e TZ=Asia/Shanghai \
  nousresearch/hermes-agent chat -q "你好,用一句中文回复我。"

查看 Hermes 数据目录

ls -la /root/.hermes

查看容器挂载

docker inspect hermes --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

26. 本阶段易踩坑汇总

坑 1:Docker Hub 超时

表现:

dial tcp ...:443: i/o timeout

解决:

配置腾讯云 Docker 镜像源:

https://mirror.ccs.tencentyun.com

坑 2:镜像最后一步 unknown error

表现:

error from registry: unknown error

解决:

不要清理缓存,直接重试:

docker pull nousresearch/hermes-agent:latest

坑 3:误以为源码目录必须保留

实际:

使用官方 Docker 镜像后,源码目录可以删除。

真正需要保留的是:

/root/.hermes

坑 4:mimo-v2-flash 不支持

表现:

HTTP 400: Not supported model mimo-v2-flash

解决:

改成:

mimo-v2-pro

或根据套餐支持尝试:

mimo-v2.5-pro

坑 5:混淆 /root/.hermes 和 /opt/data

正确理解:

/root/.hermes 是服务器宿主机路径
/opt/data 是容器内部路径
两者通过 Docker volume 映射到一起

第 2 部分将记录:
Hermes Agent 云服务器部署笔记(二):微信 Weixin Gateway 与 Docker Compose 常驻运行
会详细解释:

  • 为什么终端聊天能回复,不代表微信能回复
  • gateway run 是什么
  • 临时 docker run 和 Docker Compose 常驻运行的区别
  • 如何创建 /root/compose.hermes.yml
  • 微信 pairing code 是什么
  • 为什么 docker exec hermes hermes ... 会失败
  • 正确批准微信配对的方法
  • /status/sethome 的作用
  • 两个 SSH 窗口应该怎么用
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐