docs(runbook): browser desktop mode, HTTPS and prototype verification

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-29 02:30:55 +08:00
1 parent 67c8542498
commit d0884bca37
1 file changed
+97 -2
+97 -2
View File
@@ -23,16 +23,20 @@ docker compose --env-file .env.deploy up -d --build
docker compose ps camofox # healthy 即可
```
上游不发布镜像,compose 用 `docker/camofox/Dockerfile` 从 git tag `v1.17.0` 构建(修了上游 Dockerfile 的两个问题,见文件头)。
首次构建要从 GitHub 拉源码与约 630 MB 的 Camoufox 浏览器包;网络不好时先在本机构建同名镜像,compose 会直接用:
上游不发布镜像。compose 缺省用的是**浏览器桌面镜像** `umt-browser-desktop:1.17.0`(`docker/browser-desktop`,§8),
它从纯截图镜像 `camofox-browser:1.17.0` 复制 camofox,所以**先构建旧镜像**:`docker/camofox/Dockerfile` 从 git tag `v1.17.0`
构建(修了上游 Dockerfile 的两个问题,见文件头)。首次构建要从 GitHub 拉源码与约 630 MB 的 Camoufox 浏览器包:
```sh
git clone --depth 1 --branch v1.17.0 https://github.com/jo-inc/camofox-browser.git /tmp/camofox-src
docker build -t camofox-browser:1.17.0 --build-arg APT_MIRROR=mirrors.ustc.edu.cn \
--build-context upstream=/tmp/camofox-src docker/camofox
# 走宿主代理时加 --network host --build-arg https_proxy=http://127.0.0.1:7890 --build-arg http_proxy=...
docker compose build camofox # 再构建桌面镜像(或 docker build -t umt-browser-desktop:1.17.0 docker/browser-desktop)
```
只要截图模式(不要桌面、省约 400 MB 常驻内存与 3 GB 磁盘):`.env` 里 `CAMOFOX_IMAGE=camofox-browser:1.17.0`,同一个卷,登录状态通用。
### 1.2 接自有实例
`.env` 里 `BROWSER_PROVIDER_URL=http://<host>:9377`、`BROWSER_ACCESS_KEY=<它的 CAMOFOX_ACCESS_KEY>`、`CAMOFOX_REPLICAS=0`
@@ -245,3 +249,94 @@ compose 网络里的 mock NexusPHP 站 `mocknexus:8080`;服务层在宿主进程
没有核验的:四个真实站点(观众 / 馒头 / HHClub / CHD)的登录保持、Cloudflare / 验证码挑战、真实站点页面上的提取对比;
并发 1 / 2 / 4 会话的性能与资源;原站视图界面本身在浏览器里的点击体验(1.5 秒截图刷新);VNC 插件(镜像已装,未启用、未接入)。
## 8. 原站视图桌面模式(Selkies 远程桌面,WT-1)
方案与取舍见 `docs/design/webtop-remote-browser.md`。桌面镜像 = linuxserver `baseimage-selkies:debiantrixie`(Webtop 4.0 的底座,
pixelflux + labwc Wayland 桌面 + Selkies 2.0 Web 客户端)+ camofox 1.17.0 **有头**运行(`CAMOFOX_INTERACTIVE=desktop`,
`MOZ_ENABLE_WAYLAND=1`)。原站视图里看到的窗口就是 Agent 经 camofox API 驱动的同一个 Firefox 进程:Agent 导航,画面跟着变;
人在画面里点,Agent 下一次快照读到的就是点过之后的页面。
### 8.1 组成
| 部件 | 位置 | 说明 |
| --- | --- | --- |
| 镜像 | `docker/browser-desktop/Dockerfile` | 底座按 digest 锁定;从 `camofox-browser:1.17.0` 复制 node、`/app`、Camoufox;补 `fonts-noto-cjk-extra`;可选 fcitx5(拼音 + mozc,`--build-arg WITH_FCITX5=0` 不装) |
| 启动 | `root/etc/s6-overlay/s6-rc.d/svc-camofox` | s6 服务,等 labwc 的 `wayland-0` 出现后以 `abc` 身份 `exec node server.js`;依赖 `svc-de` 与 `svc-dbus`(Firefox 连着 D-Bus,dbus 先停会把浏览器带走,关机落盘失败) |
| 初始化 | `init-umt-desktop` | 由 `CAMOFOX_ACCESS_KEY` 派生 Selkies 控制 / 只读口令;覆盖 labwc autostart;把 `/root/.camofox` 交给 `abc` |
| 反代 | `apps/server/src/modules/desktop` | `/api/v1/browser/desktop/{sessionId}/*` → 容器 `:3000`(静态客户端 + `api/websockets`);只接受控制台会话 |
| 前端 | `apps/web/app/components/browser/desktop-view.tsx` | 原站视图 Tab:桌面可用且是安全上下文 → 桌面模式;否则截图模式并说明原因;可手动切换 |
| HTTPS | compose `caddy`(profile `tls`)+ `docker/browser-desktop/Caddyfile` | 可选;已有反代终结 TLS 时不用 |
窗口:无标题栏、最大化铺满 1280×900(`BROWSER_DESKTOP_WIDTH/HEIGHT`),`HARDEN_DESKTOP` 去掉终端 / sudo / xdg-open,
`HARDEN_OPENBOX` 去掉关闭按钮与右键 / 中键菜单、禁 Alt+F4 等。音频、麦克风、摄像头、手柄、文件传输、打印、命令、共享全部关闭并锁定,
剪贴板只允许文本。
### 8.2 鉴权与输入权限
- Selkies 端口(3000/8082)不映射到宿主,唯一入口是 app 的反代;外部 API Key 与 DEV key 一律 403。
- 口令不经浏览器:app 按请求者身份在上游请求上注入 `Authorization: Basic`。持有该会话 active 人工租约的本人 → 控制口令;
其他人(包括未接管的本人)→ 只读口令,Selkies 服务端丢弃只读连接的键鼠与剪贴板输入。
- 口令 = `HMAC-SHA256(CAMOFOX_ACCESS_KEY, "umt-desktop/control" | "umt-desktop/view")` 前 48 位 hex,app 与容器各算一遍;
没设 `CAMOFOX_ACCESS_KEY` 时容器用随机口令,桌面模式不可用(界面回退截图模式)。
- WebSocket 每 3 秒复查一次角色:交还 / 租约过期 / 被他人接管 / 控制台会话失效时服务端主动断开,Selkies 客户端自动重连并按新口令认证
(实测交还后 5 秒内点击已无效)。WebSocket 还要求 `Origin` 与 `Host` 同源(cookie 会话 + WS 无 CORS)。
- 反代响应带 `Content-Security-Policy: frame-ancestors 'self'` 与 `X-Frame-Options: SAMEORIGIN`,只能被本站 iframe 嵌入;
上游的 `WWW-Authenticate` 不外露(否则浏览器弹 Basic 登录框)。
- 只支持环境变量登记的 `camofox-env`(compose 自带容器);桌面地址缺省由 `BROWSER_PROVIDER_URL` 推出(端口换 3000),
或显式 `BROWSER_DESKTOP_URL`。
### 8.3 界面
原站视图 Tab 调 `GET /api/v1/browser/desktop/{sessionId}/_status` 决定模式:`available`(容器 3000 能连上且有访问凭据)
且 `window.isSecureContext` → 桌面模式(iframe);否则截图模式,顶部写原因:"桌面模式不可用:…" 或 "桌面模式需要通过 HTTPS 访问控制台"。
桌面模式顶栏:连接状态(已连接,只读 / 可操作)、当前控制者、接管 / 交还(沿用 `control/acquire|release`)、重新连接、截图模式、关闭会话。
接管后直接在画面里点和输入;中文、日文用**本机输入法**(Selkies 接收 composition 事件,按 Unicode 注入上屏文本);
复制粘贴用 Ctrl+C / Ctrl+V。
### 8.4 HTTPS
WebCodecs 视频解码与剪贴板 API 只在安全上下文(HTTPS 或 `localhost`)可用;用 IP / 局域网主机名经 HTTP 访问时只能用截图模式。
```sh
# 已有反代(nginx / Caddy / Traefik)终结 TLS:无需改动,WebSocket 需透传 Upgrade、读超时 ≥ 1 小时、不缓冲
# 没有反代:启用 compose 自带 Caddy
docker compose --profile tls up -d # 自签:Caddy 内部 CA 按访问的主机名现场签发,浏览器需放行或导入根证书
docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt ./umt-root.crt # 导入到客户端受信任根
# 有公网域名:.env 里 TLS_DOMAIN=media.example.com、[email protected](ACME,80/443 需可达)
```
`TLS_PORT`(缺省 443)、`TLS_BIND` 可改;4380 仍可直连(截图模式)。
### 8.5 回退
- 桌面容器起不来 / 桌面异常:`.env` 设 `CAMOFOX_IMAGE=camofox-browser:1.17.0` 后 `docker compose up -d camofox`,原站视图自动回到截图模式,
Agent 能力不受影响(实测同一个卷,切换前后登录状态都在)。
- 只关桌面、保留镜像:不设 `CAMOFOX_ACCESS_KEY` 即可(桌面口令随机,app 探测为不可用)。
- 容器内输入法(本机输入法不可用时的备选):`BROWSER_DESKTOP_IME=fcitx5`,Ctrl+Space 切换;与本机输入法同时开会重复组字,缺省关闭。
### 8.6 原型核验(2026-09-29,临时栈 `umtwt`)
环境:本机 96 核、无 GPU(pixelflux 软件渲染 + CPU H.264);客户端 headless Chromium 145(Playwright),经 Caddy 自签 HTTPS;
上游 camofox 1.17.0 / Camoufox 152.0.4-beta.28,Selkies 2.0.0,labwc 0.8.3。脚本 `apps/web/test/screenshots/webtop/{p0,verify}.mjs`(截图不进 git)。
| # | 项 | 结果 | 观测 |
| --- | --- | --- | --- |
| 1 | 同会话 | 通过 | camofox API 导航 example.com → iana,桌面画面同步;在桌面里点链接,API 快照 URL 变为 `iana.org/domains/reserved`,tabId 不变 |
| 2 | 中日文显示 | 通过 | zh / ja 维基首页正文、标题栏、地址栏无豆腐块(Camoufox 自带 Noto CJK) |
| 3 | 本机输入法 | 通过 | CDP `Input.imeSetComposition` + `insertText` 模拟组字:搜索框得到「流浪地球」「進撃の巨人」(camofox `evaluate` 读回) |
| 4 | 剪贴板 | 通过 | 本机 → 远端:写本机剪贴板,焦点回到画面后 Ctrl+V 粘贴中日文;远端 → 本机:远端 Ctrl+C 后本机 `readText` 读回中文 |
| 5 | 只读口令 | 通过 | 未接管时在画面点链接,URL 不变;接管后同一坐标点击生效;API 交还后 5 秒内再点无效 |
| 6 | 重启保持 | 通过(修了 1 处) | `docker compose restart camofox` 后 httpbin cookie 仍在。修前 dbus 与 camofox 并行停止,Firefox 先退出导致关机落盘失败 |
| 7 | HTTP 回退 | 通过 | 经 HTTP 访问显示"桌面模式需要通过 HTTPS 访问控制台",截图模式正常;旧镜像下显示"浏览器服务没有桌面…" |
| 8 | 资源 | 见右 | 容器内存:1 会话无人观看约 570–670 MB,观看约 610 MB,滚动维基首页约 730 MB;CPU:无人观看 0.3%(不编码),观看静止页 1–7%,持续滚动约 75–100%(约 1 核) |
| 9 | 镜像 | — | `umt-browser-desktop:1.17.0` 解压 6.9 GB / 压缩 2.0 GB(旧镜像 3.6 GB / 1.1 GB) |
已知问题与未做:
- Firefox 工具栏里有 Playwright 的 "JUGGLER" 标识;用户可在画面里打开 `about:addons`、新标签页、输入任意网址——越界防护
(`policies.json`、`context.route` 白名单、交还时核对 URL,方案 §6)未做。
- 接管期间 camofox 看不到 API 请求,`SESSION_TIMEOUT_MS`(缺省 30 分钟)到期会回收会话窗口;接管心跳(方案 §5.5 插件)未做。
- 一个桌面承载所有站点会话:持有 A 站租约的人在画面里能看到 / 操作切到前台的其它窗口;目前同一时刻一般只有一个会话窗口。
- 真实输入法(Windows 微软拼音、macOS 日文)、Firefox / Safari 客户端、真实 PT 站点未测;容器内 fcitx5 只验证能启动,未验证组字。
- 画面坐标与 camofox 截图坐标不同(桌面含 56 px 工具栏,Camoufox 伪装了 `screenX` / `outerHeight`),Agent 视觉操作继续用 camofox 截图。