摘要:本文面向内网 Ubuntu 服务器,完整讲解 OpenClaw 的重装部署、本地模型接入与 WebUI 内网直连全流程。内容包括:备份旧配置、停止服务并重装、手写models.providers配置接入本地模型代理(freellmapi/auto)、以 systemd 用户服务启动 Gateway,以及通过 Gateway 原生 TLS 自签证书实现局域网内其他电脑直接访问 Control UI。文章重点剖析了两个最容易踩的坑——自定义 Provider 的input/cost字段格式校验失败,以及新设备访问 Control UI 时的配对审批流程,并给出常见问题排查对照表,帮助读者少走弯路、一步到位完成部署。
1. 方案背景与架构
目标
- 服务器上已安装过 OpenClaw,需重装到干净状态。
- 接入本地模型代理(本文示例为
freellmapi,监听127.0.0.1:31415,提供 OpenAI 兼容的/v1接口,内含 206 个模型,其中auto为自动路由模型)。 - 局域网内其他电脑(Windows 等)能通过内网 IP 直接访问WebUI(Control UI),无需 SSH 隧道。
架构图
flowchart TD A[浏览器: https://192.168.1.107:18789] -- HTTPS TLS 自签证书 --> B[OpenClaw Gateway 端口 18789 TLS 终止] B -- http://127.0.0.1:31415/v1 OpenAI 兼容 --> C[本地模型代理 freellmapi] C -- 上游模型服务 --> D[模型推理]关键结论(先看,少走弯路)
- OpenClaw 的 Control UI只允许在“安全上下文”(HTTPS 或 localhost)下工作。直接用
http://内网IP:18789访问会报control ui requires device identity (use HTTPS or localhost secure context),且 token 认证无法替代该限制。必须开 HTTPS。 - OpenClaw Gateway原生支持 TLS 终止(
gateway.tls),不需要额外装 nginx。 - 新设备首次访问 Control UI 会进入设备配对流程,需要在服务器端批准(
openclaw devices approve),否则提示pairing required: device is not approved yet。 - 自定义模型 Provider 的
models[].input/models[].cost字段格式要求严格,格式不对会导致配置校验失败(详见第 5 节)。
2. 前置准备
2.1 服务器环境
# 查看系统版本 cat /etc/os-release uname -a 确认 Node / npm(本文使用 nvm 安装的 Node v24.19.0) node -v npm -v 查看 openclaw 是否已全局安装及版本 which openclaw openclaw --version2.2 确认本地模型代理
# 确认本地模型代理监听 ss -tlnp | grep 31415 查看可用模型(确认有 auto / claude-sonnet-4-5 等) curl -s http://127.0.0.1:31415/v1/models -H "Authorization: Bearer <your-api-key>" | head -c 20003. 备份旧配置
重装前务必备份~/.openclaw目录,避免丢失原有 gateway token、设备、workspace 等:
cp -r ~/.openclaw ~/.openclaw.bak.$(date +%Y%m%d) du -sh ~/.openclaw.bak.$(date +%Y%m%d)备份后用cat ~/.openclaw/openclaw.json记录原有关键配置(gateway token、端口等),作为重装后对比基线。
4. 停止服务并重装 OpenClaw
4.1 查看现有 gateway 服务
OpenClaw 安装为 systemd用户服务时,服务名为openclaw-gateway.service:
export XDG_RUNTIME_DIR=/run/user/$(id -u) systemctl --user list-unit-files | grep -i openclaw systemctl --user status openclaw-gateway | head -8 确认是否开机自启(Linger) loginctl show-user $USER | grep Linger4.2 停止服务并卸载旧版本
export XDG_RUNTIME_DIR=/run/user/$(id -u) systemctl --user stop openclaw-gateway systemctl --user is-active openclaw-gateway # 应输出 inactive 清理可能残留的前台进程 pkill -f "openclaw" 2>/dev/null 卸载旧全局包(需加载 nvm 环境) source ~/.nvm/nvm.sh npm uninstall -g openclaw4.3 安装最新版
source ~/.nvm/nvm.sh npm install -g openclaw@latest openclaw --version # 确认版本若 npm 提示
allow-scripts未执行 install 脚本,可执行一次npm install -g --allow-scripts=openclaw,@google/genai,protobufjs,tree-sitter-bash。
5. 配置本地模型 Provider(接入 auto)
5.1 为什么不走交互式 onboard
openclaw onboard交互式向导在 SSH 会话中容易卡住。推荐直接手写models.providers配置,一步到位。
5.2 配置 JSON 模板
在~/.openclaw/openclaw.json中加入:
{ "models": { "providers": { "freellmapi": { "baseUrl": "http://127.0.0.1:31415/v1", "apiKey": "<your-api-key>", "api": "openai-completions", "models": [ { "id": "auto", "name": "Auto (router picks the best available model)", "reasoning": false, "contextWindow": 1048576, "contextTokens": 1048576, "maxTokens": 32768 } ] } } }, "agents": { "defaults": { "model": { "primary": "freellmapi/auto" } } } }字段说明
| 字段 | 说明 |
|---|---|
baseUrl | 本地模型代理的 OpenAI 兼容地址,末尾要带/v1 |
apiKey | 本地代理的 API key |
api | 固定openai-completions;仅当后端支持/v1/responses时才用openai-responses |
models[].id | 在代理里真实存在的模型 ID(如auto) |
contextWindow/contextTokens/maxTokens | 上下文与输出上限,按代理实际能力填写 |
5.3 校验与踩坑
用官方 CLI 校验配置:
source ~/.nvm/nvm.sh openclaw config validate # 期望输出: Config valid: ~/.openclaw/openclaw.json坑 1:
input/cost字段格式
若在models[]里写了"input": 0.0或"cost": 0.0,会报models.providers.xxx.models.0.input: Invalid input导致整个配置失效。
解法:直接删掉这两个字段,不要给简单数值。坑 2:不能用
config set分步拼 Provideropenclaw config set models.providers.xxx.baseUrl ...会做增量校验,因缺少models字段而报custom model providers must declare models。自定义 Provider 必须一次性完整写入 JSON。
(可以先用 base64 传输脚本改 JSON,再用config validate校验。)
6. 配置并启动 Gateway(systemd 用户服务)
6.1 安装/重建系统服务
export XDG_RUNTIME_DIR=/run/user/$(id -u) source ~/.nvm/nvm.sh openclaw gateway install --force # 生成/覆盖 systemd 用户服务 systemctl --user daemon-reload systemctl --user enable --now openclaw-gateway6.2 确认启动
systemctl --user status openclaw-gateway | head -12 # Active: active (running) # Main PID: ... 查看日志,确认模型已加载 journalctl --user -u openclaw-gateway --no-pager -n 20 | grep -iE "agent model|listening|ready" 期望看到: agent model: freellmapi/auto (thinking=off, fast=off)6.3 验证模型端到端
curl -s -X POST http://127.0.0.1:31415/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <your-api-key>" \ -d '{"model":"auto","messages":[{"role":"user","content":"hi"}],"max_tokens":16}'能看到返回(含_routed_via表示 auto 实际路由到的上游模型)即链路 OK。
7. 内网 WebUI 访问:HTTPS 直连方案
7.1 背景:为什么不能 http:// 内网 IP 直连
Control UI 需要安全上下文才能生成设备身份。局域网明文 HTTP(http://192.168.1.107:18789)会被浏览器判定为非安全上下文,报错:
control ui requires device identity (use HTTPS or localhost secure context)token 认证不能替代设备身份,gateway.controlUi.allowInsecureAuth=true也只在 localhost 下放宽。
7.2 方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
SSH 隧道(ssh -L 18789:127.0.0.1:18789) | 零改动 | 隧道进程易断、需保活、非“直接访问” |
| Gateway 原生 TLS(本文方案) | 内网 IP 直连、无额外组件 | 需自签证书(浏览器信任一次即可) |
| Tailscale Serve | 公网可访问、证书自动 | 需装 Tailscale 并登录 |
推荐 Gateway 原生 TLS,最贴合“内网 IP 直接访问”诉求。
7.3 生成自签名证书(含 IP SAN)
证书必须包含服务器的内网 IP 的 SAN,否则浏览器会报“证书名称不匹配”。
mkdir -p ~/.openclaw/certs && cd ~/.openclaw/certs openssl req -x509 -newkey rsa:2048 \ -keyout server.key -out server.crt \ -days 3650 -nodes \ -subj "/CN=192.168.1.107" \ -addext "subjectAltName=IP:192.168.1.107,DNS:localhost,DNS:<your-hostname>" chmod 600 server.key 验证 SAN openssl x509 -in server.crt -noout -ext subjectAltName 期望: IP Address:192.168.1.107, DNS:localhost, DNS:<hostname>7.4 配置 Gateway TLS
source ~/.nvm/nvm.sh openclaw config set gateway.tls.enabled true openclaw config set gateway.tls.certPath /home/<user>/.openclaw/certs/server.crt openclaw config set gateway.tls.keyPath /home/<user>/.openclaw/certs/server.key openclaw config set gateway.controlUi.allowedOrigins '["https://192.168.1.107:18789","http://localhost:18789","http://127.0.0.1:18789"]' openclaw config validate说明:
gateway.tls支持enabled / certPath / keyPath / caPath / autoGenerate。生产建议用正式证书;内网自签即可。allowedOrigins需要把实际访问来源的https://IP:端口加进去,否则浏览器 CORS/Origin 校验会拦。
7.5 重启并验证
export XDG_RUNTIME_DIR=/run/user/$(id -u) systemctl --user restart openclaw-gateway sleep 8 systemctl --user is-active openclaw-gateway 服务器本地验证(-k 忽略证书校验) curl -sk -o /dev/null -w "%{http_code}\n" https://127.0.0.1:18789/ # 200 curl -sk -o /dev/null -w "%{http_code}\n" https://192.168.1.107:18789/ # 200 明文 http 此时应失效(000),说明已被 TLS 取代7.6 本机(Windows)导入证书,消除浏览器警告
把server.crt拷到本机后:
# 导入到当前用户受信任根(无需管理员) Import-Certificate -FilePath C:\path\to\server.crt -CertStoreLocation Cert:\CurrentUser\Root之后浏览器访问https://192.168.1.107:18789不再有证书警告。
8. 设备配对审批(最容易踩的坑)
8.1 现象
HTTPS 通了、token 填对了,仍然进不去,页面/日志提示:
pairing required: device is not approved yet (requestId: xxxx) phase=auth_validated含义:token 已验证通过,但当前浏览器设备尚未获得配对批准。Control UI 的流程是:
flowchart LR A[新设备 HTTPS 首次连接] -- 生成配对请求 new pairing --> B[服务器端批准] B -- 设备进入已配对表 --> C[之后免审批连接]8.2 查看待批准设备
source ~/.nvm/nvm.sh openclaw devices list输出分为Pending(待批准)与Paired(已配对):
Pending (1) │ Request: 70e5fe9e-218d-4550-8016-eccc19da97e8 │ Device : cea971d9... │ IP : 192.168.1.108 │ Status : new pairing8.3 批准设备
openclaw devices approve 70e5fe9e-218d-4550-8016-eccc19da97e8 # 输出: Approved cea971d9... (70e5fe9e-...)再openclaw devices list,该设备应进入Paired列表。
8.4 重要注意点
配对请求有有效期。若批准前请求已过期(
No pending device request matches ...),需要让浏览器重新打开/刷新Control UI 页面生成新请求,再在有效期内尽快批准。
相关命令:openclaw devices approve|reject|list|remove|revoke|clear。
9. 验证与日常使用
- 浏览器打开
https://192.168.1.107:18789。 - 输入 gateway token(来自
openclaw.json的gateway.auth.token)登录。 - 进入 Control UI 后,可在 WebChat 中发消息,验证
freellmapi/auto正常推理。
日常状态检查
openclaw gateway status openclaw doctor openclaw models list --provider freellmapi systemctl --user status openclaw-gateway10. 常见问题排查
| 现象 | 原因 | 解决 |
|---|---|---|
control ui requires device identity | 用明文 HTTP 访问非 localhost | 改走 HTTPS(本文第 7 节) |
pairing required: device is not approved yet | 新设备未批准 | openclaw devices list+approve(第 8 节) |
models.0.input: Invalid input | input/cost字段格式错误 | 删除这两个字段后重新config validate |
custom model providers must declare models | 用config set分步写 Provider | 一次性完整写入 JSON |
No pending device request matches | 配对请求已过期 | 浏览器刷新页面重新生成,再尽快批准 |
| HTTP 000 / 连不上 | gateway 未启动或绑定错误 | systemctl --user status+journalctl --user -u openclaw-gateway看日志 |
| 浏览器证书警告 | 未信任自签证书 | 将 server.crt 导入本机受信任根(第 7.6 节) |
| SSH 隧道方案易断 | 隧道进程被清理 | 改用本文 HTTPS 直连方案 |
附:最终 openclaw.json 关键片段(供对照)
{ "gateway": { "mode": "local", "auth": { "mode": "token", "token": "<your-token>" }, "port": 18789, "bind": "lan", "controlUi": { "allowInsecureAuth": true, "allowedOrigins": [ "https://192.168.1.107:18789", "http://localhost:18789", "http://127.0.0.1:18789" ]}, "tls": { "enabled": true, "certPath": "/home/<user>/.openclaw/certs/server.crt", "keyPath": "/home/<user>/.openclaw/certs/server.key" } }, "models": { "providers": { "freellmapi": { /* 见第 5 节 */ } } }, "agents": { "defaults": { "model": { "primary": "freellmapi/auto" } } } }(内容由AI生成,仅供参考)