我给博客和日记加了一套CF R2 异地备份
前几天我检查服务器,发现博客、日记和统计服务都在按时备份。乍一看挺安心,数据库有副本,图片也打进了压缩包。
可我又想到一个问题:生产数据和备份都在同一台服务器。手滑删错数据时,本地备份确实能救命。服务器或云盘真出问题,它们也可能一起消失。
于是我给这几个项目补了一层 Cloudflare R2 异地备份。整个过程没有改原来的业务,也不需要 LLM,每天由脚本自动完成。
一、本地有备份,为什么我还是不放心
1. 原来的备份状态
① 三个项目都在自动备份
我的博客每天会导出 MySQL 数据库。图片、插件和必要配置也会打包。日记项目用 SQLite,自带完整性检查。uploads 图片目录也会装进压缩包。网站统计则单独导出数据库。
这套本地备份很实用。文章误删或数据库改坏时,我能直接在服务器恢复。更新程序翻车也不用先去云端下载大文件。
② 问题藏在存储位置
这些文件都放在当前服务器的磁盘里。它们能处理局部误操作。整机损坏、云盘异常或实例误删仍然覆盖不到。
我需要的很简单:本地备份继续留着,再把同一批文件送到另一套存储里。这样恢复速度和容灾能力都能保住。
2. 为什么选择 R2
① 它很适合保存异地副本
R2 是 Cloudflare 的对象存储。简单理解,它就是一个只管放文件的云端仓库。它支持 S3 接口,服务器用 rclone 就能上传、检查和下载。
我的备份每天只有几份,当前总量约 336MiB。按现有速度,保留90天大约占3GB,离10GB的免费存储额度还有空间。
② 备份桶默认不公开
我一开始也在控制台里找“设为私有”的开关,结果根本找不到。后来查了官方文档才确认:R2 存储桶默认不公开。只有主动启用公共地址或绑定公开域名,外部才能直接访问。
我没有打开这些入口,匿名访问测试也被拒绝。备份只能用授权凭据读取。
二、我把备份流程串了起来
1. 保留原来的本地备份
① 不重写现有逻辑
我没有把三个项目的备份脚本推倒重来。博客、日记和统计服务仍按原时间生成文件。数据库导出、图片打包和完整性检查照常执行。
这样改动范围很小。就算R2临时不可用,本地备份仍会正常产生。云端故障不会拖累原来的保护层。
② 统一增加一次云端上传
等当天的本地任务都结束后,系统再统一运行一次上传脚本。它把新增文件同步到一个R2存储桶,并按项目分到三个目录:
kanle/:博客数据库、图片和配置paper-diary/:日记数据库、图片和校验文件umami/:网站统计数据库
这一步交给系统定时任务执行。它不需要模型参与,也没有Token消耗。
2. 文件怎么保存
① 每个项目一个目录
所有内容放在同一个私有桶里,通过目录区分项目。以后再增加服务,只需要加一个新目录,不必重新设计整套流程。
本地保留周期没有变化,R2则保留更长时间。平时误删时优先用本地文件,遇到整机问题再从R2恢复。
② 校验文件要一起留下
日记备份旁边还有一个102字节的 .sha256 文件。它是压缩包的数字指纹,并非第二个压缩包。
下载备份后重新计算指纹,两边一致,说明文件没有损坏或传输不完整。所以清理旧备份时,我让压缩包和校验文件始终成对处理。
3. 容量怎么控制
① 每周检查一次
我又加了一个每周任务,检查R2当前容量。低于 9GB 时只记日志,不发起删除,也不需要每天反复计算。
② 超限后删最旧批次
如果容量超过9GB,脚本会清理最旧的完整备份批次。容量降到约 4.5GB 后停止。每个项目至少保留最新一批,无法识别的文件一律不碰。
这个兜底近期大概率不会触发,但它能防止以后图片增长,把免费空间慢慢吃满。
三、上传成功,还不算真正完成
1. 我做了哪些验证
① 对比本地和云端文件
第一次上传完成后,R2里共有 41个对象。总容量为352,283,298字节。我没有只看“命令执行成功”,还逐个比较了三类备份。结果都是0差异。
这一步确认了文件数量和内容都对得上。列表中有文件,内容也确实上传完整。
② 实际下载并恢复
我从R2下载了最新一份日记备份,先检查SHA256,再解压数据库。校验结果为 OK,SQLite完整性检查返回 ok。
这一轮完成后,我才敢把它当成可恢复的备份。毕竟真正有用的标准很朴素:需要时能把数据拿回来。
2. 这次遇到的小坑
① 旧版工具出现兼容问题
服务器仓库里的 rclone 版本偏旧。首次上传时,部分请求返回了 501 Not Implemented。自动重试完成上传后,我还是换成了新版。随后又跑了一遍同步和逐文件检查。
升级后任务不再报错,新文件的上传、下载和删除测试也都通过。
② 300多MB从哪里来
日记当前数据只有二十多MB,R2里却一下出现三百多MB。原因是每天保存一份完整快照。当时已有16份历史备份,每份都包含数据库和69张图片。
所以300多MB不是突然多出一份神秘数据,只是多天完整备份叠加后的结果。现在有90天保留和9GB兜底,容量增长也有明确边界。
写在最后
这套流程跑起来后,我依然保留本地备份。它负责处理日常误删和快速恢复。R2保存独立的异地副本,防住更大的故障范围。
整套工作由Shell脚本和系统定时任务完成。逻辑固定,资源占用也低。删几个旧文件,无需叫醒一次LLM。对个人博客和日记来说,这样已经很踏实。