【教程】用 Cloudflare Tunnel + Access,把本地 Chromium 安全接给 OpenClaw

2026-04-11 15:211阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐
问题描述:

适合使用服务器或者Docker部署OpenClaw,但是想要控制本地电脑浏览器的场景。欢迎大佬指正和优化方案。

PS:忘记说了,这个方案部署后的3000端口可以直接打开docker内的浏览器。这样如果有遇到验证码可以直接人工干预。如有需要也可以将这个端口通过Tunnel一块共享到公网,但是一定要限制白名单访问!!!
image2472×1468 173 KB


0. 准备条件

  • 一台本地机器,能跑 Docker
  • 一台 OpenClaw 服务器,最好有固定公网出口 IP
  • 一个已托管到 Cloudflare 的域名
  • 已开通 Cloudflare Zero Trust

前提提醒:如果 OpenClaw 服务器的出口 IP 不固定,先解决固定出口/NAT 再做 Access 白名单,不然策略会经常失效。


1. 本地启动 Chromium、cloudflared(只给本机调试,同时给 cloudflared 走容器内网)

下面这份 docker-compose.yaml 直接把 chromiumcloudflared 放到同一个 Compose 项目里。92223000 只绑定宿主机回环地址;而 cloudflared 则通过容器内网直连 chromium:9222。为什么不用--remote-debugging-address参数?因为Chromium官方已经停用该参数了…

1.1 进入:Zero Trust → Networks → Connectors → Create a tunnel → Select Cloudflared
image2568×1330 311 KB

1.2 填写Tunnel name

1.3 选择Docker,把Token复制出来

1.4 本地找一个合适的位置新建一个文件夹,新建一个docker-compose.yaml,文件内容:

services: chromium: image: lscr.io/linuxserver/chromium:latest container_name: chromium restart: unless-stopped ports: - "127.0.0.1:3000:3000" # 可选:本地 Web UI,用于直接打开docker内的浏览器 environment: - PUID=1000 - PGID=1000 - TZ=Asia/Shanghai - LC_ALL=zh_CN.UTF-8 - LANGUAGE=zh_CN.UTF-8 - LANG=zh_CN.UTF-8 - CHROME_CLI=chrome://version --remote-debugging-port=9222 --remote-allow-origins=* volumes: - ./chromium-config:/config shm_size: "4gb" cloudflared: image: cloudflare/cloudflared:latest container_name: cloudflared restart: unless-stopped network_mode: "service:chromium" depends_on: - chromium command: tunnel --no-autoupdate run --protocol http2 --token ${TUNNEL_TOKEN}

1.5 替换文件中${TUNNEL_TOKEN}为你的隧道Token

1.6 执行docker compose up -d启动服务

1.7 在chromium容器内验证 CDP:

curl http://127.0.0.1:9222/json/version curl http://127.0.0.1:9222/json/list

能返回 JSON,说明 Chromium 的 CDP 已经起来了。

linuxserver/chromium 默认没有强认证能力,官方也明确提醒不要直接暴露到公网。这里把端口绑在 127.0.0.1,就是为了把暴露面压到最小。 (LinuxServer)

1.8 回到Zero Trust页面,确认 Connectors 下有内容,点击下一步
image2604×1636 269 KB

1.9 输入你的域名信息,Service填写HTTP127.0.0.1:9222

1.10 注意:一定要在 Additional application settings → HTTP Settings → HTTP Host Header中输入127.0.0.1
image3114×2194 372 KB

这里因为 cloudflaredchromium 在同一个 Compose 网络里,所以可以直接访问。Tunnel 的入口走公网域名,Tunnel 后端走容器内网,不需要再绕宿主机。Docker Compose 官方文档也明确说明了,同一网络里的服务可以通过服务名互相发现。 (Docker Documentation)

Cloudflare Tunnel 的 published application 本质上就是“公网 Hostname → 本地 Service”的映射;通过 Dashboard 添加 route 时,Cloudflare 还会自动创建对应的 DNS 记录。 (Cloudflare Docs)

另外,CDP 底层会用到 WebSocket 升级连接。Cloudflare 支持代理 WebSocket 连接,不需要额外再套一层专门的 ws 代理。如果你之前手动把 Zone 的 WebSockets 关掉了,记得重新打开。 (Cloudflare Docs)


2. 先在 Cloudflare Access 外面套一层“保护壳”

进入:

Zero Trust → Access controls → Applications → Add an application → Self-hosted

填写:

  • Application domainchrome.example.com
  • 其他外观项保持默认即可

点击Create new policy

  • ActionBypass
  • IncludeIP ranges
  • Value你的 OpenClaw 服务器出口 IP/32

其余默认拒绝,打开审计日志。
image2380×1706 308 KB

也就是说,这个域名不是“谁知道地址谁就能连”,而是“只有从你那台 OpenClaw 服务器出来的请求,才允许打到 CDP”。

Cloudflare Access 的 IP ranges 本身就是标准策略选择器,适合这类固定来源机器访问;Access 默认也是 deny by default。 (Cloudflare Docs)

为什么这里默认推荐 IP allow,而不是 Service Token
Cloudflare 的 Service Token 很适合自动化系统,但它要求请求里带 CF-Access-Client-IdCF-Access-Client-Secret 头。OpenClaw 官方文档对远程 CDP 的主路径是配置 browser.profiles.<name>.cdpUrlbrowser.cdpUrl,并明确写了支持 HTTP(S)/WS(S)、URL query token 和 HTTP Basic auth,但没有把“给远程 CDP 单独注入 Cloudflare Access 头”作为标准入口写出来。所以对 OpenClaw 这类“只填一个 cdpUrl”的接入方式来说,固定出口 IP + Access Allow 是最通用、最少坑的方案。等你的接入层明确支持自定义 Access 头,再切 Service Auth 也不迟。 (Cloudflare Docs)


3. 启动 cloudflared

docker compose up -d cloudflared docker compose logs -f cloudflared

正常情况下,Tunnel 会很快连上 Cloudflare。


4. 按顺序验证整条链路

4.1 本地先看 Chromium 自己是否正常

curl http://127.0.0.1:9222/json/version curl http://127.0.0.1:9222/json/list

4.2 再看 cloudflared 容器能不能打到 Chromium

docker exec cloudflared wget -qO- http://chromium:9222/json/version

如果这一步拿不到 JSON,先别看 Cloudflare,先把 Docker 侧打通。

4.3 再从“允许的来源”验证公网域名

最好直接在 OpenClaw 那台服务器 上跑:

curl https://chrome.example.com/json/version curl https://chrome.example.com/json/list

如果这里能返回 JSON,说明:

  • Chromium 正常
  • Docker 网络正常
  • Tunnel 正常
  • Access 放行正常

如果你在自己电脑上测试却被拦截,不一定是坏事,往往只是因为你的电脑 不在 Access 的 IP 白名单里

如果 Tunnel 没连上,但 DNS 记录已经在,Cloudflare 侧常见现象是 1016。这是因为 DNS 记录和 Tunnel 本身是独立的,Tunnel 停了,记录不会自动删。 (Cloudflare Docs)


5. 接到 OpenClaw

OpenClaw 官方文档对远程 CDP 的说明很明确:

  • browser.profiles.<name>.cdpUrlbrowser.cdpUrl
  • 如果给的是 https://... 这类 HTTP(S) 入口,OpenClaw 会先请求 /json/version 获取 WebSocket debugger URL,再建立连接
  • 如果给的是 wss://...,就会直接走 WebSocket 连接 (OpenClaw)

一个最直接的配置示例:

{ "browser": { "profiles": { "remote": { "cdpUrl": "https://chrome.example.com/", "color": "#00AA00" } } } }

接好之后,建议按这个顺序验:

  1. 能列出 tabs openclaw browser tabs
  2. 能打开新页面 openclaw browser open
  3. 能 screenshot openclaw browser screenshot
  4. 能 snapshot / PDF openclaw browser snapshot

如果“能连上但截图/快照能力不完整”,再去看 OpenClaw 侧是否带了完整的浏览器/Playwright 依赖。OpenClaw 官方文档也说明了,部分高级能力依赖 Playwright。 (OpenClaw)


6. 常见故障排查顺序

6.1 本地 CDP 没起来

先看:

curl http://127.0.0.1:9222/json/version

没 JSON,就先不要继续排 Tunnel。

6.2 容器内网不通

看这条:

docker exec cloudflared wget -qO- http://chromium:9222/json/version

如果这里失败,问题在 Docker 网络或 Chromium 监听地址,不在 Cloudflare。

6.3 Access 拦截了

去 Zero Trust 的日志里看请求有没有命中策略。
尤其要确认 OpenClaw 服务器看到的 真实出口 IP 和你写进白名单的 IP 是同一个。

6.4 OpenClaw 的 cdpUrl 写错了

两个常见错误:

  • https://cdp.example.com/json/version 当成 cdpUrl 填进去
    HTTP(S) 模式下,通常应该填基础地址:https://cdp.example.com
  • 把 HTTP 入口和 WebSocket 入口混着用
    只有在你已经拿到明确的 ws:// / wss://.../devtools/browser/... 时,才直接填 WebSocket 地址。OpenClaw 文档也明确区分了这两种模式。 (OpenClaw)

6.5 Chromium 容器在老环境启动异常

linuxserver/chromium 官方文档提到,某些较老的内核或较老的 libseccomp 环境里,可能需要额外加:

security_opt: - seccomp=unconfined

这只在确实起不来时再加,不要默认就开。 (LinuxServer)

网友解答:
--【壹】--: zhfeng:

curl http://127.0.0.1:9222/json/list

佬 请教一下 我配置跟你一样 docker-compose 也跑起来了,但是为啥
root@debian:~# curl http://127.0.0.1:9222/json/version
curl http://127.0.0.1:9222/json/list
curl: (56) Recv failure: Connection reset by peer
curl: (56) Recv failure: Connection reset by peer
报错

但是我通过docker exec -it chromium curl http://127.0.0.1:9222/json/version
又可以返回json


--【贰】--:

技术贴必须顶


--【叁】--:

学习了,我的是在nas虚拟机上安装的openclaw,没有桌面,准备参考你这个方法,用docker部署一个浏览器给openclaw用


--【肆】--:

感谢大佬教程


--【伍】--:

可以继续试试能用域名访问不,如果可以的话就没问题


--【陆】--:

感谢佬友分享


--【柒】--:

这个很实用,感谢。


--【捌】--:

看的一脸懵逼


--【玖】--:

感谢大佬分享技术


--【拾】--:

感谢大佬,刚好需要


--【拾壹】--:

支持大佬


--【拾贰】--:

后面没搞定,我不加 Cloudflare Access 外面套一层“保护壳,
我通过网页访问

http://域名/json/version

可以出来游览器信息
{ "Browser": "Chrome/146.0.7680.164", "Protocol-Version": "1.3", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36", "V8-Version": "14.6.202.26", "WebKit-Version": "537.36 (@bbd8c5dd25fb2f52171abdff)", "webSocketDebuggerUrl": "ws://127.0.0.1/devtools/browser/aaa9af7b-c1-f7fec957af23" }
然后在服务器上 没办法
crul: 127.0.0.1:9222/json/version 没办法出来游览器信息
进入docker内部可以出游览器信息
3000 端口在网页访问也不会出游览器web 页面


--【拾叁】--:

大厂除了jvs 带了桌面 其他都没带。你这个好啊


--【拾肆】--:

好主意啊!我龙虾在本地,我可以在外网起一个浏览器给本地的龙虾用,解决了网络问题,感谢佬友分享!


--【拾伍】--:

很棒,学习了。

zhfeng:

security_opt: - seccomp=unconfined

确实是,老版本docker需要加这个,当然不推荐的–provileged也可以解决。


--【拾陆】--:

不错不错,教程很清晰


--【拾柒】--:

好强


--【拾捌】--:

这就把教程扔给我的去学习(


--【拾玖】--:

感谢分享(*ゝω・)

问题描述:

适合使用服务器或者Docker部署OpenClaw,但是想要控制本地电脑浏览器的场景。欢迎大佬指正和优化方案。

PS:忘记说了,这个方案部署后的3000端口可以直接打开docker内的浏览器。这样如果有遇到验证码可以直接人工干预。如有需要也可以将这个端口通过Tunnel一块共享到公网,但是一定要限制白名单访问!!!
image2472×1468 173 KB


0. 准备条件

  • 一台本地机器,能跑 Docker
  • 一台 OpenClaw 服务器,最好有固定公网出口 IP
  • 一个已托管到 Cloudflare 的域名
  • 已开通 Cloudflare Zero Trust

前提提醒:如果 OpenClaw 服务器的出口 IP 不固定,先解决固定出口/NAT 再做 Access 白名单,不然策略会经常失效。


1. 本地启动 Chromium、cloudflared(只给本机调试,同时给 cloudflared 走容器内网)

下面这份 docker-compose.yaml 直接把 chromiumcloudflared 放到同一个 Compose 项目里。92223000 只绑定宿主机回环地址;而 cloudflared 则通过容器内网直连 chromium:9222。为什么不用--remote-debugging-address参数?因为Chromium官方已经停用该参数了…

1.1 进入:Zero Trust → Networks → Connectors → Create a tunnel → Select Cloudflared
image2568×1330 311 KB

1.2 填写Tunnel name

1.3 选择Docker,把Token复制出来

1.4 本地找一个合适的位置新建一个文件夹,新建一个docker-compose.yaml,文件内容:

services: chromium: image: lscr.io/linuxserver/chromium:latest container_name: chromium restart: unless-stopped ports: - "127.0.0.1:3000:3000" # 可选:本地 Web UI,用于直接打开docker内的浏览器 environment: - PUID=1000 - PGID=1000 - TZ=Asia/Shanghai - LC_ALL=zh_CN.UTF-8 - LANGUAGE=zh_CN.UTF-8 - LANG=zh_CN.UTF-8 - CHROME_CLI=chrome://version --remote-debugging-port=9222 --remote-allow-origins=* volumes: - ./chromium-config:/config shm_size: "4gb" cloudflared: image: cloudflare/cloudflared:latest container_name: cloudflared restart: unless-stopped network_mode: "service:chromium" depends_on: - chromium command: tunnel --no-autoupdate run --protocol http2 --token ${TUNNEL_TOKEN}

1.5 替换文件中${TUNNEL_TOKEN}为你的隧道Token

1.6 执行docker compose up -d启动服务

1.7 在chromium容器内验证 CDP:

curl http://127.0.0.1:9222/json/version curl http://127.0.0.1:9222/json/list

能返回 JSON,说明 Chromium 的 CDP 已经起来了。

linuxserver/chromium 默认没有强认证能力,官方也明确提醒不要直接暴露到公网。这里把端口绑在 127.0.0.1,就是为了把暴露面压到最小。 (LinuxServer)

1.8 回到Zero Trust页面,确认 Connectors 下有内容,点击下一步
image2604×1636 269 KB

1.9 输入你的域名信息,Service填写HTTP127.0.0.1:9222

1.10 注意:一定要在 Additional application settings → HTTP Settings → HTTP Host Header中输入127.0.0.1
image3114×2194 372 KB

这里因为 cloudflaredchromium 在同一个 Compose 网络里,所以可以直接访问。Tunnel 的入口走公网域名,Tunnel 后端走容器内网,不需要再绕宿主机。Docker Compose 官方文档也明确说明了,同一网络里的服务可以通过服务名互相发现。 (Docker Documentation)

Cloudflare Tunnel 的 published application 本质上就是“公网 Hostname → 本地 Service”的映射;通过 Dashboard 添加 route 时,Cloudflare 还会自动创建对应的 DNS 记录。 (Cloudflare Docs)

另外,CDP 底层会用到 WebSocket 升级连接。Cloudflare 支持代理 WebSocket 连接,不需要额外再套一层专门的 ws 代理。如果你之前手动把 Zone 的 WebSockets 关掉了,记得重新打开。 (Cloudflare Docs)


2. 先在 Cloudflare Access 外面套一层“保护壳”

进入:

Zero Trust → Access controls → Applications → Add an application → Self-hosted

填写:

  • Application domainchrome.example.com
  • 其他外观项保持默认即可

点击Create new policy

  • ActionBypass
  • IncludeIP ranges
  • Value你的 OpenClaw 服务器出口 IP/32

其余默认拒绝,打开审计日志。
image2380×1706 308 KB

也就是说,这个域名不是“谁知道地址谁就能连”,而是“只有从你那台 OpenClaw 服务器出来的请求,才允许打到 CDP”。

Cloudflare Access 的 IP ranges 本身就是标准策略选择器,适合这类固定来源机器访问;Access 默认也是 deny by default。 (Cloudflare Docs)

为什么这里默认推荐 IP allow,而不是 Service Token
Cloudflare 的 Service Token 很适合自动化系统,但它要求请求里带 CF-Access-Client-IdCF-Access-Client-Secret 头。OpenClaw 官方文档对远程 CDP 的主路径是配置 browser.profiles.<name>.cdpUrlbrowser.cdpUrl,并明确写了支持 HTTP(S)/WS(S)、URL query token 和 HTTP Basic auth,但没有把“给远程 CDP 单独注入 Cloudflare Access 头”作为标准入口写出来。所以对 OpenClaw 这类“只填一个 cdpUrl”的接入方式来说,固定出口 IP + Access Allow 是最通用、最少坑的方案。等你的接入层明确支持自定义 Access 头,再切 Service Auth 也不迟。 (Cloudflare Docs)


3. 启动 cloudflared

docker compose up -d cloudflared docker compose logs -f cloudflared

正常情况下,Tunnel 会很快连上 Cloudflare。


4. 按顺序验证整条链路

4.1 本地先看 Chromium 自己是否正常

curl http://127.0.0.1:9222/json/version curl http://127.0.0.1:9222/json/list

4.2 再看 cloudflared 容器能不能打到 Chromium

docker exec cloudflared wget -qO- http://chromium:9222/json/version

如果这一步拿不到 JSON,先别看 Cloudflare,先把 Docker 侧打通。

4.3 再从“允许的来源”验证公网域名

最好直接在 OpenClaw 那台服务器 上跑:

curl https://chrome.example.com/json/version curl https://chrome.example.com/json/list

如果这里能返回 JSON,说明:

  • Chromium 正常
  • Docker 网络正常
  • Tunnel 正常
  • Access 放行正常

如果你在自己电脑上测试却被拦截,不一定是坏事,往往只是因为你的电脑 不在 Access 的 IP 白名单里

如果 Tunnel 没连上,但 DNS 记录已经在,Cloudflare 侧常见现象是 1016。这是因为 DNS 记录和 Tunnel 本身是独立的,Tunnel 停了,记录不会自动删。 (Cloudflare Docs)


5. 接到 OpenClaw

OpenClaw 官方文档对远程 CDP 的说明很明确:

  • browser.profiles.<name>.cdpUrlbrowser.cdpUrl
  • 如果给的是 https://... 这类 HTTP(S) 入口,OpenClaw 会先请求 /json/version 获取 WebSocket debugger URL,再建立连接
  • 如果给的是 wss://...,就会直接走 WebSocket 连接 (OpenClaw)

一个最直接的配置示例:

{ "browser": { "profiles": { "remote": { "cdpUrl": "https://chrome.example.com/", "color": "#00AA00" } } } }

接好之后,建议按这个顺序验:

  1. 能列出 tabs openclaw browser tabs
  2. 能打开新页面 openclaw browser open
  3. 能 screenshot openclaw browser screenshot
  4. 能 snapshot / PDF openclaw browser snapshot

如果“能连上但截图/快照能力不完整”,再去看 OpenClaw 侧是否带了完整的浏览器/Playwright 依赖。OpenClaw 官方文档也说明了,部分高级能力依赖 Playwright。 (OpenClaw)


6. 常见故障排查顺序

6.1 本地 CDP 没起来

先看:

curl http://127.0.0.1:9222/json/version

没 JSON,就先不要继续排 Tunnel。

6.2 容器内网不通

看这条:

docker exec cloudflared wget -qO- http://chromium:9222/json/version

如果这里失败,问题在 Docker 网络或 Chromium 监听地址,不在 Cloudflare。

6.3 Access 拦截了

去 Zero Trust 的日志里看请求有没有命中策略。
尤其要确认 OpenClaw 服务器看到的 真实出口 IP 和你写进白名单的 IP 是同一个。

6.4 OpenClaw 的 cdpUrl 写错了

两个常见错误:

  • https://cdp.example.com/json/version 当成 cdpUrl 填进去
    HTTP(S) 模式下,通常应该填基础地址:https://cdp.example.com
  • 把 HTTP 入口和 WebSocket 入口混着用
    只有在你已经拿到明确的 ws:// / wss://.../devtools/browser/... 时,才直接填 WebSocket 地址。OpenClaw 文档也明确区分了这两种模式。 (OpenClaw)

6.5 Chromium 容器在老环境启动异常

linuxserver/chromium 官方文档提到,某些较老的内核或较老的 libseccomp 环境里,可能需要额外加:

security_opt: - seccomp=unconfined

这只在确实起不来时再加,不要默认就开。 (LinuxServer)

网友解答:
--【壹】--: zhfeng:

curl http://127.0.0.1:9222/json/list

佬 请教一下 我配置跟你一样 docker-compose 也跑起来了,但是为啥
root@debian:~# curl http://127.0.0.1:9222/json/version
curl http://127.0.0.1:9222/json/list
curl: (56) Recv failure: Connection reset by peer
curl: (56) Recv failure: Connection reset by peer
报错

但是我通过docker exec -it chromium curl http://127.0.0.1:9222/json/version
又可以返回json


--【贰】--:

技术贴必须顶


--【叁】--:

学习了,我的是在nas虚拟机上安装的openclaw,没有桌面,准备参考你这个方法,用docker部署一个浏览器给openclaw用


--【肆】--:

感谢大佬教程


--【伍】--:

可以继续试试能用域名访问不,如果可以的话就没问题


--【陆】--:

感谢佬友分享


--【柒】--:

这个很实用,感谢。


--【捌】--:

看的一脸懵逼


--【玖】--:

感谢大佬分享技术


--【拾】--:

感谢大佬,刚好需要


--【拾壹】--:

支持大佬


--【拾贰】--:

后面没搞定,我不加 Cloudflare Access 外面套一层“保护壳,
我通过网页访问

http://域名/json/version

可以出来游览器信息
{ "Browser": "Chrome/146.0.7680.164", "Protocol-Version": "1.3", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36", "V8-Version": "14.6.202.26", "WebKit-Version": "537.36 (@bbd8c5dd25fb2f52171abdff)", "webSocketDebuggerUrl": "ws://127.0.0.1/devtools/browser/aaa9af7b-c1-f7fec957af23" }
然后在服务器上 没办法
crul: 127.0.0.1:9222/json/version 没办法出来游览器信息
进入docker内部可以出游览器信息
3000 端口在网页访问也不会出游览器web 页面


--【拾叁】--:

大厂除了jvs 带了桌面 其他都没带。你这个好啊


--【拾肆】--:

好主意啊!我龙虾在本地,我可以在外网起一个浏览器给本地的龙虾用,解决了网络问题,感谢佬友分享!


--【拾伍】--:

很棒,学习了。

zhfeng:

security_opt: - seccomp=unconfined

确实是,老版本docker需要加这个,当然不推荐的–provileged也可以解决。


--【拾陆】--:

不错不错,教程很清晰


--【拾柒】--:

好强


--【拾捌】--:

这就把教程扔给我的去学习(


--【拾玖】--:

感谢分享(*ゝω・)