Hermes Web UI 外网访问与 Android App 连接:ngrok 反向隧道实战
文章目录
1:结论与适用范围
这篇文章记录一次在 Windows + WSL2 环境中,将本机 Hermes Web UI 通过 ngrok 发布为 HTTPS 地址,并用 Android 的 Hermes Agent WebUI App 连接访问的完整过程。
最终结构如下:
| |
这个方案的特点:
- 不需要公网 IPv4、路由器端口映射或自购域名;
- 本机主动向 ngrok 云端发起 HTTPS 出站连接;
- 手机可通过普通 HTTPS URL 访问;
- Hermes Web UI 保持绑定在
127.0.0.1,不直接暴露8648; - Android App 可作为 WebView 容器访问 Web UI;
- 最终只使用 Hermes Web UI 自身的 token 登录,不再叠加 ngrok OAuth 或 Basic Auth。
本文适合个人远程管理 Hermes。Hermes 具备本机工具调用能力,不应把数据库、SSH、券商接口、OEMS/FIX/SBL/LMS 等端口通过 ngrok 一并发布。
2:先理解:Tailscale、ngrok 与 FRP 的选择
| 方案 | 是否公网可访问 | 是否需手机 App | 是否需要 VPS | 本次用途 |
|---|---|---|---|---|
| Tailscale Serve | 否,仅 tailnet | 是 | 否 | 安全性最佳,适合本人设备访问 |
| ngrok HTTP Tunnel | 是,HTTPS URL | 否,浏览器/App 都可 | 否 | 本次采用,部署最快 |
| FRP | 是 | 否 | 是,需公网 frps | 长期自建、可控性更高 |
| Cloudflare Tunnel + Access | 是,但可加身份网关 | 否 | 否 | 长期公网入口的优选方案 |
如果只是本人手机访问,优先考虑 Tailscale;如果希望 Android App 或普通浏览器直接填 HTTPS 地址,ngrok 的接入成本更低。
3:前置条件
3.1 Hermes Web UI 必须只监听 localhost
本次环境中,Web UI systemd 服务明确绑定:
| |
检查命令:
| |
预期看到类似:
| |
不要为了手机访问把 Web UI 改成 0.0.0.0:8648;ngrok 可以直接代理 127.0.0.1:8648。
3.2 ngrok 账户与专用 Authtoken
- 注册/登录 ngrok Dashboard;
- 在 Dashboard 创建一个专用于此 WSL 的 Authtoken;
- 不要把 Authtoken 写入 Git、Markdown、聊天记录或 shell history;
- 为了降低凭据泄露影响,一台机器使用一个独立 token。
ngrok 的工作模式是:Agent 从 WSL 主动连接到 ngrok 云端的 443 端口,ngrok 再将公网 HTTPS 请求通过加密隧道转回本机。因此不需要开放家庭路由器端口。
4:安装 ngrok Agent
Ubuntu/WSL 可通过 ngrok 官方 APT 源安装:
| |
安装后应能看到 ngrok version 3.x。
5:以低权限 systemd 服务运行 ngrok
不建议用 root 直接在终端长期执行:
| |
原因包括:进程断开后隧道消失、缺少开机重启、凭据边界不清晰、日志不便于审计。
5.1 创建专用账户与目录
| |
Authtoken 单独保存在受限文件中。下面命令不会把 token 写入 shell history:
| |
文件权限应为:
| |
5.2 ngrok service 文件
创建 /etc/systemd/system/ngrok-hermes.service:
| |
其中:
User=ngrok-agent:Agent 无登录 shell,降低被利用后的权限范围;http://127.0.0.1:8648:隧道只连接 Web UI 的 localhost 地址;--inspect=false:关闭 Agent 本地 HTTP Inspector;Restart=on-failure:网络短暂中断后由 systemd 自动拉起;ConditionPathExists:没有 Authtoken 时服务不启动。
当前不需要在 ngrok 层做 OAuth 或 Basic Auth,可使用最小策略文件:
| |
启动并设为开机自启:
| |
日志中会出现类似:
| |
该 HTTPS 地址就是手机端要填写的服务器 URL。
6:验收与日常检查
6.1 服务检查
| |
应满足:
| |
6.2 查看当前公网 URL
ngrok Agent 运行时,在本机 127.0.0.1:4040 提供状态 API:
| |
该端口只监听 localhost,不应发布到公网。
6.3 公网与内建认证检查
| |
最终设计中:
- 首页和静态资源可被 ngrok 公网访问;
- Web UI API 仍由 Hermes Web UI 内建
Authorization: Bearer <token>保护; - App/浏览器首次连接后,会进入 Hermes Web UI 自己的 token 登录流程。
Hermes Web UI 的内建认证是 token/Bearer 认证,并非单独的 username/password 表单。不要把 Web UI token 发到聊天或提交到仓库。
7:Android Hermes Agent WebUI App 连接
Android App:
| |
配置步骤:
安装 App 并允许网络访问;
新增 Server Profile;
填写 ngrok 返回的 HTTPS URL,例如:
1https://<随机子域>.ngrok-free.dev/连接成功后,在 Hermes Web UI 内输入 token;
进入聊天页后测试新建会话、发送文本、上传文件等功能。
Android App 是 WebView 容器,并不自带 Hermes 模型、Gateway 或服务器;实际执行仍发生在 WSL 的 Hermes runtime。
8:为什么最终不使用 ngrok OAuth / Basic Auth
理论上,ngrok 可以在外层添加 OAuth 或 HTTP Basic Auth。但与当前 Android Hermes App 和 Hermes Web UI 的组合存在两个重要兼容性问题。
8.1 ngrok OAuth:ERR_NGROK_3303
外层 Google OAuth 的跳转大致为:
| |
Android App 对“可信 Hermes Host”与外部浏览器/Custom Tab 有导航隔离。OAuth 开始和回调若不在同一 cookie/session 容器中,ngrok 会报:
| |
手机 Chrome 中能成功,并不表示 App WebView 一定也能成功。
8.2 ngrok Basic Auth:登录后重复弹框
Basic Auth 使用:
| |
而 Hermes Web UI 在登录后调用 API 使用:
| |
若对所有 ngrok 路径强制 Basic Auth,则前端进入聊天页后的 /api/... 请求会带 Bearer header;ngrok 不会将它视为 Basic Auth,会返回 401 和 WWW-Authenticate。Android/WebView 会因此持续弹出用户名密码框。
即使只对部分路径加 Basic Auth,也可能被 SPA 路由、后台资源、流式请求或刷新流程触发。为了避免两个认证系统抢占同一个 Authorization header,本次最终选择:
| |
这个选择改善了 Android App 兼容性,但意味着公网首页可被访问。因此 Web UI token 必须保密,且不应把 ngrok URL 广泛传播。
9:Android 麦克风与 STT 设置
9.1 报错:STT settings are required for provider openai
手机 App 点击麦克风后,如果看到:
| |
说明:
| |
这不是 ngrok、Android 麦克风权限或 Hermes Gateway 连接故障。
一个容易忽略的点:Hermes Agent 的 /root/.hermes/config.yaml 中即使已有 stt: 配置,Hermes Web UI 仍维护一套自己的 profile 级 STT 设置。两者不是同一份配置。
9.2 推荐模型:gpt-transcribe
对于 Android App 当前的模式——录完一段音频,再上传文件获取全文——推荐:
| |
理由:
- OpenAI 当前对“已完成录音/文件转写”建议优先使用
gpt-transcribe; gpt-live-transcribe是持续实时音频流、实时字幕/电话场景的模型,不是本 App 当前一次上传一段录音的首选;gpt-4o-transcribe可作为较高质量的兼容替代;gpt-4o-mini-transcribe适合希望降低成本、频繁短语音输入的场景;whisper-1是较旧的兼容兜底,不是当前“最高质量”选择。
在 Web UI 的 STT 设置页中填入 OpenAI 可用 API Key、https://api.openai.com/v1(或实际 OpenAI-compatible 语音转写网关)及上述模型后,保存并执行一次测试转写。
如经常出现量化交易术语、中英混合名称,可增加提示词:
| |
不要把 API Key 写入本文、截图或 Git 仓库。
10:常见故障排查
| 现象 | 根因 | 处理方式 |
|---|---|---|
ERR_NGROK_3200 / endpoint offline | ngrok Agent 未运行或启动失败 | systemctl status ngrok-hermes.service,查看 journal |
ERR_NGROK_2237 | Basic Auth 密码低于 ngrok 最低 8 位要求 | 使用至少 8 位密码;本方案已不使用 Basic Auth |
ERR_NGROK_3303 | ngrok OAuth state cookie 在 WebView/浏览器间丢失 | 不在 Android App 里使用 ngrok OAuth;改用 Web UI 内建 token 或 Tailscale |
| 登录后不断弹 Basic Auth 框 | ngrok Basic Authorization 与 Hermes Bearer Authorization 冲突 | 移除 ngrok Basic Auth |
| 页面能打开,聊天/API 401 | Hermes Web UI token 未填写或已失效 | 在 Web UI 登录页重新输入 token,必要时刷新 App 缓存 |
麦克风报 STT settings are required | Web UI 的 profile 级 STT 未配置 | 在 Web UI 的 STT 设置中保存 provider/model/key/base URL |
ngrok 日志有短暂 EOF、heartbeat 或 DNS 超时 | 网络短抖动 | 确认 systemd Restart=on-failure,等待 Agent 自动重连;重连后检查 URL |
127.0.0.1:8648 connection refused | Hermes Web UI 重启中或异常 | systemctl status hermes-web-ui.service,检查 /root/.hermes-web-ui/logs/server.log |
常用排障命令:
| |
11:安全边界与后续建议
本次方案已经满足“手机 App 远程操作 Hermes”的目标,但风险边界需要明确:
- ngrok URL 是公网地址。 不要在公开群、截图或文章中暴露当前实际 URL;
- 不要映射 Hermes Gateway
8642、SSH、数据库、KDB、Redis、券商或交易系统端口; - Web UI token 是关键门禁,泄露后应立即更换并重启 Web UI;
- 只以低权限
ngrok-agent账户运行 Agent; - 定期查看 ngrok、Web UI 与 Gateway 日志;
- 如果后续只供本人设备使用,迁移到 Tailscale Serve 可进一步缩小公网暴露面;
- 若未来需要长期固定域名、多人受控访问,应优先评估 Cloudflare Tunnel + Cloudflare Access,而不是无保护地扩展 ngrok 公网入口。
12:参考资料
文章作者 lucas(lpp)
上次更新 2026-08-06