[Feature] 通过 Cloudflare Tunnel 进行设备间同步
需求
一台 DeepChat(主机,设备 A)通过用户自己的 Cloudflare Tunnel 暴露同步端点,得到一个公网
HTTPS 地址;主机签发配对令牌,其他设备(B、C、D)用这个地址 + 令牌与 A 同步数据。
拓扑是星型:其他设备只和主机通信,设备之间不直连。
为什么需要
- 现在的同步必须依赖 S3 兼容对象存储(R2 / S3 / MinIO / B2)。有些用户不愿把数据放进第三方
bucket,但自己有域名,而且已经在用 Cloudflare Tunnel 暴露其他自建服务。
- CGNAT 用户(家宽常见)没法做端口映射,局域网直连也不通。
- 现在流程是全手动的:备份 → 上传 → 换设备 → 下载 → 导入。有了主机之后,其他设备可以按需或
定时拉取。
目标
- 主机模式 — 通过用户自管的 Cloudflare Tunnel 暴露同步端点,不需要入站端口,不受 CGNAT
限制。
- 配对 — 主机展示一个短时效配对码(含二维码),其他设备用配对码换取自己的设备令牌;主机
可以随时查看、重命名、吊销设备。
- 同步 — 其他设备可以从主机拉取数据,也可以把自己的数据推给主机,复用现有备份/导入流程,
语义与现在保持一致。
- 状态可见 — 隧道状态、上次同步时间、进度、错误提示都放在「设置 → 数据」页。
- 安全 — 每个请求都要鉴权;Cloudflare 提供 TLS;可选 Cloudflare Access service token;
可选端到端载荷加密。
非目标
- 不做 DeepChat 官方中继,不做多租户账号体系。
- 主机离线时不排队、不转发(其他设备只能等待或跳过)。
- 不自动操作用户的 Cloudflare 账号。
- 不替代现有的 S3/R2 云备份。
- 第一阶段不做并发编辑合并(见「已知限制」)。
实现思路
设备 A(主机) Cloudflare 边缘
┌───────────────────────┐ ┌──────────────────────┐
│ DeepChat │ cloudflared │ https://sync. │
│ 同步端点 ───────────┼──(仅出站连接)────────┼──example.com │
│ unix:<sock> 或 │ │ TLS + 可选 │
│ 127.0.0.1:<port> │ │ Access 策略 │
│ 令牌鉴权 + 审计 │ └──────────┬───────────┘
└───────────────────────┘ │
┌───────────────────────────────┼───────────────────────────────┐
│ │ │
设备 B(从设备) 设备 C(从设备) 设备 D(从设备)
拉取 / 推送 拉取 / 推送 拉取 / 推送
流程:
- 主机打开「作为同步主机」(默认关闭),填入自己的隧道域名。
- 主机生成配对码,内容包含域名、主机公钥指纹和一次性密钥。
- 其他设备通过隧道连接,用配对码换取本机专属令牌;主机只保存令牌哈希。
- 其他设备本地保存
{hostUrl, deviceId, token},令牌用 safeStorage 保护。
- 其他设备拉取主机快照,或把自己的数据推给主机;每个请求都鉴权并记录审计。
建议的接口面(除 handshake 外都需要鉴权):
| 接口 |
用途 |
GET /sync/v1/handshake |
协议/应用/数据库版本、能力、加密方式 |
POST /sync/v1/pair |
配对码换取设备令牌 |
GET /sync/v1/status |
快照 id、大小、哈希、数据库版本 |
GET /sync/v1/snapshot |
流式下载备份包,支持断点续传 |
POST /sync/v1/push |
把本机备份包推给主机导入 |
GET /sync/v1/events |
数据变更通知(SSE / 长轮询) |
传输层说明:
- 同步端点本身不需要监听 TCP 端口:
cloudflared 支持 service: unix:/path/to.sock
(文档),
所以 macOS/Linux 上可以直接复用应用已有的「HTTP over Unix socket」方式。
- Windows 上命名管道不能作为
cloudflared 的 origin,因此 Windows 主机需要一个只绑定回环的
监听(127.0.0.1:<port>,绝不能是 0.0.0.0)。这一点需要决策,见「待定问题」。
Cloudflare 侧配置(用户操作)
要拿到固定域名,需要一个已接入 Cloudflare 的域名(免费套餐即可)。没有域名只能用 Quick
Tunnel(随机 *.trycloudflare.com、无 SLA、官方定位是试验用途)。
cloudflared tunnel login
cloudflared tunnel create deepchat-sync
cloudflared tunnel route dns deepchat-sync sync.example.com
cloudflared tunnel run deepchat-sync
# ~/.cloudflared/config.yml
tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef
credentials-file: /Users/me/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json
ingress:
- hostname: sync.example.com
service: unix:/Users/me/Library/Application Support/DeepChat/sync.sock
# Windows 主机改用回环监听(端口由实现确定)
# service: http://127.0.0.1:<port>
- service: http_status:404
在应用令牌之外,可以再叠加 Cloudflare Access service token 作为机器间访问控制(Access 策略需
要求携带该令牌):
CF-Access-Client-Id: <id>.access
CF-Access-Client-Secret: <secret>
本地调试可临时用 Quick Tunnel:cloudflared tunnel --url http://127.0.0.1:<port>。
同步哪些数据(以及哪些不同步)
第一阶段直接复用现有备份流程:agent.db 加 app-settings.json、custom_prompts.json、
system_prompts.json、mcp-settings.json、manifest.json;导入方式仍是 increment(只插入
缺失行)与 overwrite(整库替换)。
现有流程本身的限制,本次需求并不解决:
- 修改和删除不会传播,
increment 只插入缺失的行。
- 每次都是整库传输,没有增量。
- 机器本地相关配置(
cloudSyncSecret、agentCommandShell)按设计不参与同步。
- 记忆的向量数据不在数据库里,接收端需要重新生成。
所以 tunnel 主要解决的是「不依赖第三方 bucket」。真正让同步又快又不丢数据(增量、删除标记、
冲突处理)是后续工作,需要提前说清楚,避免让人以为加了 tunnel 同步体验就变好了。
安全基线
- 默认关闭,开启需要显式确认并给出风险提示。
- 只绑定 Unix socket、命名管道或
127.0.0.1,绝不监听 0.0.0.0。
- 设备令牌按设备签发:只存哈希、限定作用域、可设置有效期、可即时吊销;配对码一次性、短时效、
限速。
- 请求体积上限、按设备限速、两端都做路径校验。
- Provider API Key 等凭据默认不参与同步。
- 审计日志记录设备、方法、字节数、结果,不记录令牌和载荷内容。
待定问题
- Windows 主机:允许仅回环监听,还是第一阶段主机模式只支持 macOS/Linux?
cloudflared 由应用托管(启动/监控/升级),还是只做「用户自己跑隧道」?应用托管要处理三个
平台的打包与签名;cloudflared 本身是 Apache-2.0。
- 默认同步范围:会话、消息、设置是基本盘;Provider 凭据、Skills、MCP、知识库文件、记忆,哪些
需要用户显式勾选?
- 使用公网域名时,Cloudflare Access service token 是强制要求,还是仅在界面上强烈建议?
验收标准
- 两台设备完成配对,能互相拉取与推送,
increment 导入不丢数据、不产生重复会话。
- 传输中途断开后可以续传,不损坏数据、不产生半成品导入。
- 令牌被吊销或过期后立即拒绝;任何请求在校验失败时都不会返回 200。
- 关闭该功能后不留监听端口、不留残留的
cloudflared 进程。
- 凭据类数据(Provider Key、隧道凭据、机器本地值)可证明不存在于任何传输内容中。
参考文档
Cloudflare:
相关代码:src/main/sync/、src/shared/contracts/routes/sync.routes.ts、
src/renderer/settings/components/DataSettings.vue、src/main/cli/server.ts、
docs/architecture/local-control-plane/spec.md。
[Feature] 通过 Cloudflare Tunnel 进行设备间同步
需求
一台 DeepChat(主机,设备 A)通过用户自己的 Cloudflare Tunnel 暴露同步端点,得到一个公网
HTTPS 地址;主机签发配对令牌,其他设备(B、C、D)用这个地址 + 令牌与 A 同步数据。
拓扑是星型:其他设备只和主机通信,设备之间不直连。
为什么需要
bucket,但自己有域名,而且已经在用 Cloudflare Tunnel 暴露其他自建服务。
定时拉取。
目标
限制。
可以随时查看、重命名、吊销设备。
语义与现在保持一致。
可选端到端载荷加密。
非目标
实现思路
流程:
{hostUrl, deviceId, token},令牌用safeStorage保护。建议的接口面(除
handshake外都需要鉴权):GET /sync/v1/handshakePOST /sync/v1/pairGET /sync/v1/statusGET /sync/v1/snapshotPOST /sync/v1/pushGET /sync/v1/events传输层说明:
cloudflared支持service: unix:/path/to.sock(文档),
所以 macOS/Linux 上可以直接复用应用已有的「HTTP over Unix socket」方式。
cloudflared的 origin,因此 Windows 主机需要一个只绑定回环的监听(
127.0.0.1:<port>,绝不能是0.0.0.0)。这一点需要决策,见「待定问题」。Cloudflare 侧配置(用户操作)
要拿到固定域名,需要一个已接入 Cloudflare 的域名(免费套餐即可)。没有域名只能用 Quick
Tunnel(随机
*.trycloudflare.com、无 SLA、官方定位是试验用途)。在应用令牌之外,可以再叠加 Cloudflare Access service token 作为机器间访问控制(Access 策略需
要求携带该令牌):
本地调试可临时用 Quick Tunnel:
cloudflared tunnel --url http://127.0.0.1:<port>。同步哪些数据(以及哪些不同步)
第一阶段直接复用现有备份流程:
agent.db加app-settings.json、custom_prompts.json、system_prompts.json、mcp-settings.json、manifest.json;导入方式仍是increment(只插入缺失行)与
overwrite(整库替换)。现有流程本身的限制,本次需求并不解决:
increment只插入缺失的行。cloudSyncSecret、agentCommandShell)按设计不参与同步。所以 tunnel 主要解决的是「不依赖第三方 bucket」。真正让同步又快又不丢数据(增量、删除标记、
冲突处理)是后续工作,需要提前说清楚,避免让人以为加了 tunnel 同步体验就变好了。
安全基线
127.0.0.1,绝不监听0.0.0.0。限速。
待定问题
cloudflared由应用托管(启动/监控/升级),还是只做「用户自己跑隧道」?应用托管要处理三个平台的打包与签名;cloudflared 本身是 Apache-2.0。
需要用户显式勾选?
验收标准
increment导入不丢数据、不产生重复会话。cloudflared进程。参考文档
Cloudflare:
unix:/unix+tls:)— https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/routing-to-tunnel/protocols/warp-routing,不暴露公网域名)— https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/相关代码:
src/main/sync/、src/shared/contracts/routes/sync.routes.ts、src/renderer/settings/components/DataSettings.vue、src/main/cli/server.ts、docs/architecture/local-control-plane/spec.md。