🐻 Hermes Agent 实战部署全记录

WSL2 + DeepSeek + Cloudflare Tunnel + 熊.online 完整部署 | v0.13.0 | 2026-05-14

📑 目录
  1. 环境准备与 WSL2 踩坑
  2. Hermes 安装与命令行配置
  3. DeepSeek API 接入
  4. 微信集成实战
  5. Dashboard 中文可视化
  6. SOUL 人格与工具优化
  7. 外网访问:Cloudflare Tunnel 血泪史
  8. DNS + API 配置关键步骤
  9. 网页聊天界面搭建
  10. 短链服务 (Shlink)
  11. 最终架构与经验总结

1. 环境准备与 WSL2 踩坑

1.1 初始环境

操作系统:Windows 11,WSL 功能未启用

关键发现:wsl.exe 存在但总是返回帮助信息 — 说明 Windows 功能未启用

解决:需要管理员权限运行 dism.exe /online /enable-feature

1.2 执行步骤

# 启用 WSL(需管理员权限)
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

# 重启电脑后
wsl --install -d Ubuntu    # 安装 Ubuntu
wsl --set-default-version 2  # 设 WSL2 为默认
💡 经验:Ubuntu 实际上早已安装(ERROR_ALREADY_EXISTS),只是从未启动过。用 wsl -l -v 发现状态为 "Stopped"。

1.3 最终环境

组件版本
Ubuntu (WSL2)26.04
Python3.14.4
Node.js22.22.2
uv (包管理器)0.11.14
Docker29.4.3
nginx1.28.3

2. Hermes 安装与命令行配置

2.1 安装路径选择

官方推荐:一键安装脚本 curl .../install.sh | bash

实际采用:手动 clone + uv 安装,更可控

cd ~ && git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent && uv sync && uv pip install -e ".[web]"

2.2 全局命令配置

⚠️ 踩坑:bash -c "hermes" 在非交互 shell 中 alias 不生效。必须创建 /usr/local/bin/hermes 脚本文件。
✅ 解决:从 Windows 端写入脚本文件(避免 CRLF 换行问题),复制到 WSL 的 /usr/local/bin/hermes

2.3 CRLF 换行噩梦

整个部署过程中反复遇到 \$'\r': command not found 错误。根源是 PowerShell 写入文件默认用 CRLF,WSL 需要 LF。

# PowerShell 侧统一使用这个模式
(Get-Content "file.sh" -Raw).Replace("`r`n","`n") | Set-Content "file_lf.sh" -NoNewline
wsl.exe cp /mnt/c/.../file_lf.sh /path/in/wsl/

3. DeepSeek API 接入

3.1 模型选择

为什么选 DeepSeek:国内直连速度快、价格极低(deepseek-chat ~¥1/百万token)、注册即送免费额度

可用模型:deepseek-chat / deepseek-reasoner / deepseek-v4-flash / deepseek-v4-pro

3.2 配置方式

# ~/.hermes/config.yaml
model:
  provider: deepseek
  default: deepseek-chat

# ~/.hermes/.env
DEEPSEEK_API_KEY=sk-xxxxx
DEEPSEEK_BASE_URL=https://api.deepseek.com

3.3 API Key 泄露事件

⚠️ 严重教训:微信扫码配置时,终端错误地将 DeepSeek API Key 输出到日志中! sk-26050...8673 在终端明文可见。立即删除旧 Key、创建新 Key、更新配置。
✅ 预防:配置阶段完成后立即检查终端日志是否有敏感信息泄露。

4. 微信集成实战

4.1 三种方案对比

方案难度适用关键配置
个人微信 (Weixin)个人使用扫码即连
企业微信 (WeCom)⭐⭐⭐团队Bot ID + Secret
WeCom 回调⭐⭐⭐⭐高级公网服务器

4.2 扫码流程

# 终端运行
hermes gateway setup
# 选择 Weixin / WeChat → Y 开始扫码
# 终端会输出二维码链接,复制到浏览器打开
# 微信扫码 → 确认登录
⚠️ 限制:这是 iLink Bot 身份(@im.bot),不是脚本化个人微信号。普通微信群无法邀请 Bot。群聊功能已禁用。

4.3 DM 策略建议

WEIXIN_DM_POLICY=allowlist           # 白名单模式(推荐)
WEIXIN_GROUP_POLICY=disabled          # 禁用群聊

5. Dashboard 中文可视化

5.1 启动命令

hermes dashboard --port 9119 --host 0.0.0.0 --no-open --insecure
⚠️ 注意:Dashboard 默认拒绝绑定 0.0.0.0(安全考虑),必须加 --insecure。但在 Cloudflare Tunnel + HTTPS 保护下是安全的。

5.2 中文切换

左下角 Switch to Chinese → 选择 简体中文。所有导航、配置页面立即中文化。

5.3 Dashboard 依赖

# 必须先安装 Web 依赖
uv pip install -e ".[web]"   # 安装 fastapi + uvicorn

6. SOUL 人格与工具优化

6.1 SOUL.md 人格配置

默认 SOUL.md 是英文的,需要用中文重写。关键指令:

6.2 优化的工具

优化项效果
DuckDuckGo 搜索免费网页搜索(要求安装 ddgs 包)
网关自启动~/.bashrc 添加 systemctl start hermes-gateway
浏览器工具agent-browser 可用,Playwright 暂不兼容 Ubuntu 26.04
时区设置Asia/Shanghai(影响 cron 和会话重置)

6.3 配置优化建议

agent.max_turns: 90        # 工具调用上限(探索场景可设 150+)
compression_threshold: 0.5 # 上下文压缩阈值
tool_progress_mode: all    # 工具进度显示模式

7. 外网访问:Cloudflare Tunnel 血泪史

💀 最艰难的环节!从国内到 Cloudflare 的网络连接极不稳定,经历了多次失败尝试。

7.1 尝试过的方法

方法结果原因
trycloudflare 临时 URL成功但 URL 随机变化
token 模式 + 自定义域名530/404QUIC 超时、路由未配置
cloudflared tunnel login失败cert.pem 始终无法写入
HTTP2 协议切换部分改善延迟降低但仍有超时
Nginx 反代 + token 模式成功需要额外配置

7.2 最终可行的方案

✅ 关键突破:使用 Cloudflare Global API Key 直接调 API 配置 Tunnel ingress,跳过了 cert.pem 依赖。
# API Key 格式(不是 Bearer Token)
curl -H "X-Auth-Email: [email protected]" -H "X-Auth-Key: cfk_xxxxx" \
  -X PUT ".../cfd_tunnel/TUNNEL_ID/configurations" \
  -d '{"config":{"ingress":[{"hostname":"hermes.熊.online","service":"http://localhost:8888"},...]}}'

7.3 架构决策

Nginx 反代层 (port 8888):

由于 token 模式 Tunnel 只能暴露一个 --url,用 Nginx 做统一入口:

/           → http://127.0.0.1:9119  (Dashboard)
/chat       → /var/www/chat          (聊天页面)
info子域名   → port 8889              (信息页)

8. DNS + API 配置关键步骤

8.1 Cloudflare API 认证差异

⚠️ 踩坑:Cloudflare 有两种 API Key 格式: 用错格式会报 "Invalid access token" 9109 错误。

8.2 关键 ID 获取

# Zone ID
curl "https://api.cloudflare.com/client/v4/zones?name=熊.online" \
  -H "X-Auth-Email: ..." -H "X-Auth-Key: ..."

# DNS 记录管理
curl "...zones/$ZONE/dns_records" -X POST -d '{"type":"CNAME","name":"hermes",...}'

# Tunnel ingress 配置
curl "...accounts/$ACCOUNT/cfd_tunnel/$TUNNEL/configurations" -X PUT -d '{...}'

8.3 Hermes API Server 启用

# ~/.hermes/.env
API_SERVER_ENABLED=true
API_SERVER_KEY=***REDACTED***
API_SERVER_HOST=0.0.0.0
API_SERVER_PORT=8642
# 重启网关
hermes gateway restart
✅ 验证:curl https://api.熊.online/v1/models -H "Authorization: Bearer ***REDACTED***" 应返回模型列表。

9. 网页聊天界面搭建

9.1 架构

纯前端 HTML 页面,直接调用 Hermes API Server 的 OpenAI 兼容接口。不需要后端服务器。

浏览器 → https://hermes.熊.online/chat (静态 HTML)
       → fetch('https://api.熊.online/v1/chat/completions', {
           headers: { 'Authorization': 'Bearer ***REDACTED***' },
           body: JSON.stringify({model:'deepseek-chat', messages:[...]})
         })

9.2 功能特性

9.3 接入其他前端

任何支持 OpenAI 兼容 API 的客户端都能接入:

客户端配置
ChatBoxAPI 地址填 https://api.熊.online/v1
LobeChat同上,Key 填 ***REDACTED***
NextChat可部署到 Cloudflare Pages

10.1 选型变化

方案结果
YOURLS + MySQL放弃 — 容器内 MySQL 连接过于复杂
Shlink (SQLite 内置)成功 — 一个容器搞定

10.2 部署命令

docker run -d --name shlink -p 8080:8080 \
  -e DEFAULT_DOMAIN=s.熊.online \
  -e INITIAL_API_KEY=abc123def456 \
  shlinkio/shlink:latest

10.3 API 使用

# 创建短链
curl -X POST https://s.熊.online/rest/v3/short-urls \
  -H "X-Api-Key: abc123def456" \
  -H "Content-Type: application/json" \
  -d '{"longUrl":"https://github.com/NousResearch/hermes-agent"}'

# 健康检查
curl https://s.熊.online/rest/v3/health

11. 最终架构与经验总结

11.1 完整架构图


                          ┌─────────────────────────┐
                          │     Cloudflare CDN       │
                          │  (DNS + Tunnel + HTTPS)  │
                          └───────────┬─────────────┘
                                      │
              ┌───────────────────────┼───────────────────────┐
              │                       │                       │
      hermes.熊.online          api.熊.online           s.熊.online
              │                       │                       │
      ┌───────┴───────┐       ┌───────┴───────┐       ┌───────┴───────┐
      │  Nginx :8888   │       │ Hermes :8642  │       │ Shlink :8080   │
      │  /     → :9119 │       │ (API Server)  │       │ (Docker)       │
      │  /chat → html  │       └───────┬───────┘       └───────────────┘
      └───────┬───────┘               │
              │               ┌───────┴───────┐
      ┌───────┴───────┐       │   DeepSeek    │
      │Dashboard :9119│       │   API (外部)   │
      │ info.熊.online│       └───────────────┘
      │   :8889       │
      └───────────────┘

11.2 子域名完整列表

地址端口服务
hermes.熊.online:8888→:9119Dashboard 管理面板
hermes.熊.online/chat:8888→静态AI 聊天网页
api.熊.online:8642OpenAI 兼容 API
s.熊.online:8080Shlink 短链
info.熊.online:8889部署总览文档

11.3 服务自启动状态

服务自启?启动方式
cloudflaredsystemd service
hermes-gatewaysystemd user + ~/.bashrc
nginxsystemd service
Docker (Shlink)Docker restart policy
Dashboard需手动启动
⚠️ WSL 重启后:大部分服务自动启动。Dashboard 需要手动运行:
hermes dashboard --port 9119 --host 0.0.0.0 --no-open --insecure

11.4 核心经验教训

1. CRLF vs LF

Windows + WSL 混用环境,所有脚本文件必须转换为 LF 换行。这是整个部署中最大的时间浪费源。

2. Cloudflare Tunnel 的坑

从国内连接 Cloudflare 极度不稳定(QUIC 超时、TCP 超时)。HTTP2 协议稍好。最终靠 API 直接配置 ingress 才解决。

3. Token vs Cert 模式

cloudflared tunnel login 需要浏览器回调下载 cert.pem,在 WSL 环境中几乎不可用。token 模式配合 API 直接配置是可行路径。

4. API Key 安全

DeepSeek Key 在微信配置时泄露到终端日志。配置完成后应立即检查并更换泄露的 Key。

5. Nginx 反向代理是关键

token 模式 Tunnel 只能暴露单个 --url。用 Nginx 做统一入口是必须的架构选择。

6. DNS 先于 Tunnel

CNAME 记录必须在 Tunnel ingress 配置之前添加。Tunnel ingress 配置好之后需重启 cloudflared 服务。

12. 网站优化:认证、API、短链修复 (2026-05-15)

12.1 问题背景

部署完成第二天,发现多个子站点存在问题需要修复:

站点问题原因
exp.熊.online弹窗要求用户名密码nginx auth_basic 未清理
info.熊.online弹窗要求用户名密码nginx auth_basic 未清理
api.熊.online访问显示裸 JSONAPI 端口无首页文档
s.熊.online404 + 短链不跳转无网页界面 + 域名错误

12.2 移除 HTTP Basic Auth

⚠️ 发现:exp 和 info 两个子站点弹出浏览器原生登录框,HTTP 响应头 WWW-Authenticate: Basic realm="Password"

排查过程

# 查看 HTTP 响应头确认认证类型
curl -I https://exp.熊.online
# → WWW-Authenticate: Basic realm="Password"

# 查看 nginx 配置
grep -r auth_basic /etc/nginx/sites-enabled/

根因:/etc/nginx/sites-enabled/expinfo 中配置了:

auth_basic "Password";
auth_basic_user_file /etc/nginx/.htpasswd;

早期测试时加的认证,部署完成后忘记清理。

✅ 修复:注释掉 auth 行并 reload nginx。
sed -i 's/^[[:space:]]*auth_basic/#auth_basic/' /etc/nginx/sites-enabled/exp
sed -i 's/^[[:space:]]*auth_basic_user_file/#auth_basic_user_file/' /etc/nginx/sites-enabled/exp
# info 同理
nginx -t && nginx -s reload

12.3 API 站点修复与文档页

架构发现

关键发现:cloudflared 使用 token 模式运行(--token 参数),本地 /root/.cloudflared/config.yml 完全被忽略。所有路由必须通过 Cloudflare Zero Trust 仪表板管理。

# 查看运行模式
ps aux | grep cloudflared
# → --token xxx  ← token 模式!

路由配置位置:Zero Trust → Networks → 连接器 → 个人 → 已发布应用程序路由

API 页面方案

需求:api.熊.online 打开后显示文档 + 在线测试界面,而非裸 JSON。

方案:新建 nginx 站点 :8092,/ 返回暗色主题 API 文档页,/v1/ 代理到 API Server :8642。风格与 exp/info 统一。

# /etc/nginx/sites-enabled/api (port 8092)
server {
    listen 8092;
    root /var/www/api;
    index index.html;
    location /v1/ {
        proxy_pass http://127.0.0.1:8642;
        proxy_set_header Host $host;
        proxy_buffering off;
        proxy_read_timeout 120s;
    }
    location = / {
        try_files /index.html =404;
    }
}

API 免认证决策

✅ 决策:流量已走 Cloudflare Tunnel + HTTPS,移除 Hermes API Server 的 Key 认证。
# ~/.hermes/.env
API_SERVER_KEY=          # 清空 = 允许无认证
API_SERVER_HOST=127.0.0.1 # 仅监听本地

12.4 短链服务 (s.熊.online) 修复

问题根因修复
首页 404Shlink 只有 API编写短链网页 (:8091)
短码跳转 404nginx 只代理 /rest/添加 location / → Shlink
生成短链 401请求无 API Key网页嵌入 Shlink Key
域名显示 localhostDEFAULT_DOMAIN 未设重建容器设 s.熊.online

Nginx 配置(位置优先级!)

server {
    listen 8091;
    location /rest/ { proxy_pass http://127.0.0.1:8080; }  # API
    location = /   { try_files /index.html =404; }          # 网页
    location /     { proxy_pass http://127.0.0.1:8080; }    # 跳转
}
⚠️ location 顺序:= /(精确)→ /rest/(前缀)→ /(通配)。顺序错了会导致 404。

Shlink 重建

docker stop shlink && docker rm shlink
docker run -d --name shlink --restart unless-stopped -p 8080:8080 \
  -e DEFAULT_DOMAIN=s.熊.online -e IS_HTTPS_ENABLED=true \
  shlinkio/shlink:latest
docker exec shlink shlink api-key:generate  # 重建后旧 Key 失效

12.5 最终服务映射

域名Tunnel →后端服务
熊.online:8891导航页
hermes.熊.online:8888/→:9119 Dashboard, /chat→html, /v1/→:8642
api.熊.online:8092/→API文档, /v1/→:8642
s.熊.online:8091/→网页, /rest/→:8080, /*→:8080跳转
exp.熊.online:8890本页
info.熊.online:8889总览

12.6 新增经验教训

7. 部署完≠能用

初版部署后每个站点都需要逐一浏览器验证。exp/info 的认证弹窗就是因为跳过了这一步。

8. Token 模式 Tunnel 的路由陷阱

cloudflared 有 config.yml 和 token 两种模式。token 模式下本地配置被忽略,必须在 Zero Trust 仪表板管理。改 config.yml 没用。

9. Nginx location 优先级

= /(精确)> ^~ /prefix/ > /regex/ > /(通配)。静态页用精确匹配保证不被 API 代理吞掉。

10. Docker 参数要一次到位

Shlink 的 DEFAULT_DOMAIN 创建即固定。重建 = 丢失数据。生产环境先规划参数。

11. API 需要人类可读首页

API 端点返回 JSON 正确,但 api.域名 根部应有文档页面——否则用户打开就是一脸懵的 JSON。