cc-haha/docs/desktop/06-h5-access.md
2026-07-23 20:46:33 +08:00

8.3 KiB
Raw Blame History

H5 访问

H5 是桌面服务的可选浏览器入口。启用后,手机可以通过局域网或你自己的反向代理访问同一套会话、消息、附件和权限流程。

它不是公开 SaaS也不是多租户账号系统。任何拿到有效 H5 Token 的设备都可以访问桌面服务暴露的核心能力只应在可信网络、VPN 或自己维护的 HTTPS 代理中使用。

推荐结构:一个地址、一个端口

当前服务端可以同时提供:

  • H5 静态页面
  • REST API
  • Provider 代理
  • WebSocket / SDK 连接

因此推荐让浏览器只访问一个来源:

http://192.168.1.20:3456/

同源路径不需要再维护独立的前端地址,也能减少 Token 和 WebSocket 代理配置错误。源码运行时默认服务端口是 3456;发布版应以设置页显示的“当前端口”为准。

安全策略不会因为前后端同源就自动信任一个远程浏览器。该来源仍需出现在 H5 允许来源中;桌面端正常开启流程会沿用已保存的 H5 配置,源码或手工部署应按下文显式填写 allowedOrigins

桌面端开启步骤

  1. 打开「设置 → H5 访问」。
  2. 打开「启用 H5 访问」,阅读风险提示后确认。
  3. 查看自动生成的 H5 链接和“当前端口”。
  4. 如果保存的局域网 IP 已失效,使用设置页建议的新 IP或手动填写电脑当前的局域网 IP。
  5. 需要稳定书签或反向代理时,在“固定端口”填写 3456 或其他浏览器允许的端口并保存。
  6. 修改固定端口后重启桌面端,确认“当前端口”已经变成新值。
  7. 用手机扫描二维码,或复制“扫码链接”到可信设备。

二维码链接会携带 Server URL 和 H5 Token。浏览器连接成功后会在本机保存连接信息后续打开可继续使用。

访问主机 / IP

普通局域网访问只填写电脑真实的私有 IP例如

192.168.1.20

设置页会结合当前服务端口生成完整地址。如果电脑切换 Wi-Fi、网线或 VPN原 IP 可能不再属于当前网卡;桌面端会提示切换到可用地址。

使用反向代理时可以直接填写完整 URL

https://cc.example.com

桌面端无法替你验证外部域名、隧道或证书是否持续可用。

固定端口

不设置固定端口时,桌面端会使用当前运行端口,并尽量复用已有端口。下列场景建议固定:

  • 手机书签需要长期不变。
  • 防火墙只允许指定端口。
  • Nginx、Caddy 或隧道固定转发一个上游端口。

端口必须是 102465535 之间且浏览器允许访问的整数。修改后要重启应用才会生效。

断连保活

手机锁屏、切后台或短暂换网时:

  • 正在执行的任务不会因为 H5 断连被直接停止。
  • 任务可以在后台完成,重连后查看结果。
  • 只有任务已经空闲且无人连接时,才会在保活时间到期后停止对应 CLI。

默认空闲保活时间为 30 秒,可配置范围是 5 秒到 24 小时。调大数值会让无人观察的空闲进程保留更久,不应把它当作云端永久任务。

Token 生命周期

  • Token 会保存在本机设置中,重启桌面端后仍可查看和生成二维码。
  • 关闭 H5 会立即拒绝远程访问,但会保留 Token方便以后重新启用已配对设备。
  • 重新生成 Token 会轮换凭证,旧二维码和旧 Token 立即失效。
  • 不要把带 Token 的扫码链接贴到群聊、公开 Issue、日志截图或公共网页。

怀疑链接泄露时,应重新生成 Token而不只是关闭再打开 H5。

手机端可用范围

H5 优先保证对话主流程:

  • 会话列表与项目切换。
  • 消息发送、停止和流式回复。
  • 图片和文件附件。
  • 权限按钮与 AI 提问。
  • 消息复制、分叉等操作。
  • @ 文件引用与适合触屏的输入布局。
  • 手机安全区、软键盘和横竖屏下的基础布局。

桌面工作区、底部终端、原生文件“打开方式”、Computer Use 系统授权和桌面宠物不属于 H5 的完整等价体验。

从源码运行同源 H5

先构建 Web UI再让服务端在 3456 同时提供页面与 API

# 项目根目录
bun install
cd desktop
bun install
bun run build
cd ..

SERVER_HOST=0.0.0.0 \
SERVER_PORT=3456 \
CLAUDE_H5_AUTO_PUBLIC_URL=1 \
bun run src/server/index.ts

如果不是从项目根目录启动,设置:

CLAUDE_H5_DIST_DIR=/absolute/path/to/claude-code-haha/desktop/dist

没有 desktop/dist 时,控制 API 可以启动,但浏览器根路径会返回 404。

在服务器本机启用

H5 控制接口只接受本机可信请求。另开一个服务器终端:

curl -sS -X POST http://127.0.0.1:3456/api/h5-access/enable

响应中的 token 是完整 Token。为局域网地址设置同源入口和固定端口

curl -sS -X PUT http://127.0.0.1:3456/api/h5-access \
  -H 'Content-Type: application/json' \
  --data '{
    "allowedOrigins": ["http://192.168.1.20:3456"],
    "publicBaseUrl": "http://192.168.1.20:3456",
    "fixedPort": 3456,
    "disconnectGraceSeconds": 30
  }'

把示例 IP 替换成服务器真实的局域网 IP。不要填写另一台机器或已经失效的网卡地址。

随后打开:

http://192.168.1.20:3456/

更安全的个人方案是保持 SERVER_HOST=127.0.0.1,通过 SSH、VPN 或受控隧道访问;单纯 SSH 转发到本机时不需要启用 H5。

反向代理

推荐用一个 HTTPS 域名把静态页面和所有后端路径转到同一个上游:

https://cc.example.com  ->  http://127.0.0.1:3456

至少确保下列路径进入同一个桌面服务:

  • /
  • /api/*
  • /proxy/*
  • /ws/*

WebSocket 路径必须支持协议升级。

Nginx 必要请求头

反向代理连接本机服务时,后端看到的来源地址通常是 127.0.0.1。必须保留公开 Host或传递标准代理头防止远程请求被误判为本地直连

proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

Caddy 默认会保留原始 Host 并补充 X-Forwarded-*。如果自定义 header_up,不要同时把 Host 改成 127.0.0.1 并删除全部代理头。

反向代理域名也要加入 H5 允许来源。可从服务器本机调用控制接口:

curl -sS -X PUT http://127.0.0.1:3456/api/h5-access \
  -H 'Content-Type: application/json' \
  --data '{
    "allowedOrigins": ["https://cc.example.com"],
    "publicBaseUrl": "https://cc.example.com"
  }'

如果必须把页面与 API 放在不同来源,需要把页面来源加入 allowedOrigins,并另外维护 Server URL。不要使用通配来源。除非现有基础设施强制要求否则优先使用同源方案。

安全检查

  • H5 默认关闭。
  • 远程 REST、Provider 代理与 WebSocket 都需要有效 Token。
  • 本机回环豁免不会扩展到真实局域网或带代理痕迹的请求。
  • 远程预览与桌面可信 session 分离,不会自动获得摄像头、麦克风或通知权限。
  • 不使用时关闭 H5。
  • 泄露时重新生成 Token。
  • 公网使用 HTTPS、VPN、访问控制与防火墙不要只依赖一个长期 Token。
  • 不要把桌面服务直接暴露给不受信任的团队或互联网扫描。

排查

现象 检查
二维码打不开 核对访问主机是否属于当前网卡、手机与电脑是否同网
地址端口不一致 以“当前端口”为准;固定端口修改后重启
页面 404 构建 desktop/dist,或检查 CLAUDE_H5_DIST_DIR
Token 无效 确认 H5 已启用;重新生成后更新旧书签
浏览器提示 CORS 把浏览器地址栏中的来源精确加入 allowedOrigins,不要使用 *
REST 可用但消息不流式 检查 /ws/* 的 WebSocket upgrade
反代后被当成本机或被拒绝 保留公开 Host 和标准代理头
切换网络后旧 IP 失效 在设置页应用建议 IP 或更新反向代理地址
手机切后台后连接消失 重新打开页面;运行中任务应继续,空闲任务受保活时间限制

仍无法定位时,到「设置 → 诊断」复制错误摘要与事件 ID。分享诊断材料前检查其中是否含私有域名、IP、用户名或路径。