
拿到一台全新的 Rocky Linux 服务器第一件事往往不是急着复制粘贴安装命令而是先把 Hermes Agent 和 Hermes-Web-UI 之间的关系理顺。我在多台机器上见过两种极端情况一种是只装了 Hermes Agent结果天天对着终端敲命令连个可视化界面都没有排查日志全靠journalctl另一种是装好了 Hermes-Web-UI但 Agent 本体没跑起来界面打开一片空白点哪儿都没反应。这篇指南要做的就是把 Rocky Linux 从裸系统到 Web UI 可用的完整链路走一遍包括环境准备、Agent 安装、Web UI 部署、systemd 托管以及我在实际操作中踩过的坑和对应的排查思路。如果你正准备在自己服务器上本地部署 Hermes Agent又想让管理界面更友好一点这篇文章会很有参考价值。我会把每一步的理由也说清楚不是简单丢命令给你抄而是帮你理解为什么要这样做这样你在遇到报错时才有能力自己判断问题出在哪。1. 为什么先理清 Agent 和 Web-UI 的关系再动手装1.1 两个组件的分工完全不同Hermes Agent 和 Hermes-Web-UI 虽然是配套使用的但它们的职责边界非常清楚。Hermes Agent 是真正干活的后端程序负责加载配置、连接模型供应商或本地模型、处理请求、维护会话状态、写日志、执行各种自动化任务。它本身不提供图形界面大部分时候以命令行进程或后台服务的方式运行。Hermes-Web-UI 则是给 Agent 套了一层可视化的操作台它做的事情是把 Agent 的状态、对话记录、配置项、运行日志等展示出来同时把你在网页上操作的动作转成 API 请求发给 Agent。换句话说UI 是壳Agent 才是核。你可以在没有 Web UI 的情况下单独跑 Agent但反过来不行——没有 Agent 的 Web UI 只是一个空壳页面什么都干不了。这个关系听起来很简单但实际部署时很多人栽跟头。原因在于网上不少教程把两个组件混在一起讲导致用户以为安装某一个就等于把整套系统装好了。我见过最典型的例子是有人花了半小时装好 Web UI然后启动服务浏览器打开 80 端口页面确实出来了但登录进去发现 Agent 状态一直显示离线。他折腾了半天配置 Nginx、改防火墙结果最后发现 Agent 压根没装。1.2 明确自己的使用场景再决定两步都要不要做不是所有人都需要 Web UI。如果你只是想在服务器上跑一个 Agent通过命令行或 API 调用那只需要安装 Hermes Agent 本体再加一个 systemd 服务让它稳定常驻就够了。Web UI 对这种场景反而是一个多余的攻击面和资源占用源。反过来如果团队里有多个人要使用 Agent或者你想在手机上通过浏览器查看状态、发指令那 Web UI 就不是可选项了。它提供的可视化操作能力能大幅降低使用门槛让不熟悉命令行的同事也能上手。所以我的建议是先想清楚自己的使用场景再决定安装路径。这篇指南会按Agent 必装 Web UI 按需安装的顺序来讲这样即使你最后不需要 UI前面的步骤也不会白做。2. Rocky Linux 环境准备静态 IP、SELinux 和防火墙三件套2.1 选对系统版本装前先做一次全量更新Rocky Linux 目前主流版本是 8.x 和 9.x 两个系列。8.10 是 8 系列比较新的版本9.6 则是 9 系列的一个阶段性版本新项目我一般建议直接用 9 系列毕竟软件包版本更新Python、OpenSSL 这些基础组件的版本也更高省得后面为了凑依赖版本折腾。系统安装完之后无论你用的是哪个版本第一件要做的事永远是把系统包更新到最新。这不仅是安全需要更重要的是如果系统自带的组件版本太旧后面安装 Hermes Agent 的依赖时可能会因为 OpenSSL 版本不够或者 glibc 版本偏低而编译失败。dnf update -y dnf install -y curl wget git tar gzip unzip vim bash-completion更新完之后重启一下确保内核和用户态工具都切换到新版本。这一步不做的话后面跑ss、firewall-cmd这些命令时有可能遇到行为不一致的问题。2.2 用 nmcli 把服务器 IP 固定成静态 IP这一步容易被忽略但非常关键。Hermes Agent 部署完成后如果你需要让局域网内其他机器访问 Web UI服务器的 IP 必须稳定。DHCP 分配的 IP 一旦过期重新续租地址可能就变了到时候你的 Web UI 在浏览器里突然打不开排查半天发现是 IP 变了——这种低级错误真的会浪费大量时间。Rocky Linux 8/9 的网络管理默认走 NetworkManager修改 IP 最稳妥的方式是用nmcli命令不要直接改/etc/sysconfig/network-scripts/ifcfg-*文件虽然改文件也能生效但在 NetworkManager 接管的环境下容易出现配置被回写的奇怪问题。先查看当前网卡名称和连接名nmcli connection show假设网卡叫ens160连接名也叫ens160把它改成静态 IP比如192.168.1.100nmcli connection modify ens160 ipv4.method manual ipv4.addresses 192.168.1.100/24 ipv4.gateway 192.168.1.1 ipv4.dns 192.168.1.1 nmcli connection up ens160改完之后用ip addr show ens160确认生效。这里有个细节ipv4.dns不要只填一个 Google 的 8.8.8.8 之类的公共 DNS除非你的服务器能稳定访问外网。如果这台机器在内网环境填内网 DNS 或者干脆填网关地址更稳。2.3 SELinux 和 firewalld 对 Hermes 的影响Rocky Linux 默认开启了 SELinux安全增强型 Linux强制模式是Enforcing。很多从 Debian/Ubuntu 转过来的用户一上来就喜欢setenforce 0甚至改/etc/selinux/config永久关闭 SELinux。我理解这样做能省很多事但对于一台要长期跑服务的机器我强烈不建议一上来就关。SELinux 其实只在你用了非标准端口、非标准配置时才会给你找麻烦而且每次报错都能通过ausearch或/var/log/audit/audit.log找到明确的拒绝记录完全有迹可循。正确做法是保持 SELinux 开启遇到问题时看审计日志具体解决。比如后面 Nginx 反向代理到 Hermes-Web-UI 的本地端口时你会撞上httpd_can_network_connect这个布尔值没有打开的问题到时候一条setsebool命令就能解决完全不需要关闭 SELinux。防火墙方面Rocky Linux 默认启用 firewalld。官方仓库装包时会自动放行 SSH 和 DHCP 相关的服务但不会放行 HTTP/HTTPS。如果你计划让 Web UI 对外提供服务记得放行 80/443 端口firewall-cmd --permanent --add-servicehttp firewall-cmd --permanent --add-servicehttps firewall-cmd --reload如果你想让 Hermes Agent 的 API 端口比如 9120也被外部直接访问那还要单独放行这个端口。但我个人的习惯是API 端口只监听 127.0.0.1对外一律走 Nginx 反向代理这样少暴露一个端口安全面更小。3. Hermes Agent 本体安装完整流程账号、运行时、配置、开机服务3.1 创建专用账号和 Python 运行时环境我不建议直接用 root 用户跑 Hermes Agent。虽然这样最省事但一旦 Agent 被外部利用或者代码本身有漏洞攻击者拿到的就是 root 权限。创建一个专用系统用户把服务运行在最小权限下这是服务器运维的基本素养。useradd -r -d /opt/hermes -s /sbin/nologin hermes mkdir -p /opt/hermes/{app,logs,data,etc} chown -R hermes:hermes /opt/hermes这里-r表示创建系统用户-s /sbin/nologin表示这个用户不能登录 shell只能运行服务。数据目录单独分出来方便后续备份和升级。Hermes Agent 这类项目依赖 Python 3.10 以上。Rocky Linux 8 自带的 Python 版本是 3.6太老了Rocky Linux 9 自带 Python 3.9对某些 AI 项目来说也未必够。我建议直接安装 Python 3.11Rocky 官方 AppStream 仓库里有现成的模块。dnf module -y install python311 dnf install -y python3.11-devel python3.11-pip装完之后用python3.11 -V确认版本是 3.11.x。这里要注意千万不要直接改系统默认的 python3 软链指向 3.11因为系统里还有很多工具依赖原本的 Python 版本你强行改了软链过两天可能发现dnf都跑不起来了。3.2 获取 Hermes Agent 代码并完成依赖安装Hermes Agent 的官方发布渠道会提供源码包或预编译的二进制包我更推荐用 git clone 的方式获取源码因为后续升级可以直接git pull不用重新下载整个包。当然如果你只是想在服务器上跑起来下载官方 Release 页面的 tar.gz 压缩包也可以步骤类似。以源码方式为例cd /opt/hermes/app sudo -u hermes git clone https://github.com/your-org/hermes-agent.git .克隆完代码之后创建 Python 虚拟环境并安装依赖cd /opt/hermes/app sudo -u hermes python3.11 -m venv venv sudo -u hermes ./venv/bin/pip install -U pip setuptools wheel sudo -u hermes ./venv/bin/pip install -r requirements.txt这一步是整个安装过程中耗时最长也是最容易出问题的一步。如果依赖列表里有需要编译的 C 扩展包缺少编译器或对应的开发头文件就会报错。为了避免中途翻车建议先把编译工具链装齐dnf install -y gcc gcc-c make cmake如果你的服务器访问 PyPI 速度很慢可以配置国内镜像源比如清华源。修改方式是在用户家目录下建一个~/.pip/pip.conf或者在命令里临时指定sudo -u hermes ./venv/bin/pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple依赖装完后先跑一下 CLI 帮助命令确认入口命令可用。不同版本的项目入口命令名可能不同常见的是hermes或者hermes-agent。如果你看到的是别的名字后面所有命令都要跟着调整。sudo -u hermes ./venv/bin/hermes --help3.3 编辑 config.yaml本地模型还是外部 APIHermes Agent 的配置文件通常是一个 YAML 文件放在/opt/hermes/etc/config.yaml。第一次启动前必须把配置里的核心内容填好否则进程虽然能起来但一调用就会报错。配置里最核心的是模型供应商相关的内容。如果你用的是 DeepSeek、OpenAI 这类外部 API需要填对应的base_url、api_key和model名称。如果你用的是本地模型比如通过 Ollama 或 vLLM 跑的模型那base_url要指向本地模型的监听地址。下面是一个参考配置结构agent: name: hermes-node-01 listen_host: 127.0.0.1 listen_port: 9120 log_level: info data_dir: /opt/hermes/data llm: provider: deepseek base_url: https://api.deepseek.com/v1 api_key: sk-xxxxxxxxxxxx model: deepseek-chat temperature: 0.7 storage: type: sqlite path: /opt/hermes/data/hermes.db这里的listen_host我建议固定写127.0.0.1不要让 Agent 直接暴露在网络上。外部访问全部通过 Web UI 和 Nginx 这一层Agent 只对本地回环地址提供服务。api_key最好不要明文写在 YAML 里。更稳妥的做法是通过环境变量注入在 systemd 服务文件里引用环境变量这样即使配置文件被意外读取也不会直接泄露密钥。具体做法在 3.4 里会一起讲。3.4 初始化数据库并用 systemd 将 Agent 做成开机服务配置写好后一般需要先执行一次初始化命令让 Agent 创建数据库表结构、生成初始配置。不同项目的初始化命令不一样有的叫hermes init有的叫hermes migrate也有的在首次启动时自动完成。你可以先看一下项目 README 里的说明。以常见的方式为例sudo -u hermes ./venv/bin/hermes init --config /opt/hermes/etc/config.yaml如果之前没有遇到过这个命令但服务能正常启动且日志里没有报数据库错误那大概率是会自动初始化的类型不用额外执行。接下来创建 systemd 服务文件。我习惯放在/etc/systemd/system/hermes-agent.service[Unit] DescriptionHermes Agent Service Afternetwork.target [Service] Typesimple Userhermes Grouphermes WorkingDirectory/opt/hermes/app EnvironmentFile/opt/hermes/etc/hermes.env ExecStart/opt/hermes/app/venv/bin/hermes serve --config /opt/hermes/etc/config.yaml Restarton-failure RestartSec5 [Install] WantedBymulti-user.target注意这里的EnvironmentFile我建议把 API 密钥等敏感信息放到/opt/hermes/etc/hermes.env文件里内容类似DEEPSEEK_API_KEYsk-xxxxxxxxxxxx然后在 config.yaml 里通过api_key: ${DEEPSEEK_API_KEY}引用。这样做的好处是配置文件和密钥分离备份配置时不用担心密钥泄露。EnvironmentFile文件需要设置好权限chmod 600 /opt/hermes/etc/hermes.env chown hermes:hermes /opt/hermes/etc/hermes.env启动服务并设置开机自启systemctl daemon-reload systemctl enable --now hermes-agent最后验证一下服务状态和端口监听systemctl status hermes-agent ss -tlnp | grep 9120看到State: listening就说明 Agent 本体已经跑起来了。此时可以再执行一条简单的测试命令比如通过 API 发一个基础请求确认模型调用链路也是通的。4. Hermes-Web-UI 部署前端构建、后端服务和 Nginx 反向代理4.1 准备 Node.js 运行时并获取 Web-UI 构建产物Hermes-Web-UI 的前端部分一般是基于 Node.js 生态构建的需要 Node.js 18 或 20 版本。Rocky Linux 的 AppStream 仓库自带 Node.js 模块可以直接启用指定版本dnf module -y list nodejs dnf module -y enable nodejs:20 dnf install -y nodejs npm装完后用node -v和npm -v确认版本。获取 Web-UI 安装包的方式我建议直接下载官方 Release 页面的预构建产物这样可以省去前端编译的时间。如果你下载的是源码包则需要先安装 npm 依赖再执行构建步骤也不复杂cd /opt/hermes-web sudo -u hermes npm ci sudo -u hermes npm run buildnpm ci会严格按照锁文件安装依赖比npm install更可预期。构建完成后产出的静态文件一般在dist目录下这个目录就是下一步要用 Nginx 托管的根目录。4.2 配置 UI 后端服务会话存储、Agent 连接地址和密钥Hermes-Web-UI 不只是静态页面它还有一个后端 API 服务负责处理登录认证、会话管理、把前端请求转发给 Hermes Agent。这个后端服务可能是 Node.js 写的也可能是 Python 写的具体取决于项目实现但配置逻辑大同小异。需要关注三个核心配置项第一会话存储方式。如果只是单机部署使用默认的本地文件或 SQLite 存储就够了不需要额外装 Redis。但如果你的部署规模会上来多个 UI 实例共享会话状态那就必须引入 Redis否则用户登录状态没法在多实例之间同步。第二Agent 连接地址。这一步是最容易配错的地方。Web UI 后端需要知道 Agent 服务监听在哪个地址你要把这里填成http://127.0.0.1:9120而不是填服务器的公网 IP 或者域名。因为从同机后端访问 Agent走回环地址最快也最安全绕一圈外部地址反而可能被防火墙挡住。第三API 密钥。UI 后端调用 Agent API 时通常需要带一个密钥或 Token这个密钥要在 UI 配置里和 Agent 启动参数中保持一致。如果密钥对不上UI 里会频繁出现 401 认证失败。配置好之后用 Node 直接启动 UI 后端服务或者在项目目录下找自带的 CLI 启动脚本。先在前台跑一下确认没有报错再做成 systemd 服务。4.3 用 Nginx 托管静态文件并反向代理 APIWeb UI 的前端静态文件和后端 API 通常建议放在同一个域名下通过路径来区分这样浏览器端不会出现跨域问题。我会用 Nginx 做一层反向代理静态文件直接由 Nginx 提供服务/api路径的请求转发给 UI 后端服务。安装 Nginxdnf install -y nginx systemctl enable --now nginx然后创建一个站点配置文件比如/etc/nginx/conf.d/hermes-ui.confserver { listen 80; server_name hermes.example.com; root /opt/hermes-web/dist; index index.html; client_max_body_size 20m; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:3000; 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; } }这里把 UI 后端假设监听在127.0.0.1:3000具体端口以你配置为准。try_files那句很重要前端路由如果是 history 模式不写这句会导致刷新页面时出现 404。配置写完后重载 Nginxnginx -t systemctl reload nginx如果你配了域名记得在 DNS 把域名解析到服务器公网 IP并在云服务商的安全组和服务器 firewalld 里放行 80/443 端口。如果没配域名也可以直接用http://服务器IP访问只是server_name可以改成_或者干脆删掉。4.4 SELinux 调整给 Nginx 反代放行本地端口这是整个部署流程里最容易踩的坑。你配置好 Nginx 后访问静态页面没问题但所有/api请求都会返回 502 Bad Gateway。你检查 UI 后端进程发现它明明在正常运行手动curl http://127.0.0.1:3000也有响应那问题十有八九出在 SELinux 上。SELinux 默认策略不允许 Nginx 作为代理去连接本地非标准端口。查看审计日志ausearch -m avc -ts recent如果看到httpd_t相关的 deny 记录执行setsebool -P httpd_can_network_connect 1这个布尔值打开后Nginx 就能正常转发到127.0.0.1:3000之类的本地端口了。-P参数表示持久化重启后仍然生效。执行完后不需要重启 Nginx直接刷新页面接口应该就通顺了。5. 实战排错桌面版报错、端口不通、依赖版本裂化5.1 桌面版安装报错为什么频繁出现搜索hermes agent 桌面版安装报错的人不少我在现实中也遇到过类似问题。Hermes Agent 官方会发布桌面版安装包但在 Rocky Linux 这种以服务器为主要使用场景的系统上桌面版安装报错的概率比服务器版高得多。原因在于桌面版安装包通常会依赖图形界面的运行库比如 GTK、Qt 或者 X11 相关的库。如果你装的是最小化系统或者纯服务器版本这些库压根不存在安装器跑起来自然一团糟。我个人的建议是在 Rocky Linux 服务器上部署 Hermes Agent走 Portable 便携版或者源码安装的方式不要碰桌面版。桌面版面向的是个人电脑用户依赖的库太多而且它在无头服务器上就算能装上没有显示器也用不了。如果确实需要在本地电脑上使用桌面版那也尽量选择官方明确支持的系统版本并且按官方文档把图形库依赖一次性装齐。在服务器上折腾桌面版纯粹是浪费时间。5.2 连接拒绝和 502一次完整的排查链路这里分享一次我在部署 Web UI 时遇到的真实排查过程。现象是Nginx 配置好了静态页面能打开但登录后报错接口返回 502。我当时的第一反应是看 Nginx 日志tail -f /var/log/nginx/error.log日志里显示的是connect() failed (111: Connection refused) while connecting to upstream也就是 Nginx 连不上127.0.0.1:3000。但我前面明明已经确认 UI 后端进程起来了。这里要强调一个关键细节确认进程存在不意味着监听地址正确。我后来用ss -tlnp | grep 3000看了一下发现后端服务确实监听在 3000 端口但监听地址是::也就是 IPv6 的任意地址。而 Nginx 配置里proxy_pass指向的是127.0.0.1:3000这是 IPv4 的回环地址。在某些网络环境下IPv6 的::并不会接受来自 IPv4 回环的连接请求于是 502。解决方式两种要么把 Nginx 的proxy_pass改成http://[::1]:3000要么让后端服务明确监听127.0.0.1。我选择了后者因为让服务监听明确的 IPv4 回环地址更可控也更容易理解和排查。如果你遇到 502我建议按照这个顺序排查先curl -I http://127.0.0.1:3000看后端通不通不通就说明后端没起来通了再看 Nginx 错误日志看是连接拒绝还是超时如果日志里没有明显报错再查 SELinux 审计日志。这套链路基本能覆盖九成以上的场景。5.3 依赖版本裂化venv 能隔离但不万能Python 虚拟环境能隔离 Python 包的版本但隔离不了系统层面的 C 库。我在 Rocky Linux 8 上就碰到过一次很典型的版本裂化问题Hermes Agent 依赖的某个加密库在编译时要求 OpenSSL 1.1.1 以上但系统自带的 OpenSSL 是 1.1.1k满足要求后来我为了装其他软件手动从源码编译了一个新版 OpenSSL 并放在/usr/local/ssl结果 Python 在编译连接这个库时优先找到了新版本但新版本的头文件和系统库文件版本不一致导致启动时直接报version OPENSSL_1_1_1 not found。这类问题排查起来非常费力因为报错信息不一定指向你安装过的那个库。我的经验是不要为了一个软件去手动编译系统级的基础库。Rocky Linux 的仓库维护得不错大部分依赖都能通过 AppStream 或者 EPEL 解决。如果项目要求特殊版本的 OpenSSL优先考虑用容器方案隔离而不是污染宿主系统。另外升级系统包时也要留个心眼。dnf update升级了底层依赖后原先装在 venv 里的某些二进制扩展可能因为系统库接口变化而不能加载。这种问题通常表现为启动时 import 报错解决方案是重建虚拟环境把所有依赖重新装一遍。5.4 高频错误速查表现象大概率原因快速处理hermes命令找不到没有激活 venv 或 PATH 不对使用/opt/hermes/app/venv/bin/hermes绝对路径Agent 启动后立即退出配置文件权限不对或格式错误检查config.yaml缩进和EnvironmentFile权限用journalctl -u hermes-agent -n 50看日志Web UI 静态页面能打开但接口都挂Nginx 反代目标端口不对或 SELinux 拦截确认ss -tlnp的实际监听端口执行ausearch -m avc -ts recent查看 SELinuxAPI 请求返回 401Agent 与 Web UI 的密钥不一致检查两边的 Token 配置确保完全一致Web UI 刷新页面 404Nginxtry_files配置缺失修改 Nginx 配置加上try_files $uri $uri/ /index.html;这个速查表是我在实际运维中反复用到的几类问题基本上能覆盖自己部署时八成以上的状况。如果遇到表格里没有的情况不要慌先看journalctl -u hermes-agent -n 100和/var/log/nginx/error.log这两份日志能告诉你大部分答案。Rocky Linux 上部署 Hermes Agent 和 Hermes-Web-UI整体思路其实不复杂Agent 提供服务UI 套壳展示Nginx 做对外入口。每一步只要理解了为什么这样做排查问题时就有迹可循。我个人部署时比较看重的三个点一是权限隔离Agent 和 UI 都别用 root 跑二是 Selinux 保持开启遇到问题看审计日志而不是一关了之三是一切服务都要通过 systemd 托管确保重启后能自动恢复省得半夜服务器重启后服务全挂还要手动拉起。