背景:自带的 UI 太丑了

Hermes Agent 是我目前在一台 Ubuntu 服务器上跑的主力 AI Agent,功能很强大,但官方 Dashboard(:9119)的界面实在让人提不起兴致——本质上就是一个 xterm.js 终端嵌套,操作全靠 TUI 命令。能用,但谈不上好用。

于是开始调研社区有没有更好的 Web 前端。最终锁定了 hermes-webui 这个项目,它提供了原生 Web 聊天界面、Markdown 渲染、代码高亮、流式输出、会话管理、文件浏览、可视化配置等一整套现代体验。

这篇文章记录从调研到部署的完整过程,包括踩过的坑。


hermes-webui 是什么

hermes-webui 是 Hermes Agent 生态中最成熟的社区 WebUI 项目,提供完整的浏览器聊天界面,替代官方 Dashboard。

属性
项目地址nesquena/hermes-webui
Docker 镜像ghcr.io/nesquena/hermes-webui:latest
当前版本exp-v0.52.264
技术栈Python 3.12 + vanilla JS(无 React/Vue/Node 构建)
服务端口8787
许可证开源

为什么选它:功能对比

和官方 Dashboard 相比,hermes-webui 几乎是全方位的升级:

功能官方 Dashboard (:9119)hermes-webui (:8787)
聊天界面xterm.js 嵌套 TUI(终端风格)原生 Web 聊天(Markdown 渲染、代码高亮、流式输出)
会话管理无(依赖 TUI 命令)侧边栏列表、搜索、分组、项目归类
文件浏览三栏布局含 workspace 文件树
配置管理无(需 CLI)可视化设置面板
模型切换TUI /model 命令下拉选择器
Profile 管理TUI 命令可视化切换
Skills/MCPTUI overlay可视化面板
定时任务CLI 命令可视化管理
移动端不支持PWA 支持
主题多主题 + 深色模式
认证HTTP Basic Auth密码 + Passkey + OIDC

和 Hermes Studio 的区别

之前也评估过另一个项目 Hermes Studio,但最终放弃了:

维度hermes-webuiHermes Studio
定位Hermes Agent 的 Web 前端多 Agent 工作台平台
架构Python 单进程Vue + Koa + SQLite monorepo
Agent 运行时复用官方 HermesHermes + Ekko + Claude Code + Codex + Pi
对 ~/.hermes 的侵入新建 webui/ 子目录,不修改现有文件自动注入 MCP 配置、root 权限写文件
Gateway 冲突无(不启动自己的 Gateway)启动独立 Gateway,PID/Lock 冲突
决策推荐使用已放弃

Hermes Studio 的问题在于它太重了——启动独立 Gateway 会和已有的 Agent 冲突,还会自动注入 MCP 配置。hermes-webui 则轻量得多,只作为前端存在,聊天请求转发给现有 Gateway 处理。


对现有 Agent 的影响

这是我最关心的问题:装个新前端,会不会影响已经在跑的 Agent?

数据架构

~/.hermes/                          ← 现有 Agent 数据(不被修改)
├── config.yaml                     ← WebUI 读取;用户改设置时才写入
├── state.db                        ← WebUI 以 read-only 打开
├── gateway.pid / gateway.lock      ← WebUI 不触碰
├── sessions/                       ← Agent 原生会话(不触碰)
├── skills/                         ← 共享读取
├── memory/                         ← 共享读取
└── webui/                          ← 【新建】WebUI 专属目录
    ├── sessions/                   ← WebUI 会话 JSON sidecar
    ├── settings.json               ← WebUI 设置
    ├── workspaces.json             ← 已注册的 workspace
    └── projects.json               ← 会话项目分组

影响矩阵

操作Gateway 模式(推荐)In-process 模式
读取 config.yaml只读只读
读取 state.dbread-only 连接read-only 连接
写入 state.db不写入写入(标记 source=webui)
启动 Gateway 进程不启动不启动
占用 8642 端口不占用(连接现有 Gateway)不占用
修改现有会话不修改不修改

结论:Gateway 模式下对现有 Agent 几乎零影响。WebUI 只读取共享数据,聊天请求转发给现有 Gateway。不会启动新的 Gateway,不会冲突 PID/Lock 文件,不会修改已有会话。


部署方案

架构概览

                  Ubuntu Server (内网)
┌─────────────────────────────────────────────────────┐
│                                                     │
│  Native systemd                                     │
│  ┌──────────────────────────────────┐               │
│  │  hermes-gateway.service          │               │
│  │  端口: 127.0.0.1:8642 (API)      │               │
│  │  数据: ~/.hermes/                │               │
│  └──────────────────────────────────┘               │
│  ┌──────────────────────────────────┐               │
│  │  hermes-dashboard.service        │               │
│  │  端口: 0.0.0.0:9119 (官方 Dashboard) │           │
│  └──────────────────────────────────┘               │
│                    ▲                                │
│                    │ HTTP 127.0.0.1:8642            │
│  Docker (host 网络模式)                              │
│  ┌─────────────────┴────────────────┐               │
│  │  hermes-webui 容器               │               │
│  │  端口: 0.0.0.0:8787              │               │
│  │  CHAT_BACKEND=gateway            │               │
│  │  GATEWAY_BASE_URL=               │               │
│  │    http://127.0.0.1:8642         │               │
│  │  挂载: ~/.hermes (共享数据)       │               │
│  └──────────────────────────────────┘               │
│                                                     │
└─────────────────────────────────────────────────────┘

核心设计:使用 network_mode: host 而非 bridge 网络。原因是 Gateway 仅监听 127.0.0.1:8642,bridge 模式下容器通过 host.docker.internal (172.17.0.1) 无法访问。host 模式下容器直接共享宿主机网络栈,可直接访问 127.0.0.1:8642

前置条件

  1. Gateway API Server 已启用 — 8642 端口在监听,API_SERVER_KEY 已配置
  2. Docker 已安装 — Docker 29.7.2 + Compose v5.5.0
  3. 防火墙放行 8787 端口 — 服务器启用了 UFW(默认策略 DROP),必须显式放行

部署步骤

# 1. 创建部署目录
mkdir -p ~/hermes-webui && cd ~/hermes-webui
 
# 2. 准备配置文件
cp <你的仓库路>/docker-compose.yml ~/hermes-webui/
cp <你的仓库路>/.env.example ~/hermes-webui/
cp .env.example .env
# 编辑 .env,填入 API_SERVER_KEY、HERMES_WEBUI_PASSWORD、UID/GID
 
# 3. 拉取镜像(~750MB,首次约 1-2 分钟)
docker compose pull
 
# 4. 防火墙放行
sudo ufw allow 8787/tcp comment 'Hermes WebUI'
 
# 5. 启动
docker compose up -d
 
# 6. 等待初始化(首次启动需安装 agent 依赖,约 1-2 分钟)
docker logs -f hermes-webui
# 看到 "Hermes Web UI listening on http://0.0.0.0:8787" 即启动成功
 
# 7. 验证
curl -s http://localhost:8787/health | python3 -m json.tool

配置文件说明

docker-compose.yml 关键设计

  • 网络模式network_mode: host,容器直接使用宿主机网络栈
  • 挂载 ~/.hermes:共享 config.yaml、skills、memory 等;WebUI 数据写入 ~/.hermes/webui/
  • CHAT_BACKEND=gateway:聊天由现有 Gateway 处理,WebUI 不运行 Agent runtime
  • 密码保护:端口暴露在 0.0.0.0,必须设密码
  • 资源限制:1GB 内存上限,防止影响 Agent 主进程

必须配置的环境变量

变量说明示例
API_SERVER_KEYGateway API Key(>=16 字符,需与 Gateway 一致)a1b2c3d4e5f6g7h8...
HERMES_WEBUI_PASSWORDWebUI 访问密码your-strong-password
UID / GID宿主机用户 UID/GID1000 / 1000

密码配置位置(易混淆)

WebUI 密码不在 ~/.hermes/.env 里。 两套认证各管各的:

服务配置文件变量名端口
官方 Dashboard~/.hermes/.envHERMES_DASHBOARD_BASIC_AUTH_PASSWORD9119
hermes-webui~/hermes-webui/.envHERMES_WEBUI_PASSWORD8787

使用体验

首次访问

  1. 浏览器打开 http://<服务器IP>:8787
  2. 输入密码(注意是 ~/hermes-webui/.env 中的 HERMES_WEBUI_PASSWORD,不是 Dashboard 密码)
  3. 进入聊天界面,左侧显示会话列表(包括 CLI/TUI 历史会话,只读)

日常操作

操作方法
新建对话点击侧边栏 ”+” 或快捷键
切换模型聊天区顶部模型选择器
查看历史侧边栏会话列表(WebUI + CLI/TUI 会话均可见)
文件浏览右侧 workspace 面板
修改设置左下角设置按钮 → Control Center
管理 SkillsControl Center → Skills 面板
管理 MCPControl Center → MCP 面板

和官方 Dashboard 的关系

两者可以同时运行、互不干扰:

界面URL用途
官方 Dashboardhttp://<服务器IP>:9119TUI 终端体验、系统监控
hermes-webuihttp://<服务器IP>:8787现代 Web 聊天界面、文件浏览、可视化管理

踩坑记录

1. bridge 网络无法访问 Gateway

Gateway 绑定 127.0.0.1:8642,Docker bridge 网络中容器通过 host.docker.internal (172.17.0.1) 访问会被拒绝。

解决:改用 network_mode: host

2. UFW 防火墙未放行 8787 端口

容器正常运行、端口正常监听,但其他节点浏览器访问超时 (ERR_CONNECTION_TIMED_OUT)。

原因network_mode: host 时 Docker 不自动管理 iptables 规则(与 bridge 模式不同),需要手动在 UFW 中放行端口。9119 端口在部署 Dashboard 时已放行,但部署 WebUI 时遗漏了 8787。

修复

sudo ufw allow 8787/tcp comment 'Hermes WebUI'

3. 首次启动慢

容器首次启动需要 uv pip install hermes-agent 的 Python 依赖(约 100 个包),耗时 1-2 分钟。期间 /health 端点不可用。后续重启不需要重新安装。

4. dashboard-auth-basic 警告

启动日志中出现的 dashboard-auth-basic 警告来自 ~/.hermes/.env 中的 Dashboard Basic Auth 配置,与 WebUI 无关,可以安全忽略。

5. WebUI 显示旧会话但无法继续对话

WebUI 以 read-only 模式读取 state.db 中的 CLI/TUI 会话,这些会话无法在 WebUI 中继续。在 WebUI 中新建会话即可开始对话,历史会话仅供查看。


回退方案

如果哪天不想要了,清理也很干净:

# 1. 停止并删除容器
cd ~/hermes-webui && docker compose down
 
# 2. 删除 WebUI 专属数据
rm -rf ~/.hermes/webui/
 
# 3. 可选:删除 Docker 镜像
docker rmi ghcr.io/nesquena/hermes-webui:latest
 
# 4. 可选:删除部署目录
rm -rf ~/hermes-webui/

临时停用更简单:docker compose stop,恢复时 docker compose start,数据完整保留。


已知限制

限制说明影响
Gateway 模式功能不完整附件上传、工具审批等功能需额外配置核心聊天不受影响
版本耦合WebUI 镜像内置的 agent 版本需与本地 Agent 兼容升级时需注意同步
config.yaml 写入在 WebUI 中修改设置会写入共享的 config.yamlCLI/TUI 会同步看到变化

总结

hermes-webui 的部署比预期顺利——Docker 单容器 + Gateway 模式 + host 网络,对现有 Agent 几乎零影响。界面从”终端嵌套”升级到”现代 Web 聊天”,日常使用体验提升巨大。

最关键的是回退成本极低:WebUI 的所有数据都在 ~/.hermes/webui/ 下,删掉这个目录就等于什么都没装过。对于这种”锦上添花”的组件,低侵入性比功能丰富更重要。


参考资料