上个月我在 Rocky Linux 9 上部署 Hermes Agent 和 Hermes-Web-UI,一开始以为难点在 Agent 本身的安装,折腾完才发现真正让人头疼的是两个服务的连接方式、SELinux 策略、以及“会话老是丢”这种看起来像玄学的问题。如果你正打算在 Rocky Linux 上把这套东西跑起来,我给你一条完整可走的路径,顺带把几个高频坑的排查链路拆开讲清楚。
这篇文章适合两类人看:一类是刚接触 Hermes Agent,只想在内网服务器上快速搭一个可控的 AI Agent 服务端点,配一个 Web 界面用来调试对话;另一类是已经部署过,但被会话丢失、登录卡死、UI 连不上 Agent 这类问题反复折磨的运维。两种场景我都会覆盖,命令以 Rocky Linux 9.x 为例,8.x 大部分通用,差异我会在相关部分点出来。
1. 部署前先把两个组件的关系弄清,能省一半排查时间
1.1 Hermes Agent 与 Hermes-Web-UI 各管什么事
Hermes Agent 本质上是负责跑智能体运行时的那一层:它对接大模型接口,管理工具调用,执行会话中的任务逻辑。你可以完全不需要 Web 界面,只用命令行或 API 方式驱动它。Hermes-Web-UI 则是配套的一个浏览器控制台,负责展示会话、管理多个 Agent 实例、查看运行日志、编排提示词等。
我用一个不严谨但好记的类比:Agent 是发动机,UI 是仪表盘和中控台。发动机不行,仪表盘再好看车子也走不动;但仪表盘如果没有正确接到发动机的总线上,你一样看不到转速和车速。部署时的顺序必须是 Agent 先跑起来,UI 再连过去。我看到过很多人先装 UI,填了一堆配置结果 UI 一直报 Agent 不可用,回过头才发现 Agent 进程根本没起,或者 Agent 配置里没填模型网关的密钥。
另一个值得注意的点是:Hermes 这个名字在开源社区里被不少项目用过,有做网络监控的,有做 SIP 探测的,跟我们要部署的 AI Agent 是完全不同的东西。下载前确认你拿到的发行包确实是“Hermes Agent + Hermes-Web-UI”这套组合,避免跟同名项目混淆。检查方式很简单,看解压后的目录里有没有 config 模板、agent serve 或 agent run 这类子命令入口,以及文档里是否提到大模型接入和 WebUI 配置。
1.2 分清服务器部署和桌面版/Windows 部署的边界
标题里写的是 Rocky Linux,但实际搜索“Hermes Agent 安装”的人里,很多是在 Windows 上或桌面 Linux 环境里折腾。这里有个认知要纠正:Rocky Linux 服务器上部署,一般走的是无桌面、无头模式,Agent 作为后台守护进程运行,UI 通过浏览器远程访问,这跟你在 Windows 上双击安装、用桌面图标点开的管理方式完全是两套玩法。
服务器部署不依赖图形库,不需要 xcb、gtk 这些组件;而桌面版安装报错,往往不是 Agent 本身的问题,是系统缺少图形运行库。网上能看到大量“hermes agent 桌面版安装报错”的帖子,十有八九是缺 libX11、libgtk-3 之类的东西。你在 Rocky Linux 最小化安装环境里硬要跑桌面版,先检查ldd /path/to/hermes-agent | grep "not found",把缺的库补上再说,但这不应该是服务器部署的核心路径。Windows 本地部署则涉及到不同的进程托管方式和路径写法,不能把本篇文章的 systemd 逻辑照搬过去。
2. Rocky Linux 上先补四件基础配置,每一步都有明确原因
2.1 网卡静态 IP:别让机器重启后 UI 彻底消失
很多人会忽视这一步,因为云主机或虚拟机装系统时 DHCP 也能正常工作。但等你把 Hermes-Web-UI 部署完,某次机房断电或服务器重启后,网卡拿到了一个新 IP,你会发现自己连 UI 的访问地址都找不回来了。Rocky Linux 9 的默认网络管理工具是 NetworkManager,设置静态 IP 最稳妥的方式是用 nmcli。
先看当前网卡和连接的对应关系:
nmcli -t -f NAME,DEVICE con show假设你的连接名是 ens160,我想把地址改成 192.168.1.100/24,网关指向 192.168.1.1,DNS 用一个可用的公共 DNS 或者内网 DNS:
nmcli con mod ens160 ipv4.addresses 192.168.1.100/24 nmcli con mod ens160 ipv4.gateway 192.168.1.1 nmcli con mod ens160 ipv4.dns "223.5.5.5 119.29.29.29" nmcli con mod ens160 ipv4.method manual nmcli con up ens160这里强调一下,ens160 只是我环境里的网卡名称,你的机器上可能是 ens3、enp1s0 或 ens192,务必以ip a输出为准。改完执行ip a和ip route确认地址和网关生效。
有同学会问:我们是内网访问,能不能不改静态 IP?如果网络里有 DHCP 保留,且网管能确保帮你长期保留同一个地址,那确实可以不改。但按我的实际经验,服务器部署还是建议直接固定 IP,因为后续配置 UI 的访问地址、回调地址、Agent 的 endpoint 都依赖一个稳定 IP,频繁变化非常影响排查。
2.2 dnf 源与系统更新:装 Agent 前先保证基础环境干净
网上关于“rocky linux 8.10 yum源”的讨论很多,核心原因就是 Rocky Linux 默认官方源在某些网络环境下速度一般,而且 epel-release 的安装也容易出差错。在装任何东西前,先做系统更新:
dnf update -y如果发现默认源慢,想切换到国内镜像源,操作前务必备份原有的 repo 文件。Rocky Linux 8 的仓库文件在 /etc/yum.repos.d/,主要包括 Rocky-AppStream.repo、Rocky-BaseOS.repo、Rocky-Extras.repo 这几个。换成镜像源后记得执行:
dnf clean all dnf makecache这里我多说一句:不管换哪个镜像源,都别在 repo 文件里同时开一堆第三方源而没有优先级控制,那会让依赖解析变得非常难搞。让基础源保持干净,后面排查依赖问题时会省很多力气。
编译和安装 Hermes Agent 通常不需要编译源码,所以 gcc 这类工具没必要装。但有几个基础工具是必须的:curl、tar、policycoreutils-python-utils(管理 SELinux 端口标签用)、firewalld。如果是最小化安装,先执行:
dnf install -y curl tar policycoreutils-python-utils firewalld2.3 SELinux:放行端口远远不够,还要让 Nginx 能主动连出去
Rocky Linux 默认开启 SELinux,很多人部署完发现浏览器访问 Nginx 能开页面,但 Nginx 转发到 Hermes-Web-UI 的 8080 端口时总超时,第一反应是防火墙不通,折腾半天结果getenforce一查,发现是 SELinux 拦了。
SELinux 对 Nginx 等 HTTP 服务的限制有两层:一层是监听端口是否被允许,另一层是进程能否作为客户端去连接别的端口。反向代理场景必须把第二层打开,也就是设置 httpd 相关布尔值:
setsebool -P httpd_can_network_connect 1如果你希望 UI 服务本身监听在自定义端口,比如 8080、8081,并且让 SELinux 放行,可以用 semanage 给端口打上 http_port_t 标签:
semanage port -a -t http_port_t -p tcp 8080排查时有个更高效的小技巧:先用setenforce 0临时切到 permissive 模式,如果服务立刻正常,基本能断定是 SELinux 策略问题。确定后把需要放行的布尔值和端口标签配好,再setenforce 1恢复。不建议一直关着 SELinux,生产环境尽量用策略解决,而不是图省事把安全机制整个关掉。
2.4 firewalld 只放必要端口,Agent 的健康检查端口不要暴露公网
Rocky Linux 的防火墙默认是 firewalld。我们对外只需要暴露 Hermes-Web-UI 的访问端口,通常由 Nginx 监听 80/443 来承担。Agent 自身提供的 API 健康检查端口,一般只应当绑在 127.0.0.1 上,让 UI 或其他本机服务访问,不需要对公网开放。
命令很简单:
systemctl enable --now firewalld firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --reload如果你不想用 Nginx,打算直接把 Hermes-Web-UI 的 8080 端口暴露出去,那就放行 TCP 8080:
firewall-cmd --permanent --add-port=8080/tcp firewall-cmd --reload我的建议是:8080 这类端口尽量别直接暴露到公网,让 Nginx 或者内网网关在前面做一层代理比较稳妥。检查放行结果用firewall-cmd --list-all,确认监听的端口用ss -lntp,这两个命令在后续排错里会反复用到。
3. Hermes Agent 安装实操:从二进制包到 systemd 守护进程
3.1 先确认版本类型和硬性依赖
Hermes Agent 的官方发行一般会同时提供 linux-amd64、linux-arm64 的二进制压缩包,有的场景也提供容器镜像。服务器部署建议直接下载二进制压缩包,不要装桌面版。下载前先确定机器的 CPU 架构:
uname -mx86_64 对应 amd64 包,aarch64 对应 arm64 包。包装依赖方面,官方二进制通常不需要额外的运行时环境,比如不要求你预先安装某个特定版本的 Python 或 Node.js。如果你下载的是源码包,那就另当别论,一般会要求 Python 3.11 以上。为了少踩坑,优先选官方预编译的二进制格式。
3.2 手工安装步骤:目录规划、用户隔离、配置分离
假设发行包为 hermes-agent-linux-amd64.tar.gz,我习惯的安装路径是 /opt/hermes-agent,配置放 /etc/hermes-agent/,数据单独放 /var/lib/hermes-agent/。首先解压到指定目录:
mkdir -p /opt/hermes-agent tar -xzf hermes-agent-linux-amd64.tar.gz -C /opt/hermes-agent然后创建一个不能登录的系统用户来跑服务。用 root 直接跑生产服务不是一个好习惯,一旦 Agent 有漏洞或者配置目录被误改,风险范围会大很多:
useradd --system --home /opt/hermes-agent --shell /sbin/nologin hermes chown -R hermes:hermes /opt/hermes-agent mkdir -p /etc/hermes-agent /var/lib/hermes-agent chown -R hermes:hermes /etc/hermes-agent /var/lib/hermes-agent这样做的好处是数据目录、配置目录和可执行文件都是受控的。后面如果发现 UI 会话无法持久化或者 Agent 写不了数据,检查ls -l的属主是不是这个用户,往往一眼就能定位。
3.3 配置模型供应商:以 OpenAI 兼容接口为例
Hermes Agent 要正常工作,必须能访问一个可以输出对话内容的大模型接口。绝大多数 Agent 框架都支持 OpenAI 兼容的接入方式,也就是你只需要提供一个 base_url、一个 api_key、一个 model 名称。
配置文件在 /etc/hermes-agent/config.yaml,常见的关键字段长这样:
server: listen: "127.0.0.1:5188" llm: provider: openai-compatible base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1" model: "qwen-plus" api_key: "${DASHSCOPE_API_KEY}" storage: dir: "/var/lib/hermes-agent/data"这里注意几点:第一,listen 地址我强烈建议绑 127.0.0.1 而不是 0.0.0.0。Agent 的连接能力就是给内部服务和 UI 用的,没必要把端口暴露到外部网络。第二,api_key 不要直接明文写死在 yaml 里。虽然写死也能跑,但配置文件时不时会被复制、备份、截图,密钥泄露风险很大。更好的做法是放在 systemd 的 EnvironmentFile 里,让配置通过环境变量引用。
如果你的模型网关不是这个地址,把 base_url 换成你自己的服务即可。不少用户用的是阿里云百炼之类的平台,它们通常提供 OpenAI 兼容协议端点,也可以在控制台拿到模型名和密钥。关键是 Agent 能通过这个配置完成一次最简单的模型调用——在正式接 UI 之前,建议先命令行跑一个对话测试。
3.4 用 systemd 托管 Agent 进程
手工在终端里执行 Agent 前台启动、再放到后台nohup的方式也能跑,但服务器重启后不会自动恢复,进程挂了你也不容易感知。正确的做法是交给 systemd 托管。创建一个服务单元文件 /etc/systemd/system/hermes-agent.service:
[Unit] Description=Hermes Agent Service After=network-online.target Wants=network-online.target [Service] Type=simple User=hermes Group=hermes WorkingDirectory=/opt/hermes-agent EnvironmentFile=/etc/hermes-agent/env ExecStart=/opt/hermes-agent/hermes-agent serve --config /etc/hermes-agent/config.yaml Restart=on-failure RestartSec=5 LimitNOFILE=65535 [Install] WantedBy=multi-user.target上述的 serve 子命令和 --config 参数是我在常用部署版本里的写法,不同构建版本可能稍有不同,以你的二进制执行hermes-agent --help看到的实际子命令为准,但 service 文件的结构是可以直接复用的。
环境变量文件 /etc/hermes-agent/env 里放密钥,创建后记得收紧权限:
cat > /etc/hermes-agent/env <<'EOF' DASHSCOPE_API_KEY=你的密钥 EOF chmod 600 /etc/hermes-agent/env chown hermes:hermes /etc/hermes-agent/env随后加载并启动:
systemctl daemon-reload systemctl enable --now hermes-agent systemctl status hermes-agent journalctl -u hermes-agent -f启动成功后执行curl http://127.0.0.1:5188/healthz也许能拿到一个健康响应,具体路径以版本为准。如果返回不是预期结果,先不要怀疑配置,回到 journalctl 日志里看有没有模型网关地址连不通、认证失败、监听端口被占用这类直接线索。
4. Hermes-Web-UI 部署:把浏览器控制台接到 Agent 上
4.1 安装形态选择:容器编排还是手动二进制
Hermes-Web-UI 的部署方式一般有两种:一种是官方提供了 docker-compose 编排,把 UI 服务和数据库一起起起来;另一种是直接下载编译好的可执行文件。如果你的服务器上本来就在用 Docker,用容器方式确实最省事,一条docker compose up -d就能把 UI 和依赖的存储组件一起拉起。
如果你的环境里没有 Docker,而且团队对容器化部署还有政策限制,那就走手动二进制路线。跟 Agent 一样,下载对应架构的 UI 发行包,我习惯放到 /opt/hermes-web-ui:
mkdir -p /opt/hermes-web-ui tar -xzf hermes-web-ui-linux-amd64.tar.gz -C /opt/hermes-web-uiUI 进程不建议用 root 跑,单独建一个用户更干净:
useradd --system --home /opt/hermes-web-ui --shell /sbin/nologin hermes-ui chown -R hermes-ui:hermes-ui /opt/hermes-web-ui4.2 让 UI 找到 Agent:核心是 agent endpoint 配置
UI 和 Agent 之间是客户端和服务器关系。Hermes-Web-UI 需要配置一个 Agent 的 API endpoint。如果二者在同一台机器,这个地址通常是:
http://127.0.0.1:5188请注意一个问题:很多人在这里图省事,直接把 Agent 的地址写成了公网 IP。这在逻辑上也能通,但平白无故把内部 API 暴露到公网增加了风险,而且绕了一圈之后才发现本机互访根本不需要走公网。同机部署就写 127.0.0.1;如果 UI 和 Agent 分别部署在两台机器,UI 服务器到 Agent 服务器之间优先走内网地址,并在 Agent 配置里做好访问控制。
UI 的配置文件里通常还包含会话存储相关的字段:存储类型可以用 SQLite 或外部的 PostgreSQL,存储目录则要指向一个可持久化的路径。同样,不要用内存模式跑生产环境。UI 部署完成后先启动一次,用浏览器访问本机端口,确认登录页能出来:
systemctl start hermes-web-ui curl -I http://127.0.0.1:8080如果 UI 页面能打开但提示 Agent 不可用,优先查 Agent 进程是否在跑、监听端口是 127.0.0.1 还是别的地址、UI 配置里的 endpoint 有没有写错。
4.3 Nginx 反向代理与长连接参数:这几行和会话丢失有直接关系
Hermes-Web-UI 默认监听在 8080 端口。生产环境不推荐把这个端口直接暴露出去,更好的方式是用 Nginx 反代到 80/443。下面是一份可用的 Nginx server 配置:
server { listen 80; server_name your.domain.example; client_max_body_size 20m; location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 300s; proxy_send_timeout 300s; proxy_buffering off; } }这段配置里最容易被忽略的是 proxy_read_timeout、proxy_buffering 和 Upgrade 头。UI 在跑大模型对话时,往往是一次很长的流式请求,模型生成几百个 token 可能需要数十秒甚至几分钟。Nginx 默认 60 秒超时,如果模型中途思考时间超过这个值,Nginx 会直接掐断连接,前端表现为“请求失败”或者“会话中断”。把超时时间加长,同时关掉代理缓冲,才能让流式输出顺畅回到浏览器。“我的 hermes-web-ui 的会话老是丢失”这个问题,有一部分就是在这里产生的——不是代码丢数据,而是连接被中断后前端没有收到最终状态,界面上的会话列表自然就乱了。
WebSocket 的 Upgrade 头也是同样道理。UI 和 Agent 之间如果使用 WebSocket 做实时消息推送,少了 Upgrade 头,连接就会退化成普通 HTTP 请求,在线状态和会话同步都会出问题。配置改完后:
nginx -t systemctl reload nginx5. 高频问题排查:会话丢失、登录卡住、UI 连不上 Agent
5.1 “会话老是丢失”的完整排查链路
先说结论:大部分“会话丢失”都不是 Hermes 团队埋了什么天坑,而是四个原因里的某一个:浏览器侧存储被清理、服务端用了内存存储、持久化目录权限不对、反向代理把长连接掐断。根据我的排查经验,正确做法是从表现反推,而不是一上来就重装服务。
第一步,先做对照实验。在一个隐身窗口里打开 UI,登录后新建一条会话,刷新页面看会话是否还在。如果隐身窗口能保留、但原来浏览器看不到历史会话,那基本是浏览器侧的 localStorage、IndexedDB 或会话 Cookie 出了问题,常见诱因是清理浏览器数据、Cookie 过期策略太激进、不同域名产生了隔离。处理方向是检查登录状态和域名一致性,不要在 IP 和域名之间频繁切换访问同一套 UI。
第二步,所有浏览器都丢,就要看后端存储。执行:
journalctl -u hermes-web-ui --no-pager -n 500 | grep -i error日志里如果出现 session save failed、database is locked、permission denied 这类关键词,直接去查数据目录的属主和写权限。现实中一个非常典型的场景是:临时用 root 用户启动过一次 UI,数据目录里的文件带着 root 属主,后来改成系统用户跑服务,进程写不进去,会话只能在内存里存活,进程一重启就全部消失。处理方式:
chown -R hermes-ui:hermes-ui /opt/hermes-web-ui/data第三步,检查会话记录到底有没有落库。如果 UI 用 SQLite 存储,可以安装 sqlite3 后直接查表:
sqlite3 /opt/hermes-web-ui/data/hermes.db ".tables"这个命令能告诉你底层表结构是否存在、会话数据是否已经写进数据库。如果数据库里明明有数据但 UI 列表不显示,通常不是丢,而是页面查询接口报错,或者浏览器端会话 token 失效,需要重新登录后才会重新拉取。
第四步,如果只有长对话、大模型回答到一半时丢,重点怀疑 Nginx 超时。回到日志看有没有连接重置记录,将 4.3 节的 proxy_read_timeout 和 proxy_buffering 调好。这个我前面专门提到过,这里再强调一次:改完 Nginx 配置一定要systemctl reload nginx,不要只改文件不重载,那是很多人最容易漏的一步。
5.2 安装时为什么要求登录网站?“登录卡住”到底卡在哪
搜索“hermes agent安装要登录网站怎么回事”的人非常多。其实不是 Agent 本身强制要求联网,而是安装脚本默认会执行一次初始化向导,引导你登录官网账号或平台账号,为当前机器生成一个访问凭证,以便同步模型服务配置、插件目录或验证许可证。这在交互式终端里看得比较清楚,但如果你是通过 SSH 远程执行,本地没有浏览器,或者公司网络策略限制了外部访问,整个过程就会卡在某一步看起来像“不动了”。
处理方法是安装时主动避开交互式向导。看官方文档是否提供--headless、--no-browser或环境变量跳过初始化向导的选项。如果没提供,可以先手动把 config.yaml 里的大模型配置和存储目录写好,再直接以后台服务方式启动 Agent。换句话说,安装向导不是必经之路,启动服务时真正读取的是配置文件,而不是“你有没有登录过网站”。另外,在执行交互式安装时尽量配合 tmux 或 screen 使用,避免 SSH 连接中断导致安装进程卡死。
5.3 UI 连不上 Agent 时的通用检查顺序
“UI 连不上 Agent”比“会话丢失”好排查很多,问题是很多人习惯性先怀疑配置,却忘了检查最基本的进程和端口状态。我建议按以下顺序走一遍:
- Agent 进程是否存活:
systemctl status hermes-agent。 - Agent 监听地址是什么:
ss -lntp | grep 5188。如果显示的是 127.0.0.1:5188,外部机器用公网 IP 去访问自然不通,本机 UI 访问则没影响。 - UI 配置里的 endpoint 是否准确:同机部署写 127.0.0.1,跨机部署写 Agent 所在机器的内网地址。
- 防火墙是否放行:
firewall-cmd --list-all。 - SELinux 是否拦截:结合第 2.3 节,临时
setenforce 0后重试,如果通了就能定位是 SELinux 策略问题,再回来把 httpd_can_network_connect 或端口标签配好。
这个顺序看起来简单,但能覆盖现实中绝大多数“连不上”场景。先把链路层面的东西排除掉,再去看 UI 界面上的错误提示,排查成本会低很多。
最后说一个我个人的运维习惯:无论 Agent 还是 UI,升级前先把配置目录和数据目录完整备份一份,尤其是 /var/lib/hermes-agent/data 这种会话和运行数据目录。有的升级包会做 schema 迁移,一旦迁移异常,有备份就还能回滚。还有就是在 /etc/hermes-agent/env 里放密钥时记得权限改成 600,别让同机其他用户能读到。这套部署方案跑顺之后,日常维护量其实不大,大部分时间你只需要盯住 Agent 日志和磁盘空间就够了。