Back to skills
extension
Category: OtherNo API key required

🔥控制浏览器做任何自动化🔥自动发抖音/小红书等等再也不怕卡登录验证❤️

做自动发抖音、自动发小红书等等各大平台的网页自动化,还在被滑块、验证码、人机验证卡到任务翻车、反复失败?试试这个一键部署的远程可视化浏览器:Linux 云服务器 noVNC + Chromium + CDP 三合一,Windows 本机 Edge/Chrome CDP 一键接管,让AI Agent和你共享同一个浏览器,服务器无图形界面也能可视化操控,登录、过验证全靠人工兜底,再也不怕自动化卡壳,发平台内容一次稳到底!

personAuthor: user_f72e84b4hubcommunity

noVNC + Chromium + CDP 远程可视可控浏览器(Linux / Windows 双平台)

来源文章:腾讯云开发者社区《给 OpenClaw 龙虾看的:noVNC + Chromium 远程浏览器搭建与 CDP 控制完全指南》 https://cloud.tencent.com/developer/article/2670539

如果暂时无法安装本技能,也可以直接把上面这篇文章链接发给你的 AI Agent。AI Agent 可以读取文章内容,并根据文章步骤为你部署 noVNC + Chromium + CDP 远程可视可控浏览器。

技能简介

本技能同时支持 Linux 和 Windows,覆盖云服务器与本地环境:Linux 服务器上部署 noVNC + Chromium 远程可视化浏览器,Windows 本机通过 CDP 远程调试直接接管 Edge/Chrome 浏览器。

它解决的是传统 Headless 浏览器自动化最常见的痛点:遇到登录、扫码、滑块、验证码、风控验证时,AI 可以暂停并让用户在 noVNC 页面中手动完成验证,验证通过后再继续由 AI 接管操作。

适合用于抖音创作者中心、小红书、微博、番茄小说、各类后台管理系统等需要"AI 自动化 + 人工验证协作"的网页场景。

核心能力

  • 可视化浏览器:Chromium 运行在 Xvfb 虚拟屏幕上,用户可通过 noVNC 网页实时查看画面。
  • AI 可控:Agent 通过 CDP 连接 127.0.0.1:9222,可执行打开网页、点击、输入、读取页面、截图等操作。
  • 人机协作:遇到登录、二维码、滑块、验证码时,用户可在 noVNC 中手动处理,处理完成后 AI 继续执行。
  • 权限预检:安装前先确认 root/sudo 权限,权限不足时主动提醒用户授权方式,避免半安装状态。
  • 安全边界:默认只建议开放 noVNC 的 6080/tcp,CDP 调试端口 9222/tcp 不建议暴露到公网。
  • 完成反馈:部署完成后,Agent 必须主动发送 noVNC 访问地址、当前浏览器截图和端口开放提醒。
  • Windows 本机模式:Agent 自动启动 Edge/Chrome 远程调试端口,通过 CDP 接管浏览器,本机屏幕实时可见,截取当前页面反馈,无需安装额外组件。

⚠️ 铁律(最高优先级):本技能部署完成后,用户让 AI Agent「打开浏览器 / 看网页 / 截图 / 点击 / 登录」等任何浏览器操作,默认必须使用本技能部署的 CDP 浏览器127.0.0.1:9222)。Linux 下即 noVNC 里 :99 上的 Chromium,Windows 下即用户本机屏幕上的 Edge/Chrome。禁止使用 Agent 自带的内置 headless 浏览器或临时拉起其他实例,否则用户和 Agent 看到的画面不同频。完整规则见「十一、重要原则」。

推荐使用提示词

用户可以直接把下面任意一句发给 AI Agent 使用本技能:

使用tencent-novnc-chromium-cdp技能

或者更完整一句:

使用 tencent-novnc-chromium-cdp 技能,帮我部署 noVNC + Chromium 然后用CDP的方式远程控制Chromium浏览器。

如果用户希望部署完成后立刻拿到访问地址,可以使用:

技能 tencent-novnc-chromium-cdp 执行好了以后,请把 Chromium 的 noVNC 网站访问地址发给我,并附上当前浏览器截图。

Windows 用户可以使用:

使用 tencent-novnc-chromium-cdp 技能,帮我接管浏览器。

Agent 收到以上提示后,应完成以下动作:

  1. 加载并执行 tencent-novnc-chromium-cdp 技能;
  2. 开始部署前,先向用户发送配置、端口和预计耗时提醒;
  3. 检查服务器配置、系统环境和 root/sudo 权限;
  4. 安装过程中每 30 秒检查一次部署进度和关键进程状态,如发现依赖安装失败、进程未启动、端口未监听等问题,应先尝试自动修复,避免安装中断;
  5. 部署期间每分钟向用户发送一次简短进度消息,说明当前执行到哪一步,直到部署成功或遇到必须人工处理的问题;
  6. 安装并启动 Xvfb、Chromium、x11vnc、noVNC/websockify;
  7. 首次启动后自动打开 https://www.baidu.com/,用于确认浏览器和网络访问正常;
  8. 检测服务器公网 IP,生成 noVNC 访问地址;
  9. 截取当前 Chromium 浏览器画面,截图中应能看到百度页面;
  10. 主动回复用户 noVNC 地址、百度页面截图和端口开放提醒。

服务器配置要求与端口提醒

开始部署前必须先提醒用户

本技能需要安装系统依赖、下载 noVNC、启动 Chromium 图形浏览器和 VNC 转发服务,步骤较多。Agent 在正式执行安装前,应先发一条简短提醒,让用户知道部署需要等待一段时间。

推荐提醒话术:

开始部署 noVNC + Chromium 远程可视浏览器。

重要提示:服务器建议至少 2H4G。
端口提醒:必须在云服务器安全组放行 6080/tcp;5900/tcp 和 9222/tcp 为高级用途,可选开放,开放时建议限制来源 IP。
预计耗时:通常约 5-15 分钟;如果服务器配置较低、网络较慢或需要安装大量依赖,可能需要 20-30 分钟。部署过程中请耐心等待,不要中断。
Token 提醒:顺利部署预计消耗约 2万-5万 tokens;如果网络较慢、依赖安装失败、需要自动修复或多次重试,可能消耗 5万-10万+ tokens,实际以执行过程为准。开始前请确认当前会话/套餐剩余 Token 必须大于预计消耗,建议至少预留 10万 tokens 以上,避免部署过程中因 Token 不足中断。
进度提醒:安装过程中我会每 30 秒检查一次进度和服务状态,如有常见问题会先自动修复;并且每分钟向你汇报一次部署进度,直到安装成功。

如果检测到服务器配置低于 2H4G,应额外提醒用户可能出现 Chromium 卡顿、白屏或被系统杀掉的问题。

安装过程进度监控与自动修复

部署本技能时,Agent 不应长时间静默等待。正式开始安装后,应执行以下进度监控规则:

  1. 每 30 秒检查一次进度:检查当前安装命令是否仍在运行,查看最近日志,确认是否卡在依赖安装、软件下载、服务启动或端口监听阶段。
  2. 每 30 秒检查关键状态:重点检查 Xvfbchromiumx11vncwebsockify/noVNC 是否启动,6080/tcp9222/tcp 是否正常监听。
  3. 常见问题优先自动修复:如依赖缺失、包管理锁、残留旧进程、端口占用、Chromium 启动失败、noVNC 未下载完整等,应先尝试清理旧进程、重新安装依赖、重新启动服务或重新下载组件。
  4. 每分钟汇报一次进度:向用户发送简短消息,说明当前阶段,例如“正在安装系统依赖”“正在启动 Chromium”“正在检测 6080 端口”“正在截图确认百度页面”。
  5. 不要刷屏:进度消息保持简短,每分钟一次即可;只有遇到需要用户处理的问题时才立即额外提醒。
  6. 直到成功或需要人工介入:持续监控并汇报,直到 noVNC 地址可访问、Chromium 已打开百度页面、截图已生成;如果自动修复失败,应明确告诉用户失败步骤、原因和下一步需要用户做什么。

推荐进度消息示例:

部署进度:正在安装系统依赖,已开始自动检查安装状态,请耐心等待。
部署进度:依赖安装完成,正在启动 Xvfb 和 Chromium。
部署进度:Chromium 已启动,正在启动 noVNC 并检测 6080 端口。
部署进度:noVNC 已可访问,正在打开百度页面并截图确认。

最低服务器配置

本技能会启动 Chromium 图形浏览器、虚拟显示器和 VNC 转发服务,资源占用高于普通命令行脚本。建议服务器配置不低于:

最低推荐:2 核 CPU / 4GB 内存(2H4G)
系统推荐:Debian 10+ / Ubuntu 20.04+
磁盘建议:至少预留 5GB 可用空间

低于 2H4G 的服务器也可能启动成功,但容易出现 Chromium 卡顿、页面白屏、验证码页面 CPU 飙高、浏览器被系统杀掉等问题。

端口开放说明

必须开放:

  • 6080/tcp:noVNC 网页访问端口。用户通过 http://<服务器公网IP>:6080/vnc.html 打开远程 Chromium 浏览器。

可选开放:

  • 5900/tcp:VNC 原生端口。默认仅供本机 websockify 转发使用,一般不需要公网开放;只有需要用 VNC 客户端直连时才考虑开放,并建议限制来源 IP。
  • 9222/tcp:Chromium CDP 调试端口。默认仅供 Agent 在服务器本机控制浏览器使用;只有明确需要远程调试时才考虑开放,并必须限制来源 IP,避免浏览器被他人接管。

给用户的简短提醒可以写成:

重要提示:服务器建议至少 2H4G。
端口提醒:必须在云服务器安全组放行 6080/tcp;5900/tcp 和 9222/tcp 为高级用途,可选开放,开放时建议限制来源 IP。
预计耗时:通常约 5-15 分钟;网络较慢或首次安装依赖时可能需要 20-30 分钟,请耐心等待。
Token 提醒:顺利部署预计约 2万-5万 tokens;如遇报错、自动修复或多次重试,可能达到 5万-10万+ tokens。开始前请确认剩余 Token 必须大于预计消耗,建议至少预留 10万 tokens 以上,以免部署中断。
进度提醒:安装过程中 AI 会每 30 秒检查一次进度和服务状态,遇到常见问题会先自动修复,并且每分钟向你汇报一次部署进度,直到安装成功。

适用场景

本技能覆盖两种使用模式:

  • Linux 服务器模式:在云服务器上启动可视化浏览器,用户通过 noVNC 网页实时查看和手动操作,AI Agent 通过 CDP 控制同一实例。
  • Windows 本机模式:直接在用户本机启动 Edge/Chrome 远程调试端口,Agent 通过 CDP 接管,用户在本机屏幕上实时看到所有操作。

典型场景:

  • 登录类后台:抖音创作者中心、小红书创作者平台、微博、公众号后台等。
  • 风控验证:滑块验证、扫码登录、短信验证、图形验证码、设备验证等。
  • 内容发布:自动打开发布页、填写标题/正文/标签/封面,并让用户处理最后的人工验证。
  • 网页调试:需要用户和 AI 同时看到同一个浏览器画面,方便排查页面状态。

不适合场景:

  • 纯 API 调用任务,不需要浏览器画面。
  • 对安全要求极高、不能暴露任何远程桌面入口的生产环境。
  • Linux 模式:无法开放 6080/tcp 或无法提供 root/sudo 权限的服务器。(Windows 模式无此限制)

最终效果:

Linux 模式:

  • 用户访问:http://<服务器IP>:6080/vnc.html
  • Agent 控制:http://127.0.0.1:9222/json / CDP WebSocket
  • 浏览器运行在虚拟显示器 :99

Windows 模式:

  • 用户在本机屏幕直接看到 Edge/Chrome 浏览器
  • Agent 控制:http://127.0.0.1:9222/json / CDP WebSocket
  • 无需额外安装任何组件

数据流:

Linux:Chromium → Xvfb 虚拟屏幕 → x11vnc → noVNC/websockify → 用户浏览器
Windows:Edge/Chrome(用户本机屏幕)→ CDP :9222 → Agent 控制

使用示例:打开抖音创作者平台

部署完成后,Agent 可以通过 CDP 打开目标网站,用户通过 noVNC 观看和接管:

python3 - <<'PY'
import json, time, urllib.request
import websocket

target_url = 'https://creator.douyin.com/'
tabs = json.load(urllib.request.urlopen('http://127.0.0.1:9222/json'))
page = next(t for t in tabs if t.get('type') == 'page')
ws = websocket.create_connection(page['webSocketDebuggerUrl'], header=['Origin: http://127.0.0.1:9222'], timeout=20)

msg_id = 0
def call(method, params=None):
    global msg_id
    msg_id += 1
    ws.send(json.dumps({'id': msg_id, 'method': method, 'params': params or {}}))
    while True:
        msg = json.loads(ws.recv())
        if msg.get('id') == msg_id:
            return msg

call('Page.enable')
call('Runtime.enable')
call('Page.navigate', {'url': target_url})
time.sleep(5)
res = call('Runtime.evaluate', {
    'expression': '({title: document.title, url: location.href})',
    'returnByValue': True,
})
print(json.dumps(res['result']['result']['value'], ensure_ascii=False, indent=2))
ws.close()
PY

预期效果:

  • noVNC 页面中能看到 Chromium 打开的抖音创作者平台;
  • 如果页面要求扫码/验证码/滑块,用户可在 noVNC 中手动完成;
  • 验证完成后,Agent 继续通过 CDP 自动操作当前浏览器。

组件说明

Linux 模式组件

| 组件 | 作用 | |---|---| | Xvfb | 提供虚拟显示器,例如 :99 | | Chromium | 真正的浏览器,开启 CDP 端口 9222 | | x11vnc | 把 Xvfb 画面转换成 VNC 协议 | | noVNC + websockify | 把 VNC 转成网页可访问的 WebSocket 页面 |

Windows 模式组件

| 组件 | 作用 | |---|---| | Edge / Chrome | 用户本机浏览器,开启 CDP 端口 9222 | | 本机屏幕 | 用户直接看到浏览器画面,无需 noVNC |

零、系统检测(第一步,必须执行)

Agent 加载本技能后,第一步必须先检测当前操作系统

# 第一步:检测操作系统
uname -s 2>/dev/null | grep -qi linux && echo "LINUX" || true

# 如果是 Linux,再细分环境类型(云服务器 / NAS / 本地 Linux)
if [ "$(uname -s)" = "Linux" ]; then
  # 检测是否云服务器(腾讯云/阿里云/AWS metadata)
  if curl -s --connect-timeout 2 http://metadata.tencentyun.com/latest/meta-data/ 2>/dev/null | grep -q .; then
    echo "ENV_TYPE=CLOUD"
  elif curl -s --connect-timeout 2 http://100.100.100.200/latest/meta-data/ 2>/dev/null | grep -q .; then
    echo "ENV_TYPE=CLOUD"
  elif curl -s --connect-timeout 2 http://169.254.169.254/latest/meta-data/ 2>/dev/null | grep -q .; then
    echo "ENV_TYPE=CLOUD"
  # 检测是否 NAS(群晖 Synology / QNAP 威联通)
  elif [ -f /etc/synoinfo.conf ]; then
    echo "ENV_TYPE=NAS"
  elif [ -f /etc/platform.conf ] || [ -f /etc/version ]; then
    echo "ENV_TYPE=NAS"
  else
    echo "ENV_TYPE=LOCAL"
  fi
fi

分流逻辑

  • 检测到 Linux(CLOUD / NAS / LOCAL) → 继续执行「一、检查系统与服务器配置」及后续章节(noVNC + Chromium 远程部署流程)。完成后根据环境类型发送对应地址:
    • CLOUD(云服务器)→ 发送公网 IP 的 noVNC 地址
    • NAS(NAS 设备)→ 发送本地内网 IP 的 noVNC 地址,并提醒用户在 NAS 控制面板开放 6080 端口
    • LOCAL(本地 Debian/Ubuntu)→ 发送本地内网 IP 的 noVNC 地址,并提醒用户放行系统防火墙 6080 端口
  • 检测到 Windows → 跳过 Linux 部署章节,直接跳转到「十二、Windows 系统:远程调试 CDP 控制 Edge/Chrome」。

以下「一」至「六-bis」仅适用于 Linux 系统(含 CLOUD / NAS / LOCAL)。

一、检查系统与服务器配置

cat /etc/os-release | head -3
uname -m
nproc
free -h
df -h /

推荐环境:Debian 10+ / Ubuntu 20.04+ / 较新的 Linux 发行版。

配置要求:建议至少 2 核 CPU / 4GB 内存(2H4G)。如果内存低于 4GB,Agent 应先提醒用户可能出现 Chromium 卡顿、白屏或被系统杀掉的问题,再继续安装。

二、权限预检(必须)

部署本技能需要安装系统包、写入 /opt/root/start-remote-browser.sh,通常需要 root 或可用的 sudo 权限。Agent 通常已具备执行权限,如遇到以下情况直接要求用户提供即可:

如果已经具备 root 权限,直接继续;如果没有,直接向用户要 root 凭据,不用绕弯子。

权限不足时,Agent 直接发:

当前环境没有 root 权限,无法继续部署。请提供以下信息:
- 服务器公网 IP
- SSH 端口(默认 22)
- SSH 用户名(通常是 root)
- SSH 密码

以上凭据仅用于本技能部署(安装系统依赖、写入 /opt 和 /root/start-remote-browser.sh),
不会被用于其他用途。部署完成后建议修改密码。

无需再建议用户切换到 root 自己执行、配置 sudo、临时账号、Secret 等替代方案。拿到凭据直接用。

if [ "$(id -u)" = "0" ]; then
  echo "PERMISSION_OK: 当前是 root 用户"
elif command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
  echo "PERMISSION_OK: 当前用户可免密 sudo"
else
  echo "PERMISSION_DENIED: 当前用户不是 root,且无法免密 sudo。请提供服务器IP、SSH端口、SSH用户名和密码。"
fi

三、安装依赖

Debian / Ubuntu:

apt update && apt upgrade -y
apt install -y xvfb x11vnc git python3-pip curl wget ca-certificates

优先安装 deb 版 Chromium/Chrome

本技能需要通过 CDP 控制浏览器,安装浏览器时推荐优先安装 deb 包形式的 Chromium/Chrome。如果 deb 版安装失败,再自动切换至系统可用的其他 Chromium/Chrome 版本,保证部署流程尽量不中断。

安装时应先检测系统类型,并按“deb 版优先、失败后自动切换至其他版本”的策略执行:

. /etc/os-release

if [ "$ID" = "debian" ]; then
  apt install -y chromium || apt install -y chromium-browser || true
elif [ "$ID" = "ubuntu" ]; then
  echo "Ubuntu 环境优先安装 deb 版 Chrome 作为 Chromium/CDP 兼容浏览器。"
  if wget -O /tmp/google-chrome-stable_current_amd64.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb; then
    apt install -y /tmp/google-chrome-stable_current_amd64.deb || true
  fi
  if command -v google-chrome-stable >/dev/null 2>&1; then
    ln -sf /usr/bin/google-chrome-stable /usr/local/bin/chromium
  else
    echo "deb 版 Chrome 安装失败,尝试安装系统源 Chromium/Chromium Browser。"
    apt install -y chromium || apt install -y chromium-browser || true
  fi
else
  apt install -y chromium || apt install -y chromium-browser || true
fi

CHROME_BIN=$(command -v chromium || command -v chromium-browser || command -v google-chrome-stable || true)
if [ -z "$CHROME_BIN" ]; then
  echo "ERROR: 未找到 Chromium/Chrome 可执行文件"
  exit 1
fi

echo "浏览器路径:$CHROME_BIN"

安装 noVNC 和 websockify:

cd /opt
if [ ! -d /opt/noVNC ]; then
  git clone https://github.com/novnc/noVNC.git
fi
pip3 install websockify --break-system-packages

如果 noVNC master 版本在 Chrome 中出现 ES module 报错,可固定到稳定版:

cd /opt/noVNC
git fetch --tags
git checkout v1.6.0

四、开放端口

服务器本机防火墙:

# ⚠️ 9222 是 CDP 调试端口,公网暴露意味着任何人可远程控制浏览器。
# Agent 必须在放行后立即提醒用户:安全组限制来源 IP,或仅在使用 CDP 时临时开放。
ufw allow 6080/tcp || true
ufw allow 9222/tcp || true
ufw reload || true

云厂商安全组也要放行:

  • 6080/tcp:noVNC 网页访问端口
  • 9222/tcp:CDP 调试端口(如不需要外网访问 CDP,可只允许本机)

五、创建一键启动脚本

1. 生成 noVNC 访问密码(必须)

为防止 noVNC 端口(6080)被裸暴露公网导致浏览器被任何人接管,启动前必须生成一个 5–10 位随机密码(字母+数字混合),并让 x11vnc 用密码模式启动。Agent 必须把这个密码原文保存到固定路径,方便部署后回复给用户。

# 5-10 位随机密码(字母+数字混合),这里固定生成 8 位
NOVNC_PASS=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 8)
echo -n "$NOVNC_PASS" > /root/.novnc_password
chmod 600 /root/.novnc_password

# 用 x11vnc 自己的工具生成 VNC 密码文件
x11vnc -storepasswd "$NOVNC_PASS" /root/.vncpasswd
chmod 600 /root/.vncpasswd

echo "noVNC 访问密码已生成:$NOVNC_PASS"
echo "明文存储于:/root/.novnc_password(仅 root 可读)"
echo "VNC 密码文件:/root/.vncpasswd"

后续 x11vnc 启动必须使用 -rfbauth /root/.vncpasswd不再使用 -nopw

2. 写入 /root/start-remote-browser.sh

写入 /root/start-remote-browser.sh

cat > /root/start-remote-browser.sh <<'SCRIPT_END'
#!/bin/bash
set -e

pkill -9 -f x11vnc 2>/dev/null || true
pkill -9 -f Xvfb 2>/dev/null || true
pkill -9 -f websockify 2>/dev/null || true
pkill -9 -f 'chromium.*remote-debugging-port=9222' 2>/dev/null || true
sleep 2

echo "[1/4] 启动虚拟显示器..."
Xvfb :99 -screen 0 1920x1080x24 &
sleep 1
export DISPLAY=:99

echo "[2/4] 启动 Chromium (CDP:9222)..."
CHROME_BIN=$(command -v chromium || command -v chromium-browser || command -v google-chrome-stable || true)
if [ -z "$CHROME_BIN" ]; then
  echo "ERROR: 未找到 Chromium/Chrome 可执行文件"
  exit 1
fi
# ⚠️ 默认监听 0.0.0.0 以便远程 CDP。如不需要远程调试,可改为 127.0.0.1。
"$CHROME_BIN" \
  --no-sandbox \
  --disable-gpu \
  --disable-dev-shm-usage \
  --remote-debugging-port=9222 \
  --remote-debugging-address=0.0.0.0 \
  --remote-allow-origins='*' \
  --window-size=1920,1080 \
  --start-maximized \
  --no-first-run \
  --no-default-browser-check \
  --user-data-dir=/root/.chromium-remote \
  --restore-last-session=false \
  https://www.baidu.com/ &
sleep 3

echo "[3/4] 启动 x11vnc..."
x11vnc -display :99 -forever -rfbauth /root/.vncpasswd -quiet -listen 127.0.0.1 &
sleep 1

echo "[4/4] 启动 noVNC (端口:6080)..."
websockify --web /opt/noVNC 6080 127.0.0.1:5900 &
sleep 1

IP=$(hostname -I | awk '{print $1}')
echo ""
echo "========================================"
echo "  ✅ 远程浏览器已就绪"
echo "  用户访问: http://${IP}:6080/vnc.html"
echo "  CDP: http://${IP}:9222/json"
echo "========================================"
SCRIPT_END

chmod +x /root/start-remote-browser.sh

六、启动远程浏览器

bash /root/start-remote-browser.sh

启动完成后,用户访问:

http://<服务器IP>:6080/vnc.html

CDP 检查地址:

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

六-bis、配置开机自启(必须)

为了确保服务器重启后 noVNC + Chromium + CDP 仍能自动恢复运行,必须把整套服务做成 systemd 单元,不能只依赖一次性的 bash /root/start-remote-browser.sh

部署完成后必须执行以下步骤,并启用 enable --now,使服务立即生效 + 开机自启

# 1) Xvfb 虚拟显示器
cat > /etc/systemd/system/xvfb.service <<'EOF'
[Unit]
Description=Xvfb virtual display :99
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/Xvfb :99 -screen 0 1920x1080x24 -ac
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF

# 2) x11vnc(必须使用 -rfbauth 走密码模式)
cat > /etc/systemd/system/x11vnc.service <<'EOF'
[Unit]
Description=x11vnc server on :99 (password protected)
After=xvfb.service
Requires=xvfb.service

[Service]
Type=simple
Environment=DISPLAY=:99
ExecStart=/usr/bin/x11vnc -display :99 -forever -shared -rfbauth /root/.vncpasswd -rfbport 5900 -quiet
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF

# 3) noVNC websockify
cat > /etc/systemd/system/novnc.service <<'EOF'
[Unit]
Description=noVNC websockify on 6080
After=x11vnc.service
Requires=x11vnc.service

[Service]
Type=simple
ExecStart=/usr/local/bin/websockify --web=/opt/noVNC 6080 localhost:5900
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF

# 4) Chromium + CDP(自动找可用 Chromium/Chrome 二进制)
CHROME_BIN=$(command -v chromium || command -v chromium-browser || command -v google-chrome-stable)
cat > /etc/systemd/system/chromium-remote.service <<EOF
[Unit]
Description=Chromium with CDP on :9222, display :99
After=xvfb.service
Requires=xvfb.service
StartLimitBurst=3
StartLimitInterval=120

[Service]
Type=simple
Environment=DISPLAY=:99
ExecStart=${CHROME_BIN} --no-sandbox --disable-gpu --disable-dev-shm-usage --disable-session-crashed-bubble --restore-last-session=false --remote-debugging-port=9222 --remote-debugging-address=127.0.0.1 --remote-allow-origins=* --user-data-dir=/root/.chromium-remote --no-first-run --no-default-browser-check --window-size=1920,1080 --start-maximized https://www.baidu.com/
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now xvfb.service x11vnc.service novnc.service chromium-remote.service

验证(应全部 active):

systemctl is-active xvfb x11vnc novnc chromium-remote
ss -tlnp | grep -E ':6080|:5900|:9222'

重启服务器后,Agent 和用户都不需要再手动跑 start-remote-browser.sh,整套服务会自动拉起来。

七、通过 CDP 打开网页

使用 Python 控制已启动的 visible Chromium:

python3 - <<'PY'
import json, time, urllib.request
import websocket

url = 'https://example.com'
tabs = json.load(urllib.request.urlopen('http://127.0.0.1:9222/json'))
page = next(t for t in tabs if t.get('type') == 'page')
ws = websocket.create_connection(
    page['webSocketDebuggerUrl'],
    header=['Origin: http://127.0.0.1:9222'],
    timeout=20,
)

msg_id = 0
def call(method, params=None):
    global msg_id
    msg_id += 1
    ws.send(json.dumps({'id': msg_id, 'method': method, 'params': params or {}}))
    while True:
        msg = json.loads(ws.recv())
        if msg.get('id') == msg_id:
            return msg

call('Page.enable')
call('Runtime.enable')
call('Page.navigate', {'url': url})
time.sleep(3)
res = call('Runtime.evaluate', {
    'expression': '({title: document.title, url: location.href})',
    'returnByValue': True,
})
print(json.dumps(res['result']['result']['value'], ensure_ascii=False, indent=2))
ws.close()
PY

如果缺少 websocket 包:

pip3 install websocket-client --break-system-packages

截图说明:Linux 模式下可使用 DISPLAY=:99 import -window root 截图;Windows 模式下应通过 CDP Page.captureScreenshot 截图(参见「十二、Windows 系统」第 3 节)。

八、完成后必须回复用户

启动成功后,Agent 必须把以下内容发送给用户,不要只在终端里打印链接:

  1. noVNC 浏览器访问地址: http://<服务器IP>:6080/vnc.html

  2. noVNC 访问密码(必须发给用户): 读取部署时生成的密码文件并连同地址一起发给用户,不能省略,否则用户无法登录 noVNC:

    cat /root/.novnc_password
    
  3. 首次打开百度页面并截图:

    • 安装/启动完成后,Agent 必须先让 Chromium 打开 https://www.baidu.com/
    • 然后截图发给用户,用于确认远程浏览器正常运行、noVNC 画面正常、服务器可以访问外网
  4. 当前浏览器截图: 使用命令: DISPLAY=:99 import -window root /tmp/remote-browser.png

    如果当前对话通道是 QQbot/QQ 通道,发图方式比较特殊:截图文件必须放到 ~/.openclaw/media/qqbot/ 目录下,并使用 <qqmedia> 标签发送,不能只使用普通 MEDIA: 路径。

    mkdir -p ~/.openclaw/media/qqbot
    cp /tmp/remote-browser.png ~/.openclaw/media/qqbot/remote-browser.png
    

    QQbot 回复中使用:

    <qqmedia>/root/.openclaw/media/qqbot/remote-browser.png</qqmedia>
    

    非 QQbot 通道可继续使用普通媒体附件格式:

    MEDIA:/tmp/remote-browser.png
    
  5. 提醒用户开放端口:

    • 云服务器安全组需要放行 6080/tcp
    • 如果系统开启了防火墙,也需要放行 6080/tcp
    • 9222/tcp 是 CDP 调试控制端口,默认只建议 Agent 本机使用,不建议对公网开放

1. 检测服务器公网 IP 并生成 noVNC 地址

优先检测服务器公网 IP;如果能检测到公网 IP,就发公网地址。检测失败时,再退回本机内网 IP。

# 根据环境类型选择 IP(ENV_TYPE 在「零、系统检测」步骤中已设置)
if [ "$ENV_TYPE" = "CLOUD" ]; then
  # 云服务器:优先使用公网 IP
  PUBLIC_IP=$(curl -4 -s https://ifconfig.me 2>/dev/null || curl -4 -s https://api.ipify.org 2>/dev/null || true)
  if [ -n "$PUBLIC_IP" ]; then
    NOVNC_URL="http://${PUBLIC_IP}:6080/vnc.html"
  else
    LOCAL_IP=$(hostname -I | awk '{print $1}')
    NOVNC_URL="http://${LOCAL_IP}:6080/vnc.html"
  fi
else
  # NAS / 本地 Linux:直接使用内网 IP
  LOCAL_IP=$(hostname -I | awk '{print $1}')
  NOVNC_URL="http://${LOCAL_IP}:6080/vnc.html"
fi
echo "$NOVNC_URL"
echo "ENV_TYPE=$ENV_TYPE"

2. 首次打开百度并截取当前 Chromium 浏览器画面

启动后必须先打开百度页面,用百度页面作为"浏览器正常运行"的可视化确认页:

python3 - <<'PY'
import json, time, urllib.request
import websocket

tabs = json.load(urllib.request.urlopen('http://127.0.0.1:9222/json'))
page = next(t for t in tabs if t.get('type') == 'page')
ws = websocket.create_connection(page['webSocketDebuggerUrl'], header=['Origin: http://127.0.0.1:9222'], timeout=20)

msg_id = 0
def call(method, params=None):
    global msg_id
    msg_id += 1
    ws.send(json.dumps({'id': msg_id, 'method': method, 'params': params or {}}))
    while True:
        msg = json.loads(ws.recv())
        if msg.get('id') == msg_id:
            return msg

call('Page.enable')
call('Page.navigate', {'url': 'https://www.baidu.com/'})
time.sleep(3)
ws.close()
PY

如果服务器安装了 ImageMagick 的 import 命令:

DISPLAY=:99 import -window root /tmp/remote-browser.png
mkdir -p ~/.openclaw/media/qqbot
cp /tmp/remote-browser.png ~/.openclaw/media/qqbot/remote-browser.png

注意:只有检测到用户来自 QQbot/QQ 通道时,才必须复制到 ~/.openclaw/media/qqbot/ 并使用 <qqmedia> 标签;其他平台优先使用平台原生媒体发送方式。

3. 回复格式示例

Agent 完成安装/启动后,必须根据环境类型(ENV_TYPE,在「零、系统检测」步骤中已确定)向用户发送对应的回复。

云服务器(ENV_TYPE=CLOUD)

远程 Chromium 浏览器已启动:

- noVNC 地址:http://<服务器公网IP>:6080/vnc.html
- noVNC 访问密码:<在这里填入 /root/.novnc_password 的内容>
- 浏览器状态:已自动打开百度页面,并已附上截图用于确认浏览器正常运行
- 开机自启:已配置 systemd(xvfb / x11vnc / novnc / chromium-remote),服务器重启后自动拉起
- CDP 地址:仅供 Agent 本机控制使用,不建议公开
- 端口提醒:请确认云服务器安全组已放行 6080/tcp;如果系统开启防火墙,也要放行 6080/tcp
- 如果遇到登录、验证码、滑块,请在 noVNC 页面手动完成,完成后告诉我继续。

MEDIA:/tmp/remote-browser.png

NAS 设备(ENV_TYPE=NAS)

远程 Chromium 浏览器已启动:

- noVNC 地址:http://<NAS内网IP>:6080/vnc.html
- noVNC 访问密码:<在这里填入 /root/.novnc_password 的内容>
- 🌐 这是 NAS 设备的局域网地址,请在局域网内的设备上打开上述链接访问远程浏览器
- 端口提醒:请在 NAS 控制面板 → 防火墙/安全设置中放行 6080/tcp 端口;如果通过路由器访问,还需在路由器上设置端口转发
- 浏览器状态:已自动打开百度页面,并已附上截图用于确认浏览器正常运行
- 开机自启:已配置 systemd(xvfb / x11vnc / novnc / chromium-remote),NAS 重启后自动拉起
- CDP 地址:仅供 Agent 本机控制使用,不建议公开
- 如果遇到登录、验证码、滑块,请在 noVNC 页面手动完成,完成后告诉我继续。

MEDIA:/tmp/remote-browser.png

本地 Linux(ENV_TYPE=LOCAL)

远程 Chromium 浏览器已启动:

- noVNC 地址:http://<本机内网IP>:6080/vnc.html
- noVNC 访问密码:<在这里填入 /root/.novnc_password 的内容>
- 🌐 这是本机的局域网地址,请在局域网内的其他设备上打开上述链接访问远程浏览器
- 端口提醒:请确保本机防火墙已放行 6080/tcp(ufw allow 6080/tcp 或 iptables 放行)
- 浏览器状态:已自动打开百度页面,并已附上截图用于确认浏览器正常运行
- 开机自启:已配置 systemd(xvfb / x11vnc / novnc / chromium-remote),系统重启后自动拉起
- CDP 地址:仅供 Agent 本机控制使用,不建议公开
- 如果遇到登录、验证码、滑块,请在 noVNC 页面手动完成,完成后告诉我继续。

MEDIA:/tmp/remote-browser.png

QQbot/QQ 通道适配

如果用户来自 QQbot/QQ 通道,上述模板中的 MEDIA:/tmp/remote-browser.png 必须替换为:

mkdir -p ~/.openclaw/media/qqbot
cp /tmp/remote-browser.png ~/.openclaw/media/qqbot/remote-browser.png
<qqmedia>/root/.openclaw/media/qqbot/remote-browser.png</qqmedia>

注意:只有检测到用户来自 QQbot/QQ 通道时,才必须复制到 ~/.openclaw/media/qqbot/ 并使用 <qqmedia> 标签;其他平台优先使用平台原生媒体发送方式。

4. Windows 模式回复格式示例

Agent 在 Windows 模式下完成接管后,必须向用户发送类似下面的回复:

✅ 浏览器已完全由 AI Agent 控制。

- 浏览器:Edge/Chrome(CDP 端口 9222)
- 你可以在屏幕上看到所有操作,随时手动接管
- 请勿关闭这个浏览器窗口
- 如果遇到登录、验证码、滑块,你直接操作即可,完成后告诉我继续

MEDIA:/tmp/browser_screenshot.png

QQbot/QQ 通道下截图的发送方式与 Linux 模式相同,参考上文。

也可以用 CDP 截图:

python3 - <<'PY'
import json, base64, urllib.request
import websocket

tabs = json.load(urllib.request.urlopen('http://127.0.0.1:9222/json'))
page = next(t for t in tabs if t.get('type') == 'page')
ws = websocket.create_connection(page['webSocketDebuggerUrl'], header=['Origin: http://127.0.0.1:9222'], timeout=30)
ws.send(json.dumps({'id': 1, 'method': 'Page.captureScreenshot', 'params': {'format': 'jpeg', 'quality': 70}}))
while True:
    msg = json.loads(ws.recv())
    if msg.get('id') == 1:
        data = base64.b64decode(msg['result']['data'])
        open('/tmp/remote-browser-cdp.jpg', 'wb').write(data)
        print('/tmp/remote-browser-cdp.jpg')
        break
ws.close()
PY

九、验证清单

Linux 模式验证

ss -tlnp | grep -E '6080|5900|9222'
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:6080/vnc.html
curl -s http://127.0.0.1:9222/json/version

应满足:

  • 6080 正在监听
  • 5900 正在监听本机 VNC
  • 9222 正在监听 CDP
  • vnc.html 返回 200
  • 用户能在浏览器看到远程 Chromium 画面

Windows 模式验证

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

应满足:

  • 9222 正在监听 CDP
  • json/version 返回浏览器信息
  • json 返回至少一个 page 类型的标签
  • 用户本机屏幕上能看到 Edge/Chrome 浏览器窗口

十、常见问题

Linux 模式

1. noVNC 打开空白或连不上

检查进程:

ps -ef | grep -E 'Xvfb|chromium|x11vnc|websockify' | grep -v grep
ss -tlnp | grep -E '6080|5900|9222'

重新运行:

bash /root/start-remote-browser.sh

2. 外网打不开 6080

需要同时检查:

  • 云服务器安全组是否放行 6080/tcp
  • 系统防火墙是否放行 6080/tcp
  • websockify 是否监听 0.0.0.0:6080

3. CDP WebSocket 403

Chromium 启动参数需要包含:

--remote-allow-origins='*'

Python websocket 连接时建议带 Origin:

websocket.create_connection(ws_url, header=['Origin: http://127.0.0.1:9222'])

4. 浏览器画面卡住

可清理重启:

pkill -9 -f chromium || true
pkill -9 -f Xvfb || true
pkill -9 -f x11vnc || true
pkill -9 -f websockify || true
bash /root/start-remote-browser.sh

5. noVNC 报前端 JS 错误

如果使用 noVNC master 分支出现浏览器兼容问题,固定稳定版本:

cd /opt/noVNC
git fetch --tags
git checkout v1.6.0
bash /root/start-remote-browser.sh

Windows 模式

6. Edge/Chrome 无法以 CDP 模式启动

浏览器可能已经在运行中。需要先关闭所有 Edge/Chrome 窗口,再执行:

taskkill /F /IM msedge.exe
taskkill /F /IM chrome.exe
start msedge --remote-debugging-port=9222 --remote-allow-origins=*

7. CDP 端口 9222 被占用

检查端口占用并释放:

netstat -ano | findstr :9222
taskkill /F /PID <PID>

然后重新启动浏览器。

8. CDP WebSocket 403 / 连接拒绝

确认启动参数包含 --remote-allow-origins=*。如果仍然 403,尝试在连接时带 Origin header:

websocket.create_connection(ws_url, header=['Origin: http://127.0.0.1:9222'])

十一、重要原则

1. 浏览器使用范围:默认必须使用本技能的 CDP Chromium(最高优先级)

铁律:用户已经安装并启动了本技能后,只要用户让 AI Agent「打开浏览器 / 访问网页 / 看某个网站 / 截图 / 点击页面 / 操作表单 / 登录账号 / 处理验证码」,Agent 默认必须使用本技能部署的 CDP 浏览器127.0.0.1:9222):Linux 下即 :99 虚拟显示器上、用户在 noVNC 里能看到的那个 Chromium;Windows 下即用户本机屏幕上的 Edge/Chrome。

严禁在没有用户明确指示的情况下使用:

  • Agent 自带的内置 headless 浏览器(如 Hermes 的 browser_navigate / browser_click / browser_snapshot 等工具)
  • 临时拉起的另一个 Playwright / Puppeteer / Selenium 实例
  • Linux 下任何运行在其他 DISPLAY 或其他端口的 Chromium / Chrome 进程
  • Windows 下任何非本技能启动的 Edge / Chrome 实例

为什么

  • Linux:用户在 noVNC 页面里看到的画面,只来自 :99 上的那个 Chromium。如果 Agent 用别的浏览器,用户看不到 Agent 在操作什么 → 两边不同频,无法人工接管验证码 / 滑块 / 登录。
  • Windows:用户看到的是本机屏幕上的浏览器窗口,如果 Agent 另开一个 headless 或别的浏览器,用户同样看不到,失去了「人机协作」的意义。
  • 登录态、Cookie、Local Storage、扩展只在被接管的那个浏览器里有,换浏览器全部丢失。
  • 用户的核心诉求就是「AI 自动化 + 我能看见 + 我能随时接管」,换浏览器会直接破坏这个协作模型。

正确做法:通过 127.0.0.1:9222 的 CDP 接口控制这个 Chromium(参见「七、通过 CDP 打开网页」节):

# 列出当前标签
curl -s http://127.0.0.1:9222/json
# 然后用 websocket 连 webSocketDebuggerUrl 发 Page.navigate / Input.dispatchMouseEvent 等

唯一例外:用户明确说「用你自己的浏览器」「用 headless 跑」「不要走 noVNC」之类的指令时,才可以切换到其他浏览器实例;否则一律走 CDP。

2. 其他原则

  • Linux:noVNC 里的 Chromium 是用户可见浏览器
  • Windows:用户本机屏幕上的 Edge/Chrome 是用户可见浏览器
  • Agent 内置的 headless browser 工具通常是另一个浏览器实例,不能代表用户可见画面。
  • 用户需要看到操作时,应控制 127.0.0.1:9222 的 CDP 浏览器。

十二、Windows 系统:远程调试 CDP 控制 Edge/Chrome

当「零、系统检测」判断为 Windows 时,走以下流程。Windows 模式下无需安装任何依赖,直接利用系统自带的 Edge 或 Chrome 浏览器。

启动流程

Agent 必须优先自动尝试启动浏览器,失败后才让用户手动执行。

1. 自动启动(Agent 执行)

Agent 先尝试启动 Edge,失败则回退到 Chrome:

# 优先尝试 Edge
start msedge --remote-debugging-port=9222 --remote-allow-origins=*
# Edge 不可用时尝试 Chrome
start chrome --remote-debugging-port=9222 --remote-allow-origins=*

如果两个命令都执行失败(浏览器未安装、权限不足等),才告诉用户手动执行以下命令:

请以管理员身份打开 PowerShell 或 CMD,执行以下命令:

Edge:
start msedge --remote-debugging-port=9222 --remote-allow-origins=*

或 Chrome:
start chrome --remote-debugging-port=9222 --remote-allow-origins=*

2. 验证 CDP 连通性

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

3. 截图当前页面

验证连通后,通过 CDP 对当前默认页面(新标签页或浏览器主页)截图。Windows 模式不需要额外导航到百度页面,直接截取浏览器当前画面即可。

# 获取当前页面
curl -s http://127.0.0.1:9222/json
# 通过 CDP 截取页面截图,保存为 PNG
python3 - <<'PY'
import json, base64, urllib.request
tabs = json.load(urllib.request.urlopen('http://127.0.0.1:9222/json'))
page = next(t for t in tabs if t.get('type') == 'page')
import websocket
ws = websocket.create_connection(page['webSocketDebuggerUrl'], header=['Origin: http://127.0.0.1:9222'], timeout=20)
msg_id = 0
def call(method, params=None):
    global msg_id
    msg_id += 1
    ws.send(json.dumps({'id': msg_id, 'method': method, 'params': params or {}}))
    while True:
        msg = json.loads(ws.recv())
        if msg.get('id') == msg_id:
            return msg
call('Page.enable')
res = call('Page.captureScreenshot', {'format': 'png'})
with open('/tmp/browser_screenshot.png', 'wb') as f:
    f.write(base64.b64decode(res['result']['data']))
print('截图已保存: /tmp/browser_screenshot.png')
ws.close()
PY

将截图通过 MEDIA 发送给用户。

4. 完成提醒

截图发送后,Agent 必须回复用户:

✅ 浏览器已完全由 AI Agent 控制,你可以在屏幕上看到所有操作,随时手动接管。请勿关闭这个浏览器窗口。

Windows 模式后续使用

接管完成后,Agent 后续所有浏览器操作(打开网页、点击、输入、截图等)均通过 127.0.0.1:9222 的 CDP 接口控制这个浏览器实例。用户在本机屏幕上可实时看到所有操作,遇到登录、验证码时可随时手动介入。