ThinkInAIXYZ / ThinkInAIXYZ/deepchat
[Feature] 通过 Cloudflare Tunnel 进行设备间同步
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 6.3k
- Forks
- 735
- Avg merge
- 6h 28m
- Merged PRs (30d)
- 100
Description
[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:
- Tunnel 概览 — https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/
- 服务类型(
unix:/unix+tls:)— https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/routing-to-tunnel/protocols/ - Published applications — https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/routing-to-tunnel/
- 配置文件 — https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/configuration-file/
- 创建隧道(控制台方式,connector token)— https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/
- Quick Tunnel(仅调试)— https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/
- 私有网络(
warp-routing,不暴露公网域名)— https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/ - Access service token — https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/service-tokens/
- cloudflared 下载 — https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/
相关代码: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。
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading src/main/sync/, src/shared/contracts/routes/sync.routes.ts, and the existing backup/import flow. Then inspect src/renderer/settings/components/DataSettings.vue, src/main/cli/server.ts, and docs/architecture/local-control-plane/spec.md to understand the current boundaries. Done means the open design questions are resolved and the pairing, transfer, security, lifecycle, and acceptance criteria are implemented and verified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- electron, typescript
- Domain
- api, backend, desktop, devops, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100