Skip to content

Hermes WebUI & Dashboard 部署方案

一、架构总览

                                    Internet
                                        │
                         ┌──────────────┴──────────────┐
                         │                             │
                         ▼                             ▼
              ┌─────────────────────┐     ┌─────────────────────────┐
              │ hermes.wonius.top   │     │  db.hermes.wonius.top   │
              └──────────┬──────────┘     └────────────┬──────────────┘
                         │                             │
                     Caddy :443                       │
              ┌──────────┴──────────┐                  │
              │                     │                  │
              ▼                     ▼                  ▼
    ┌─────────────────┐   ┌─────────────────┐  ┌──────────────────────┐
    │ hermes-webui    │   │ hermes-auth-    │  │  hermes-dashboard    │
    │ :8787           │   │ proxy :9118      │  │  :9119               │
    │                 │   │                 │  │                      │
    │ 自带认证模块      │   │ 独立认证层      │  │  无内置认证           │
    │ api/auth.py     │   │ + 反向代理       │  │                      │
    │ 认证状态: 未启用   │   │ 密码: Iron2026! │  │                      │
    └─────────────────┘   └────────┬─────────┘  └──────────────────────┘
                                  │ 无认证
                                  └──────────→ (直接代理转发)

关键点:所有服务均运行在同一台服务器,监听 127.0.0.1,仅 Caddy(:443)对公网暴露。


二、组件说明

2.1 hermes-webui(:8787)

进程

/root/.hermes/hermes-agent/venv/bin/python /root/.hermes/hermes-webui/server.py

作用:Hermes Agent 的主 Web 管理界面,提供会话管理、配置、API Keys 等功能。

认证状态:内置 api/auth.py 认证模块(Cookie Session,PBKDF2 + HMAC),但当前未启用

未启用原因: - 环境变量 HERMES_WEBUI_PASSWORD 未设置 - settings.json 中无 password_hash - is_auth_enabled() 返回 Falsecheck_auth() 直接放行

当前任何人都可以直接访问 https://hermes.wonius.top 完整界面。

Caddy 配置

hermes.wonius.top {
    root * /usr/share/caddy
    reverse_proxy localhost:8787
}

注:root 指令在仅有 reverse_proxy 时不产生实际作用(无 file_server),保留仅供将来扩展静态托管。

WebUI 路由说明: - 静态资源(/static/*):Python server.py 自己处理,不走 Caddy - 动态路由(/, /login, /api/*):由 routes.pyhandle_get / handle_post 处理


2.2 hermes-dashboard(:9119)

进程

/root/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main dashboard \
    --host 127.0.0.1 --port 9119 --insecure --no-open

作用:Hermes Agent 轻量 Web Dashboard,提供配置、API Keys、会话管理界面。

认证状态无内置认证(独立服务,无 api/auth.py 模块)。

→ 为保护敏感信息,通过 hermes-auth-proxy 在外层增加独立认证层。

访问方式https://db.hermes.wonius.top(必须通过认证)


2.3 hermes-auth-proxy(:9118)

进程/usr/bin/python3 /root/.hermes/auth_proxy.py(systemd 管理)

服务文件/etc/systemd/system/hermes-auth-proxy.service

作用: 1. 为 hermes-dashboard 提供独立的认证层(Cookie Session) 2. 作为反向代理,将认证后的请求转发给 :9119

认证机制

项目
密码 Iron2026!
密码存储 /root/.hermes/auth_proxy.pass(PBKDF2-SHA256,60万次迭代)
签名密钥 /root/.hermes/auth_proxy.key(secrets.token_urlsafe(64),自动生成)
Cookie 名称 hermes_auth
Cookie 有效期 12 小时
Cookie 安全属性 HttpOnly + Secure + SameSite=Lax
防暴力破解 同一 IP 60 秒内最多 5 次尝试

Session Cookie 格式user|timestamp|hmac_sha256_signature - 签名内容:f"{user}|{ts}",用 SECRET_KEY 生成 HMAC-SHA256,取前 32 字符

Caddy 配置

db.hermes.wonius.top {
    reverse_proxy localhost:9118
}


三、Caddy 配置

文件/etc/caddy/Caddyfile

{
    email "admin@wonius.top"
}

hermes.wonius.top {
    root * /usr/share/caddy
    reverse_proxy localhost:8787
}

db.hermes.wonius.top {
    reverse_proxy localhost:9118
}

两个域名共用同一个 Caddy 进程,各自独立反向代理。


四、认证流程详解

4.1 WebUI(理论认证流程,当前未启用)

用户请求 ──→ check_auth()
                │
                ├─ path 在 PUBLIC_PATHS?
                │     PUBLIC_PATHS = {
                │       /login, /health, /favicon.ico,
                │       /api/auth/login, /api/auth/status, /static/*
                │     }
                │     → 是:放行
                │     → 否:检查 hermes_session cookie
                │
                ├─ cookie 无效或缺失?
                │     → API 路径:返回 401 JSON
                │     → 页面路径:302 重定向到 /login
                │
                └─ POST /api/auth/login
                      → verify_password() 验证 PBKDF2
                      → 有效:create_session() 生成签名 cookie

4.2 Dashboard(auth_proxy 认证流程)

用户请求 https://db.hermes.wonius.top/
    │
    ├─ GET / ──────────────────────────────────────────────┐
    │    ├─ 有有效 hermes_auth cookie?                    │
    │    │    → 是:proxy GET / 到 dashboard (:9119)      │
    │    │         返回 Dashboard HTML                     │
    │    │    → 否:serve_login() 返回自定义登录页          │
    │    └─ /assets/*, /_next/* 静态资源?                 │
    │         → 直接 proxy 转发(无需认证)                 │
    │                                                      │
    ├─ POST /login ───────────────────────────────────────┐
    │    ├─ 超过速率限制?                                 │
    │    │    → 429 Too Many Requests                     │
    │    │                                                │
    │    ├─ 密码错误?                                     │
    │    │    → 401 + {"detail":"Invalid credentials"}    │
    │    │                                                │
    │    └─ 密码正确?                                     │
    │         → PBKDF2 验证通过                            │
    │         → sign("admin", unix_timestamp) 生成 cookie │
    │         → proxy GET / 到 dashboard (:9119)           │
    │         → 在响应中注入 Set-Cookie: hermes_auth=...  │
    │         → 浏览器收到 Dashboard HTML + 保存 Cookie     │
    │                                                      │
    └─ 其他请求 ──────────────────────────────────────────┐
         ├─ 无效 cookie → 401 Unauthorized                 │
         └─ 有效 cookie → proxy 到 :9119                  │

五、文件清单

文件路径 说明
/etc/caddy/Caddyfile Caddy 反向代理配置
/root/.hermes/auth_proxy.py 独立认证代理(含登录页、反向代理)
/root/.hermes/auth_templates/login.html 登录页 HTML 模板
/root/.hermes/auth_proxy.key HMAC 签名密钥
/root/.hermes/auth_proxy.pass PBKDF2 密码哈希
/root/.hermes/start-dashboard.sh Dashboard 启动脚本
/etc/systemd/system/hermes-auth-proxy.service auth_proxy systemd 服务
/etc/systemd/system/hermes-dashboard.service dashboard systemd 服务
/root/.hermes/hermes-webui/server.py WebUI 主进程
/root/.hermes/hermes-webui/api/auth.py WebUI 内置认证模块(未启用)
/root/.hermes/hermes-webui/api/routes.py WebUI 路由处理

六、运维命令

# 查看 auth_proxy 日志
tail -f /var/log/hermes-auth-proxy.log

# 查看 dashboard 日志
tail -f /var/log/hermes-dashboard.log

# 重启 auth_proxy
sudo systemctl restart hermes-auth-proxy

# 重启 dashboard
sudo systemctl restart hermes-dashboard

# 重载 Caddy 配置
sudo systemctl reload caddy

# 查看各服务运行状态
systemctl status hermes-auth-proxy hermes-dashboard caddy

# 手动测试(绕过 auth_proxy 直接访问 dashboard)
curl http://127.0.0.1:9119/

# 手动测试 auth_proxy
curl http://127.0.0.1:9118/

七、已知问题

7.1 curl -sI(HEAD 请求)返回 502

现象curl -sI https://db.hermes.wonius.top/ 返回 502 EOF

原因hermes-auth-proxy 基于 Python BaseHTTPRequestHandler,urllib 代理 HEAD 请求时,hermes-dashboard 返回空 body,Caddy 无法确定响应结束边界,导致 EOF。

影响范围:仅影响 curl -I / curl --head 命令,不影响真实浏览器。

状态:暂不修复。

7.2 WebUI 无认证保护

https://hermes.wonius.top 当前无任何认证,任何人可直接访问完整界面(含会话、配置内容)。

建议后续方案(二选一): 1. 设置 HERMES_WEBUI_PASSWORD 环境变量,启用 webui 内置认证 2. 在 Caddy 层为 hermes.wonius.top 增加 basicauth 指令


八、方案对比

hermes-webui (:8787) hermes-dashboard (:9119)
Caddy 配置 reverse_proxy :8787 reverse_proxy :9118 (auth_proxy)
认证模块 api/auth.py(存在,但未启用) 独立 auth_proxy.py(已启用)
认证方式 Cookie Session(PBKDF2 + HMAC) Cookie Session(PBKDF2 + HMAC)
登录页面 WebUI 自带(多语言) 自定义 login.html
外网访问 https://hermes.wonius.top https://db.hermes.wonius.top
状态 ⚠️ 无认证保护 ✅ 有认证保护