备份与配置导出:把 Cloudflare 上的东西变成能重建的文件
Cloudflare 上的资产有三类:配置必DNS 记录、路由、环境变量)、代码必Worker 脚本)、数据必KV、R2、D1)。配置和代码丢了能从 Git 恢复,数据丢了才是真丢。这篇按"能不能导出"把六样东西分类,给出可执行的导出命令,最后用一次恢复演练验证备份是不是真的能用。
安全与 DNS 的前置知识见 87-dns-hosting-notes.md,密钥管理见 64-workers-env-secrets.md。
1. 六样东西的可备份性
| 资产 | 能否导出 | 手段 | 恢复方式 |
|---|---|---|---|
| DNS 记录 | 能 | API GET /zones/{id}/dns_records 或控制台 Export | 导入 BIND 文件或 API 批量创建 |
| Worker 代码 | 能 | Git 仓库 | wrangler deploy |
| Worker 配置 | 能 | wrangler.toml | 同上 |
| KV 数据 | 能 | wrangler kv key list + get | wrangler kv bulk put |
| R2 对象 | 能 | rclone / S3 兼容 API | 反向同步 |
| D1 数据 | 能 | wrangler d1 export | wrangler d1 execute 执行 SQL |
| Secrets | 导不出 | 只能 secret list 看名字 | 从密码管理器人工重建 |
最后一行是重点。Workers 的 secret 写入后不可读回,wrangler secret list 只给出名字和类型。备份策略里要有单独一条:所有 secret 的原始值存在密码管理器或 CI 的加密变量里,环境变量的名字列表定期导出。
2. KV 全量导出
# 列出所有 key(加 --remote 才查远程,默认只查本地模拟)
npx wrangler kv key list --namespace-id=<NAMESPACE_ID> --remote
真实输出(2026-11-10,命名空间 cf97-links):
[
{ "name": "link:853ybv" },
{ "name": "link:vwegzg" }
]
拿到名单后逐个取值写文件:
$id = "<NAMESPACE_ID>"
$keys = npx wrangler kv key list --namespace-id=$id --remote | ConvertFrom-Json
New-Item -ItemType Directory -Force -Path .\kv-backup | Out-Null
foreach ($k in $keys) {
$safe = $k.name -replace '[:/\\]', '_'
npx wrangler kv key get $k.name --namespace-id=$id --remote |
Out-File -Encoding utf8 ".\kv-backup\$safe.json"
}
导出完要对账:kv key list 的条数应该等于备份目录里的文件数,单个 key 的字节数与文件大小也要对得上。差一两个通常是 key 名里的字符被替换后重名,这种错误在恢复时才会暴露,那时已经来不及了。
key 名里的冒号和斜杠要替换掉,否则在 Windows 上会当成路径分隔符。回灌用 wrangler kv bulk put,它接受一个 [{"key":"...","value":"..."}] 的 JSON 数组,一次最多 10,000 条、单次 100 MB。
跑批要注意限速:KV 免费档每天 1,000 次写入,一次全量回灌超过这个数就会失败。数据量大的命名空间分几天灌,或者临时升到付费档。
3. DNS 导出
有 Zone 权限时用 API:
curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?per_page=100" \
-H "Authorization: Bearer $CF_API_TOKEN" |
jq -r '.result[] | "\(.type)\t\(.name)\t\(.content)\t\(.ttl)\t\(.proxied)"'
控制台也能直接导出 BIND 格式的 zone 文件,适合留档。导出时注意三点:代理状态必橙色云)不在 BIND 格式里,要单独记录;ttl=1 表示自动,不要当成 1 秒;重定向规则和页面规则不在 DNS 里,属于另一份配置。
4. 恢复演练
备份没验证过等于没有。每季度做一次空环境演练,顺序如下:
建一个临时 Worker 名字必加 -restore-test 后缀),从 Git 拉代码,用导出的 wrangler.toml 部署;把 KV 备份灌进一个新建的临时命名空间,抽查三个 key 的值;DNS 在纸上核对,不实际改线上记录。
演练要记录的是时间和卡点,不是"成功了"。常见卡点:wrangler.toml 里的 compatibility_date 太旧导致新代码报错、忘了某个 secret、KV 数据里的时间戳是相对路径依赖了旧域名。
5. 自动化到什么程度
个人项目一个月手动导一次就够,关键是放在固定位置必比如私有仓库的 backup/ 目录)并写清日期。有真实用户的项目用 GitHub Actions 每天跑一次,产物传对象存储,保留 30 天。
自动化备份本身也会消耗额度:KV 全量导出是每 key 一次读,一万个 key 就是一万次读,占日额度的 10%。按周跑比按天跑合理。
6. 存放位置与保留策略
备份放在哪,和备份本身一样重要。三条约束:与线上不同账号或不同服务、私有、有日期。最常见的做法是推到私有 Git 仓库的 backup/2026-11-10/ 目录下,一个日期一个目录,一眼能看出最后一次成功是什么时候。
保留份数按恢复目标定。个人项目留最近 7 份日备加 4 份周备就够,再多也没人看。有真实用户的项目按 30 天滚动,同时保留每个月的第一份,用于"半年前那次改坏了"的追溯。
备份内容里如果含用户数据,注意别把明文推进仓库。KV 里的邮箱、token、订单号都算敏感数据,导出前过一遍脱敏,或者把备份仓库设成加密仓库。DNS 记录里的 TXT 经常带验证字符串,也属于不该公开的东西。
7. 常见问题
Worker 代码一定要放 Git 吗?是。控制台在线编辑的代码没有版本历史,改错只能凭记忆回滚。用 wrangler deploy 的流程天然要求有本地文件,把本地文件提交上去即可。
R2 备份要不要做?R2 本身有多副本,但误删是同步的。重要的桶开对象版本控制,或者定期 rclone sync 到另一个存储。注意跨云同步会产生出站流量,R2 出站免费这一点在这里也是优势。
D1 怎么备?wrangler d1 export <db> --output=backup.sql 导出 SQL,恢复时 wrangler d1 execute <db> --file=backup.sql。数据量大时导出会分段,注意命令输出里的提示。
小结
能导出的是配置、代码、数据和对象,导不出的是 secret 的值。备份清单里最容易被忽略的正是最后一项——它没法自动导出,只能靠人把原始值存进密码管理器,并把变量名列表纳入备份。
备份的价值只在恢复那一刻体现。做一次空环境演练,比多存十份没人验证过的快照有用。故障真的发生时按什么顺序查,见 104-troubleshooting-playbook.md,额度与备份频率的关系见 102-cost-control-quotas.md。
数据来源与检索时间
检索时间 2026-11-10。
| 来源 | URL | 对应数据 |
|---|---|---|
| KV 命令 | https://developers.cloudflare.com/kv/reference/kv-commands/ | kv key list / kv key get / kv bulk put 的参数与 --remote 要求 |
| KV bulk 限制 | https://developers.cloudflare.com/kv/api/write-key-value-pairs/ | 单次 10,000 条、100 MB |
| DNS 记录 API | https://developers.cloudflare.com/api/operations/dns-records-for-a-zone-list-dns-records | per_page、返回字段 |
| D1 导出 | https://developers.cloudflare.com/d1/best-practices/import-export-data/ | d1 export 与导入方式 |
核验说明
- 真实执行:
wrangler kv key list --namespace-id=c9f251cb... --remote返回两条link:记录,输出与文中一致;确认不加--remote时读到的是本地状态。 - 文档核对:
kv bulk put的单次条数与体积上限、d1 export的用法来自上述页面。 - 未做:DNS 导出必无 Zone 权限)、R2 同步、D1 导出、完整的恢复演练。文中 PowerShell 导出脚本按
wrangler的 JSON 输出结构写,未对大批量 key 运行过。