需求与目标(从用户体验出发)
我在 EC2 上部署 OpenClaw 时,发现要访问聊天页面往往需要输入一串带参数的 URL(/chat?session=...&token=...),不够“人类友好”。
现在希望在 Windows 本地环境也实现同样的体验:
- 直接访问:
http://localhost:18789 - 自动进入聊天页面(自动拼好
session和token) - WebSocket 长连接不掉(不能出现 1006/1008 等断开)
- 并且 nginx 能像 openclaw gateway 一样开机自动启动
结论先行:
- 18790:OpenClaw Gateway(上游,仅本机)
- 18789:Nginx 入口(对外访问)
- 通过 nginx 对根路径
/进行“HTTP/WS 分流”,并配置 gateway 允许从 18789 origin 访问(否则会pairing required)。
总体架构
为什么要拆成两个端口?
最直观的做法是让 OpenClaw Gateway 直接监听 18789,然后在 Gateway 内部做跳转。但这样会遇到两个现实问题:
- 端口职责混乱:既要提供页面,又要处理 WebSocket,又要做跳转拼参数。
- 根路径
/的陷阱:OpenClaw 的前端会非常早地对/发起 WebSocket 连接(Upgrade)。如果你对/一刀切做 301/302,WebSocket 握手也会被重定向,导致断连。
因此采用线上常见的更稳的形态:
127.0.0.1:18790:OpenClaw Gateway(真实服务)127.0.0.1:18789:Nginx(入口反代 + 跳转)
第 1 步:把 OpenClaw Gateway 挪到 18790
1.1 修改 OpenClaw 配置
OpenClaw 配置文件:
C:\Users\LIYAO\.openclaw\openclaw.json
把 gateway.port 改为:
1 | { |
1.2 踩坑:改了 openclaw.json 仍然监听 18789?
我实际遇到过:配置里已经是 18790,但端口还是 18789。
原因是:Windows 上我的 Gateway 是通过 gateway.cmd 启动,并且命令行带了 --port 18789,命令行参数优先级更高。
相关链路(示例):
start-gateway-silent.vbs→ 运行gateway.cmdgateway.cmd里存在:
1 | E:\nvm\v25.6.0\node.exe ... openclaw ... gateway --port 18789 |
解决方式:同步修改 gateway.cmd:
set OPENCLAW_GATEWAY_PORT=18790- 把
--port 18789改为--port 18790
然后重启 gateway 进程。
1.3 验证上游(18790)
注意:不要用 http://127.0.0.1:18790/ 来判断服务是否正常。
因为 / 会跳到 /chat?session=main,但该 URL 没带 token,WebSocket 会报:
disconnected (1008): unauthorized: gateway token missing
正确的验证方式是访问 tokenized dashboard URL:
1 | http://127.0.0.1:18790/chat?session=agent%3Amain%3Amain&token=<YOUR_TOKEN> |
第 2 步:Nginx(18789)实现“根路径自动跳转 + WebSocket 不重定向”
2.1 核心原则:根路径 / 必须区分 HTTP 和 WebSocket
WebSocket 握手请求会带:
Upgrade: websocket
Nginx 可以用 map + $http_upgrade 识别:
1 | map $http_upgrade $connection_upgrade { |
2.2 Nginx 配置(Windows,入口 18789 → 上游 18790)
Nginx 主配置:
E:\openclaw-local\nginx-1.28.2\conf\nginx.conf
关键逻辑:
location = /:- 如果不是 WS:302 跳到
/chat?...&token=... - 如果是 WS:
proxy_pass到 18790
- 如果不是 WS:302 跳到
location /:其余路径全部反代到 18790
示例(精简版,关键点保留):
1 | server { |
2.3 验证
- 访问
http://127.0.0.1:18789/:应 302 到/chat?...token=... - DevTools → Network → WS:
/的连接应看到 101 Switching Protocols
第 3 步:踩坑 pairing required —— 通过 Nginx 反代后需要允许 Origin
我在打通 18789 → 18790 之后,页面能打开,但 WebSocket 仍然报:
disconnected (1008): pairing required
这是一个很典型的“反代引入新 origin”的问题:
- 直接访问 18790:origin 是
http://127.0.0.1:18790 - 通过 nginx 访问 18789:origin 变为
http://127.0.0.1:18789
OpenClaw Control UI 有设备配对/设备鉴权机制,会校验来源 origin。结果就是:18789 这个新 origin 未被允许时,客户端无法完成鉴权初始化,于是表现为 pairing required。
3.1 解决:配置 gateway.controlUi.allowedOrigins
在 openclaw.json 里为 gateway 增加:
1 | { |
然后重启/热重载 gateway。
说明:
- 本地是 http,所以需要
allowInsecureAuth=truetrustedProxies用于信任本机反代(避免代理头被错误处理)
3.2 再次验证
- 重新打开浏览器(建议无痕,避免旧 localStorage 状态干扰)
- 访问:
http://127.0.0.1:18789/
应能正常连接 gateway,Health OK,聊天输入框可用。
第 4 步:让 Nginx 开机自启(像 OpenClaw 一样静默)
目标:用户登录 Windows 后自动启动 nginx,且不弹黑窗口。
4.1 用 VBS 隐藏启动窗口
创建:
C:\Users\LIYAO\.openclaw\nginx-start.cmd
1 | @echo off |
C:\Users\LIYAO\.openclaw\start-nginx-silent.vbs
1 | Set WshShell = CreateObject("WScript.Shell") |
4.2 放到 Startup 文件夹实现“登录自启”
把下面这个 vbs 放到 Startup:
C:\Users\LIYAO\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\openclaw-local-nginx.vbs
内容:
1 | Set WshShell = CreateObject("WScript.Shell") |
这样每次登录 Windows,nginx 就会静默启动。
4.3 踩坑:schtasks 需要管理员权限
原本想用 schtasks /Create /SC ONLOGON ... 建计划任务,但遇到:
Access is denied
说明当前权限/策略不允许创建该计划任务(尤其是 /RL HIGHEST)。因此采用用户级 Startup 更省心。
最终效果与访问方式
✅ OpenClaw Gateway:
127.0.0.1:18790(上游)- 直接访问根路径
/仍会提示 token missing:这是正常的安全策略 - 需要用 tokenized URL 才能访问
- 直接访问根路径
✅ Nginx 入口:
127.0.0.1:18789- 访问
http://localhost:18789即可进入聊天页 - WebSocket
/不被重定向,连接稳定
- 访问
✅ Nginx 登录自启:无需手动启动
经验总结(值得记下来)
- WebSocket 代理最怕“对根路径一刀切重定向”:要识别 Upgrade 请求,否则 WS 握手会被 302/301 误伤。
- 配置改了但端口不变,优先看启动命令行是否覆盖了配置(Windows 很常见:cmd/vbs/service wrapper)。
- 反代引入新 origin 时,很多带鉴权的 Control UI 会拒绝:需要显式允许
allowedOrigins。 - 本地自启:
- 不想折腾管理员权限 → 用 Startup 文件夹 + vbs 隐藏窗口
- 真正“未登录也启动” → 再上计划任务(SYSTEM)或 Windows Service(NSSM)
附:常用命令
Nginx reload
1 | cd E:\openclaw-local\nginx-1.28.2 |
Nginx stop
1 | C:\Users\LIYAO\.openclaw\nginx-stop.cmd |