# H5 访问 H5 是桌面服务的可选浏览器入口。启用后,手机可以通过局域网或你自己的反向代理访问同一套会话、消息、附件和权限流程。 它不是公开 SaaS,也不是多租户账号系统。任何拿到有效 H5 Token 的设备都可以访问桌面服务暴露的核心能力,只应在可信网络、VPN 或自己维护的 HTTPS 代理中使用。 ## 推荐结构:一个地址、一个端口 当前服务端可以同时提供: - H5 静态页面 - REST API - Provider 代理 - WebSocket / SDK 连接 因此推荐让浏览器只访问一个来源: ```text 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,例如: ```text 192.168.1.20 ``` 设置页会结合当前服务端口生成完整地址。如果电脑切换 Wi-Fi、网线或 VPN,原 IP 可能不再属于当前网卡;桌面端会提示切换到可用地址。 使用反向代理时可以直接填写完整 URL: ```text https://cc.example.com ``` 桌面端无法替你验证外部域名、隧道或证书是否持续可用。 ### 固定端口 不设置固定端口时,桌面端会使用当前运行端口,并尽量复用已有端口。下列场景建议固定: - 手机书签需要长期不变。 - 防火墙只允许指定端口。 - Nginx、Caddy 或隧道固定转发一个上游端口。 端口必须是 `1024–65535` 之间且浏览器允许访问的整数。修改后要重启应用才会生效。 ### 断连保活 手机锁屏、切后台或短暂换网时: - 正在执行的任务不会因为 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: ```bash # 项目根目录 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 ``` 如果不是从项目根目录启动,设置: ```bash CLAUDE_H5_DIST_DIR=/absolute/path/to/claude-code-haha/desktop/dist ``` 没有 `desktop/dist` 时,控制 API 可以启动,但浏览器根路径会返回 404。 ### 在服务器本机启用 H5 控制接口只接受本机可信请求。另开一个服务器终端: ```bash curl -sS -X POST http://127.0.0.1:3456/api/h5-access/enable ``` 响应中的 `token` 是完整 Token。为局域网地址设置同源入口和固定端口: ```bash 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。不要填写另一台机器或已经失效的网卡地址。 随后打开: ```text http://192.168.1.20:3456/ ``` 更安全的个人方案是保持 `SERVER_HOST=127.0.0.1`,通过 SSH、VPN 或受控隧道访问;单纯 SSH 转发到本机时不需要启用 H5。 ## 反向代理 推荐用一个 HTTPS 域名把静态页面和所有后端路径转到同一个上游: ```text https://cc.example.com -> http://127.0.0.1:3456 ``` 至少确保下列路径进入同一个桌面服务: - `/` - `/api/*` - `/proxy/*` - `/ws/*` WebSocket 路径必须支持协议升级。 ### Nginx 必要请求头 反向代理连接本机服务时,后端看到的来源地址通常是 `127.0.0.1`。必须保留公开 Host,或传递标准代理头,防止远程请求被误判为本地直连: ```nginx 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 允许来源。可从服务器本机调用控制接口: ```bash 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、用户名或路径。