首页 默认分类 正文
  • 本文约4597字,阅读需23分钟
  • 31
  • 0

Docker 部署 OpenClaw 最新版实战:从端口映射到 Control UI 配对全流程排查

Docker 部署 OpenClaw 最新版实战:从端口映射到 Control UI 配对全流程排查

这次我的目标很直接:在 Docker 中部署最新版 OpenClaw,并让 Mac 本地浏览器通过 http://localhost:8888 访问容器中的 OpenClaw 控制界面。看起来只是一个简单的端口映射问题,实际排查下来,涉及 Docker 端口发布、服务绑定地址、Control UI 的 Origin 校验,以及浏览器设备配对四个层面。

背景

我希望实现下面这条访问链路:

Mac 浏览器
  -> http://localhost:8888
  -> Docker 端口映射 8888:18789
  -> 容器内 OpenClaw 监听 18789
  -> OpenClaw Control UI / Gateway

一开始以为只要把 Docker 参数写成 -p 8888:18789 就够了,但实际情况比这复杂一些。好在这次完整走通之后,整个路径反而变得很清晰:

  1. 先让容器真正跑起来
  2. 再让宿主机能访问到容器内服务
  3. 再让浏览器来源通过 Control UI 的安全检查
  4. 最后完成浏览器设备配对

一、先用 Docker 启动最新版 OpenClaw

机器里已经有 OpenClaw 的最新镜像,因此第一步不是重新构建,而是直接用现成镜像启动容器。

我最终使用的是这种方式:

docker rm -f claw

docker run -d \
  --name claw \
  -p 8888:18789 \
  dr34m/openclaw:latest \
  openclaw gateway --allow-unconfigured

这里最关键的是:

  • 8888Mac 宿主机端口
  • 18789容器内 OpenClaw Gateway 端口

也就是说,我想要的是:

  • 浏览器打开 http://localhost:8888
  • Docker 把请求转发到容器内的 18789

到这一步,Docker 层的端口映射已经满足目标了。

二、为什么端口映射对了,页面还是打不开?

最初最容易误判的是:既然已经 -p 8888:18789 了,那打不开一定是 Docker 端口没映射好。

但继续排查后发现,问题不在 Docker 本身,而在 OpenClaw 服务监听地址。

1. 宿主机端口其实已经被 Docker 占住了

从 Docker 状态能看到类似信息:

0.0.0.0:8888->18789/tcp

这说明 Docker 已经在宿主机上监听了 8888。

2. 但访问 localhost:8888 仍然失败

这时访问健康检查会看到 connection reset 一类错误,表面上像是服务没起来。

3. 真正原因:OpenClaw 只绑定在容器内部 loopback

继续看容器日志,发现关键信息是:

[gateway] listening on ws://127.0.0.1:18789

这就意味着:

  • OpenClaw 进程是活着的
  • 它确实监听在 18789
  • 但它只监听 容器内部的 127.0.0.1
  • Docker 虽然把宿主机的流量转发到了容器,但服务本身只接受容器 loopback 访问

这也是为什么:

  • 容器里测 127.0.0.1:18789 是通的
  • 宿主机测 127.0.0.1:8888 却不通

本质上不是“端口映射失败”,而是“服务没有对容器网络开放”。

三、把 OpenClaw 的绑定地址改成 lan

OpenClaw 的 Docker 文档里提到,Docker 场景下不要让 Gateway 只绑定在 loopback,而应该使用 lan

1. 配置文件位置

这次修改的是容器内部的配置文件:

/home/node/.openclaw/openclaw.json

2. 需要增加的配置

{
  "gateway": {
    "bind": "lan",
    "mode": "local"
  }
}

3. 两个配置项分别做什么

gateway.bind = "lan"

这是这次修复里最核心的一步。

它的作用是让 OpenClaw 从只监听容器内部 loopback,变成监听对容器网络可达的地址。

修改前,日志里是:

ws://127.0.0.1:18789

修改后,日志变成:

ws://0.0.0.0:18789

也就是说服务从“只在容器内部自言自语”,变成了“容器网络里的请求也能进来”。

gateway.mode = "local"

这个配置主要是为了让 Docker / 本地场景下的 Gateway 行为更稳定,避免后续 Control UI、CLI 或配对时把目标地址理解错。

可以把它看作一个配套项:

  • bind 解决“服务能不能被外部打到”
  • mode 让“本地部署语义”保持一致

4. 改完后重启容器

docker restart claw

5. 验证结果

这时再访问:

curl http://127.0.0.1:8888/healthz

已经能返回:

{"ok":true,"status":"live"}

说明:

  • Docker 端口映射正常
  • OpenClaw 监听地址也已经正确
  • Mac 宿主机终于能真正打到容器内服务

四、页面能打开了,但又报 origin not allowed

到这里,静态页面已经能打开,但并不代表 Control UI 已经能和 Gateway 建立控制连接。

此时浏览器会提示类似:

origin not allowed
(open the Control UI from the gateway host or allow it in gateway.controlUi.allowedOrigins)

1. 这是什么问题?

这不是端口问题,而是 Control UI 的来源校验(Origin 校验)

我这次是通过:

  • http://localhost:8888

打开页面的。

于是浏览器在建立 WebSocket / 控制连接时,会带上 Origin:

  • http://localhost:8888

但 OpenClaw 当前配置里并没有明确允许这个来源,于是连接被拒绝。

2. 解决方法

继续修改同一个配置文件:

/home/node/.openclaw/openclaw.json

加入:

{
  "gateway": {
    "bind": "lan",
    "mode": "local",
    "controlUi": {
      "allowedOrigins": [
        "http://localhost:8888",
        "http://127.0.0.1:8888"
      ]
    }
  }
}

3. 为什么要写两个 Origin

因为访问本地服务时,实际浏览器来源可能有两种常见形式:

  • http://localhost:8888
  • http://127.0.0.1:8888

两个都加进去,能避免后续切换地址时再踩一次坑。

如果你未来打算通过局域网 IP 访问,比如:

  • http://192.168.x.x:8888

那也需要把对应的 Origin 再补进去。

五、Origin 通过了,但又提示 pairing required

这一步也很有代表性。

很多时候看到 pairing required 会以为服务还是坏的,其实恰恰相反:

  • 端口已经通了
  • Origin 校验也已经过了
  • 浏览器已经开始真正接触 Gateway 了
  • 只是当前浏览器设备还没有被信任

换句话说,这是一个 安全配对问题,不是网络问题。

1. pairing required 的含义

OpenClaw 不会默认信任所有能打开页面的浏览器设备。Control UI 和 Gateway 建立控制连接前,需要这个浏览器设备先完成配对授权。

2. 这一步怎么做

要做三件事:

  1. 列出待配对设备
  2. 找到当前浏览器对应的 requestId
  3. 批准这个请求

因为这次不是通过 Docker Compose,而是单容器 docker run 启动的,所以我直接在容器里调用 OpenClaw CLI。

3. 先获取 token,再查看待配对设备

OpenClaw Gateway 当前是 token 鉴权,所以 CLI 连接 Gateway 时必须显式带 token。

查看待配对设备的思路是:

openclaw devices list --url ws://127.0.0.1:18789 --token <token>

这时能看到一个 Pending 请求。

4. 批准该浏览器设备

拿到 requestId 后,执行:

openclaw devices approve <requestId> --url ws://127.0.0.1:18789 --token <token>

批准成功后,再次查看设备列表,就会从 Pending 变成 Paired。

此时浏览器刷新页面,就可以真正进入 Control UI。

六、这次到底改了哪些地方?

如果把整个过程压缩成最关键的几个改动,其实就是下面这些。

1. Docker 启动方式

docker run -d \
  --name claw \
  -p 8888:18789 \
  dr34m/openclaw:latest \
  openclaw gateway --allow-unconfigured

2. 容器内配置文件

/home/node/.openclaw/openclaw.json

3. 最终关键配置

{
  "gateway": {
    "auth": {
      "mode": "token",
      "token": "..."
    },
    "bind": "lan",
    "mode": "local",
    "controlUi": {
      "allowedOrigins": [
        "http://localhost:8888",
        "http://127.0.0.1:8888"
      ]
    }
  }
}

4. 设备配对

  • 列出待配对设备
  • 找到 requestId
  • 手动 approve

七、这次排查真正解决的是哪四层问题?

这次最值得记住的一点是:浏览器能不能打开一个 Docker 里的 OpenClaw,不是只有端口映射这一层。

实际上需要依次打通四层:

第 1 层:Docker 端口映射

8888 -> 18789

这是入口,但只是入口。

第 2 层:OpenClaw 的监听地址

如果服务只监听 127.0.0.1,那 Docker 端口映射再对也没用。

要改成:

"gateway": {
  "bind": "lan"
}

第 3 层:Control UI 的 Origin 白名单

页面资源能打开,不等于 Control UI 可以连接 Gateway。

要允许:

"allowedOrigins": [
  "http://localhost:8888",
  "http://127.0.0.1:8888"
]

第 4 层:浏览器设备配对

即使前面都没问题,浏览器设备依然可能因为没被批准而卡在:

pairing required

需要手动批准当前浏览器设备。

八、我的结论

这次看起来只是“把 Docker 端口从 18789 换成 8888”,但真实工作量其实在排查路径上。

如果只看 Docker 参数,很容易以为问题已经解决;但实际还要一路确认:

  • 服务到底有没有起来
  • 它监听的是不是对外可达地址
  • Control UI 有没有允许当前浏览器 Origin
  • 这个浏览器设备有没有完成配对

真正跑通之后,思路反而非常清楚:

端口映射解决“流量能不能到容器门口”,绑定地址解决“服务接不接这个流量”,Origin 白名单解决“Control UI 认不认这个页面来源”,设备配对解决“Gateway 信不信这个浏览器”。

把这四层都打通之后,http://localhost:8888 才真正变成一个可用的 OpenClaw 控制入口。

写在最后

这次部署虽然绕了一点,但也顺手把 OpenClaw 在 Docker 场景下的关键连接链路梳理清楚了。对后面做长期部署、改成 docker compose、补充模型 provider 配置,都会轻松很多。

如果后续要把它变成长期可维护的方案,我更推荐继续往两个方向走:

  1. 把当前运行参数固化成 docker-compose.yml
  2. 补齐模型 provider / API key / 持久化配置

这样它就不只是“页面能打开”,而是一个真正可长期使用的 Docker 版 OpenClaw 环境。

评论
友情链接