Hermes Dashboard 配置手册

1. Dashboard 功能 YML 配置

环境变量

变量默认值说明
HERMES_DASHBOARD(未设置)设为 1 启用 s6 监督下的 dashboard 服务
HERMES_DASHBOARD_HOST0.0.0.0监听地址。bridge 网络下必须用 0.0.0.0 才能被 ghost_net 内其他容器访问
HERMES_DASHBOARD_PORT9119监听端口
HERMES_DASHBOARD_INSECURE(未设置)1 = 信任上游认证(nginx/oauth2-proxy),跳过 dashboard 自检;0/不设 = 开启自查模式,必须配 DashboardAuthProvider 否则拒绝启动
HERMES_DASHBOARD_TUI01 启用浏览器内嵌 CLI 终端(Chat 标签页)

INSECURE 参数本质

--insecure 是 Hermes dashboard 自身的 CLI 参数,语义是"我承认不安全,上游已认证"。s6 脚本:

case "${HERMES_DASHBOARD_INSECURE:-}" in
    1|true|TRUE|...) insecure="--insecure" ;;
    # =0 不匹配任何条件,等同于没设
esac
设值效果适用场景
HERMES_DASHBOARD_INSECURE=1--insecure,门禁关闭nginx + oauth2-proxy 已做认证,dashboard 信任上游
HERMES_DASHBOARD_INSECURE=0不传 --insecure,门禁开启需要 DashboardAuthProvider(如 Nous Portal OAuth),否则拒绝启动
不设=0同上

你的场景:nginx + oauth2-proxy 已在 nginx 层完成认证,dashboard 不需要再做一次,所以 =1 正确。

Docker Compose 配置

services:
  hermes-agent:
    image: nousresearch/hermes-agent:v2026.5.29.2
    command: gateway run
    environment:
      - HERMES_DASHBOARD=1
      - HERMES_DASHBOARD_TUI=1
      - HERMES_DASHBOARD_INSECURE=1
      - HERMES_DASHBOARD_HOST=0.0.0.0
    networks:
      - ghost_net

CLI 链路架构

┌────────────────────┐                        ┌──────────────────────┐                    ┌───────────────┐
│     Browser        │     WebSocket          │   Dashboard Server   │      PTY          │  Hermes TUI   │
│   Dashboard Tab    │ ─────────────────────> │    /api/pty          │ ────────────────> │   子进程      │
│   (xterm.js)       │ <───────────────────── │    port 9119         │ <──────────────── │  CLI 完整     │
│   WebGL 渲染       │   ANSI 输出流            │    s6 监督           │   ANSI 输出       │  slash命令    │
└────────────────────┘                        └──────────────────────┘                   └───────────────┘

说明:
  Chat 标签页 = 浏览器内完整 Hermes CLI
  HERMES_DASHBOARD_TUI=1 额外 fork 一个 hermes --tui PTY 子进程(约 +200MB 内存)
  Docker 镜像已预装 Node.js 22 + ptyprocess,开箱可用

2. OAuth 2.0 全链路配置

部署架构

所有容器在同一个 bridge 网络(ghost_net)内,Nginx 是唯一对外暴露点。容器间用容器名+端口互访,不设 ports 映射。

公网 → Nginx(Docker, 唯一暴露点443) ─ ghost_net ─┬─ hermes-agent:9119 (dashboard)
                                                 ├─ hermes-oauth:4180  (oauth2-proxy)
                                                 └─ 其他内部服务...

认证链路

┌──────────┐   HTTPS :443   ┌──────────┐   auth_request    ┌──────────────┐   HTTP    ┌────────────────┐
│ Browser   │ ─────────────> │  Nginx   │ ────────────────> │ oauth2-proxy │ ───────> │ Hermes Agent   │
│           │   (ghost_net)  │          │ <──────────────── │ :4180        │          │ Dashboard:9119 │
│           │               │          │  401 → /sign_in   │  + Google     │          │                │
│           │               │          │                   │   OAuth App   │          │                │
└──────────┘               └──────────┘                   └──────────────┘          └────────────────┘

流程:
  ① 用户访问 dashboard → nginx 触发 auth_request
  ② oauth2-proxy 检测无会话 → 302 重定向到 Google 登录
  ③ 用户在 Google 输入账号密码 → Google 回调 oauth2-proxy
  ④ oauth2-proxy 校验邮箱白名单 → 通过则设置会话 cookie
  ⑤ 后续请求 auth_request 通过 → nginx 透传到 dashboard:9119
  ⑥ dashboard 自身 INSECURE=1 → 信任上游,不再二次验证

变量来源对照

参数值来源说明
--client-idGoogle Cloud 创建 OAuth App 时提供格式 xxx.apps.googleusercontent.com
--client-secretGoogle Cloud 创建 OAuth App 时提供弹窗显示一次,立即保存
--cookie-secret自己生成python3 -c "import secrets,base64; print(base64.urlsafe_b64encode(secrets.token_bytes(32)).decode())"
--redirect-url你的域名格式 https://你的域名/oauth2/callback,必须与 Google Cloud 授权重定向 URI 一致
--upstream你的网络http://hermes-agent:9119(ghost_net 内部容器名互访)
--authenticated-emails-file你自己管理指向 emails.txt,加第二个人只改这个文件即可

前提:Google Cloud 注册 OAuth App

  1. 访问 https://console.cloud.google.com/apis/credentials
  2. 创建 OAuth 2.0 Client ID,应用类型 Web application
  3. 名称随意(如 "Hermes Dashboard")
  4. 授权重定向 URI:https://你的域名/oauth2/callback
  5. 点创建,复制 Client ID + Client Secret(只显示一次,立即保存)

Nginx 配置(Docker 内部)

server {
    listen 443 ssl;
    server_name hermes.atibm.com;

    ssl_certificate /etc/letsencrypt/live/atibm.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/atibm.com/privkey.pem;

    # 认证校验:请求先发给 oauth2-proxy(容器名互访)
    auth_request /oauth2/auth;
    error_page 401 = /oauth2/sign_in;

    # dashboard 转发
    location / {
        proxy_pass http://hermes-agent:9119;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;
    }

    # oauth2-proxy 回调端点(容器名互访)
    location /oauth2/ {
        proxy_pass http://hermes-oauth:4180;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Docker Compose 配置

services:
  hermes-agent:
    image: nousresearch/hermes-agent:v2026.5.29.2
    command: gateway run
    environment:
      - HERMES_DASHBOARD=1
      - HERMES_DASHBOARD_TUI=1
      - HERMES_DASHBOARD_INSECURE=1     # 信任上游 nginx 认证
      - HERMES_DASHBOARD_HOST=0.0.0.0
    networks:
      - ghost_net

  hermes-oauth:
    image: quay.io/oauth2-proxy/oauth2-proxy:latest-alpine
    container_name: hermes-oauth
    restart: unless-stopped
    networks:
      - ghost_net
    # 不设 ports:nginx 在同一网络,通过容器名 hermes-oauth:4180 访问
    volumes:
      - ./data/oauthemails.txt:/etc/oauth2-proxy/emails.txt:ro
    command:
      - --provider=google
      - --client-id=你的_CLIENT_ID
      - --client-secret=你的_CLIENT_SECRET
      - --cookie-secret=生成的32字节base64
      - --redirect-url=https://hermes.atibm.com/oauth2/callback
      - --upstream=http://hermes-agent:9119
      - --email-domain=*
      - --authenticated-emails-file=/etc/oauth2-proxy/emails.txt
      - --pass-authorization-header=true
      - --set-xauthrequest=true

networks:
  ghost_net:
    external: true

邮箱白名单文件 emails.txt

you@gmail.com
zhangsan@gmail.com

加第二个用户:只改 emails.txt 加一行邮箱即可,不需要去 Google Cloud 后台修改任何东西。第二个人用自己的日常 Google 账号登录,不需要是开发者。

重要说明

  • dashboard 无用户概念:不同用户登录后看到的是同一个 dashboard、同一份会话列表、同一个 Chat 终端。认证只解决"谁能进",不解决"谁做了什么"
  • oauth2-proxy 与 Hermes 内置 OAuth 门禁是不同层面的事:oauth2-proxy 在 nginx 层做认证拦截;HERMES_DASHBOARD_INSECURE=1 是 dashboard 信任上游不做二次检查。两者配合使用才是正确姿势
  • 容器名互访:nginx 在 ghost_net 内时,用 hermes-oauth:4180 而非 127.0.0.1:4180,不需要 ports 映射

3. API Server 功能 YML 配置

架构图

┌────────────────────┐   POST /v1/chat/completions   ┌────────────────────┐
│ 第三方前端           │ ────────────────────────────> │ Hermes Agent       │
│ Open Web UI        │   Authorization: Bearer ***    │ API Server         │
│ LobeChat           │ <──────────────────────────── │ port 8642          │
│ LibreChat          │   流式响应 + tool call 进度      │ 完整工具集          │
└────────────────────┘                               │ (终端/文件/搜索)     │
                                                     └────────────────────┘

环境变量

变量说明
API_SERVER_ENABLED=true启用 OpenAI 兼容 API
API_SERVER_KEY=your-api-keyBearer token 认证(必须)
API_SERVER_HOST默认 127.0.0.1,对外暴露需设为 0.0.0.0
API_SERVER_PORT默认 8642
API_SERVER_CORS_ORIGINS浏览器直连时必设,限制允许的来源

Docker Compose 配置

environment:
  - API_SERVER_ENABLED=true
  - API_SERVER_KEY=your-api-key
  # - API_SERVER_HOST=0.0.0.0   # 如需外部访问
  # - API_SERVER_CORS_ORIGINS=http://localhost:3000
  • 端口 8642,与 Dashboard 端口 9119 独立,互不依赖
  • API Server 不启动不影响 Dashboard 任何功能
  • API Server 暴露完整工具集(含终端),必须设置 API_SERVER_KEY