备份方案从来不是在服务器出事的那一晚才接受检验,而是在几周之前,由三个没人写下来的静默决定所决定:副本放在哪里、谁有权删除它,以及是否真的有人把它读回来验证过。
从不询问你身份的主机服务,换来的代价也要老实说清楚:没有客户经理可以联系,没有工单能让被清空的硬盘复活,我们自己的数据保留政策也说得很直白:服务器终止后24小时内数据即被销毁,硬盘经过加密擦除而非简单格式化,并且不保留任何备份。这正是让这个平台值得使用的同一个特性,只是从另一个角度看而已。任何你希望在糟糕的一夜之后还能找回的东西,都必须提前存在别处,而把它放到那里的人只能是你自己。
服务器真正是怎么丢的
几乎没有人是以自己想象的方式丢掉服务器的。灾难性硬件故障确实存在,但很罕见,而且这恰恰是靠谱主机早已针对性防范的一种情况。真正会发生的损失往往更平淡,而且每一种都会打败某一类特定的副本——这就是为什么"我有备份"本身不是答案,除非你能说清楚它能扛住下面哪几种情况。
| 出了什么问题 | 通常是怎么发生的 | 什么能让你找回来 |
|---|---|---|
| 自己手滑 | Shell变量为空导致的一次rm -rf、指向生产环境的迁移脚本、误删错误表的一次部署 | 任何在失误之前就已存在的异地副本——这意味着保留时间必须比你发现问题所需的时间更长 |
| 悄悄发生的损坏 | 一块正在报废的NVMe、重启过程中被截断的写入、连续一周写入错误行的数据库 | 版本足够深、能追溯到已知良好状态的多版本副本。单一镜像副本只会忠实地把损坏也镜像一遍 |
| 入侵 | 被盗的密钥、未打补丁的应用、被投毒的依赖——然后,攻击者会刻意对你的备份下手 | 一份被入侵的机器根本无权删除的副本。这里只有这一种才算数 |
| 服务商或国家层面的事件 | 硬件损毁、数据中心遭遇的法律行动、一个你再也登录不了的账号或令牌 | 一份不在该服务商、也不受该司法辖区管辖的副本 |
| 丢失密钥 | 忘记的密码短语、随所保护服务器一起被清除的密钥文件、没人导出过的LUKS头 | 无法挽回。这是唯一一行没有"找回方式"的情况,而且它比硬件故障更常见 |
把这张表当作检查清单来读,而不是恐惧清单。每晚复制到同一台机器第二块硬盘的做法,只能应对第一行,别的都不行。同一面板里的快照能应对第一、二行。只有存放在服务器触及不到的地方、且你仍持有密钥的副本,才能应对全部五种情况。

快照不是备份,你的主机也不是
快照擅长做的事情它确实做得很好:几秒钟内、无需任何传输就能回滚一次失败的升级。但它做不到的是,扛过夺走整台服务器的那种事件,因为它和服务器共享同一个故障域——同一个服务商、同一个账号、同一个支付令牌、同一个国家,往往还是同一个存储集群。快照保护你不受自己所害,备份保护你不受其他一切所害。
在这里,这个区别比在主流主机那里更重要,因为通常的安全网是被故意拆掉的。没有人会登录客户的服务器,所以也没有人会注意到你的备份任务从三月起就一直在失败。账号没有绑定任何身份信息,所以也不存在"证明你是谁,我们就帮你恢复"这种人工路径。而终止账户是真正意义上的终局:余额耗尽是一次数据丢失事件,而不只是一次账单事件。
24小时条款就是全部论点所在。在这个平台上,被终止的服务器数据会在一天之内被销毁,硬盘经过加密擦除而非简单格式化。没有撤销删除,没有悄悄保留的冷存储层,也不存在"我们找到了一份旧副本"这种客服结果——因为保留一份就意味着在你要求我们删除之后仍然持有你的数据。安全网和隐私,本质上是同一笔交易,而且只做一次。
3-2-1原则,写给从未提交过身份证明的人
经典法则是:三份副本,两种介质,其中一份异地存放。这条规则诞生于磁带和机械硬盘的年代,如今"介质"这一条已经悄悄失去了意义:你的生产盘是NVMe,备份目标的盘也是NVMe,把这称为"两种介质"不过是自我安慰的说法。真正值得保留的是关于"距离"的那一条,而对离岸基础设施来说,距离从来不是用公里数衡量的。
把它改写成三份副本、两个服务商、两个司法辖区。同时摧毁两份副本的事件几乎从来不是物理层面的——它们通常是一个你失去访问权限的账号、一个状态不佳的服务商,或者一份能覆盖某个国家却管不到另一个国家的法律文件。同一机架里的两台服务器,不过是多绕了一圈的一份副本;处在同一法律辖区下的两台服务器,也好不到哪里去。我们的司法辖区选择指南介绍了如何挑选第二个辖区,让它不至于和第一个承担同样的风险。
实际操作起来成本很低。备份目标不需要核心数,几乎也不需要网络带宽——它需要的只是硬盘和一个地址。最小的VPS套餐,只要选在我们七个机房位置中不同的一个,就是一个称职的restic或Borg端点;而对于以TB计的归档数据,一台带真实硬盘的独立服务器,每TB成本比任何对象存储都低。当数据量确实很大、又很少被读取时,裸金属在经济性上有明显优势。
有一件事人们在生产环境上做对了,却在备份目标上做错了:付款方式应该一致。用你自己名下的银行卡买第二台服务器,会悄悄把你在第一台上费尽心思摆脱的身份重新绑定回去,而且这台服务器现在还保存着第一台的完整副本。如果生产服务器是用门罗币支付的,备份服务器也应该同样对待。
第三份副本是大多数人会跳过的一份,却是唯一能同时扛住所有远程故障的一份:一块你亲手持有、偶尔更新、平时离线保存的硬盘。对大多数人来说,每月更新一次就够了。它花费的不过是一杯咖啡钱的注意力,却是唯一能扛住前两份副本共同弱点的那一份。
推送、拉取,以及让一个坏夜晚吞掉两份副本的那个错误
下面是几乎所有人最先搭建起来的方案。生产服务器上的一个任务每晚运行,持有备份目标的密钥或令牌,连接过去,然后推送数据。它能用,也很简单,但它有一个特性,只有在服务器最糟糕的那一天才会显现出来:谁控制着生产服务器,谁就控制着备份。
这不是假设。在正式发难之前先删除或加密受害者的备份,是所有商业化攻击者的标准操作——凭证就摆在某个cron任务或环境变量文件里,找到它们只需要一分钟。一份攻击者能删除的副本,根本不算第二份副本,它只是第一份带延迟的镜像。
有两种干净的解决办法,而且和你本该已经做好的基础加固配合得很好。
- 只追加写入的目标。两款主流工具都支持一种模式:客户端只能新增数据,不能删除数据。Borg的做法是把目标端的SSH密钥锁定为
borg serve --append-only;restic的做法是启动带--append-only参数的REST服务器。生产服务器每晚写入,但从结构上就没有能力销毁历史记录。清理旧快照的操作随后在目标端进行,而这是一个生产服务器无法发起的会话。 - 用拉取代替推送。把方向反过来:由备份主机连接生产服务器,读取数据并存储。生产端根本不持有目标端的任何凭证,也就没有什么可偷的。在生产端使用的密钥上加上
restrict和强制的command=限制,这样被盗的备份密钥也无法变成一个可用的shell。
拉取模型更强,运行起来也稍微麻烦一点;如果你已经在用Borg或restic,只追加写入几乎是零成本的。这两种做法都能把"攻击者删除了我的备份"从一个既成事实变成一次未遂的尝试。如果你只从本文里记住一件事,那就记住这一节。
先在源端加密,再决定密钥交给谁保管
两款正经的工具都会在被备份的机器上、在任何数据越过网络之前完成加密。备份目标存储的是它自己无法解读的数据块——这正是跨服务商副本安全的原因所在。你的第二台主机不需要可信,甚至不需要友好;它只需要能连上、有硬盘就够了。正是这一个特性,把"一台在陌生国家的服务器"从风险变成了基础设施。
这和给服务器自身硬盘加密是不同的机制,两者回答的是不同的问题——我们关于VPS全盘加密的指南详细讲解了磁盘加密在机器运行时能保护什么、不能保护什么。备份加密是两者中更简单也更有价值的一种,因为它的威胁模型很诚实:数据处于静止状态,存放在你不掌控的硬件上,而密钥从未去过那里。
这就把全部风险转移到了密钥保管上。密码短语现在是唯一的全损失点,而且比人们预期的更糟,因为丢失它的过程是无声的——什么都不会报错,备份照常运行,而你恰恰会在最需要它的那一刻才发现问题。三个习惯可以解决这个问题:
- 密码短语在服务器上只以一份仅root可读的文件形式保存,通过
--password-file引用,这样它就永远不会出现在进程列表或shell历史记录里。 - 在所涉及的每一台机器之外,保留一份人可读的副本。抽屉里的一张纸,确实胜过一个同步到你也可能失去访问权限的账号的密码管理器。
- 给仓库再添加一把密钥——
restic key add,或者一份导出的Borg密钥——这样忘记一个密码短语就只是麻烦,而不是整个归档的终结。
三条习惯背后的同一条规则:如果密钥唯一的副本就存放在备份原本要替代的那台机器上,那你就没有备份。你只有一堆加密的数据块,和一个关于它们的故事。
一张表选出合适的工具
工具的选择,重要性其实不如连接方向和密钥状态,这也是为什么它排在第六位而不是第一位。话虽如此,工具之间的差异是真实存在的,选错形状会给以后带来麻烦。
| 工具 | 离开前是否加密 | 是否去重 | 支持只追加目标 | 适用场景 |
|---|---|---|---|---|
| restic | 是,整个仓库 | 是 | 是,通过其REST服务器 | 默认之选。支持SFTP、对象存储和自带服务器,目标端几乎可以是任何东西 |
| BorgBackup | 是,整个仓库 | 是,同类中最强 | 是,原生支持SSH | 通过SSH连接的单个Linux目标。数据量大且重复度高时无可匹敌 |
| 带轮换的rsync | 否——目标端能看到一切 | 部分支持,通过硬链接 | 否 | 镜像到一台你完全掌控的机器,适合即时局部恢复比隐私更重要的场景 |
| rclone | 仅在使用rclone crypt时 | 否 | 取决于存储服务商 | 把已存在的归档搬进对象存储,或在服务商之间迁移 |
| ZFS复制 | 仅在使用加密数据集时 | 是,块级别 | 通过快照权限实现 | 在两台ZFS机器之间复制。速度很快,但对两端要求都很严格 |
| tar配合age或GPG | 是,如果你加密归档文件 | 否 | 不适用 | 体量小、不常做、永久保存的归档,简单胜过效率 |
对单台服务器来说,用restic备份到第二台VPS是通向正确方案最短的路径。对于种子机、媒体归档,或者大量相似的大文件,Borg的去重能力决定了硬盘是被塞满还是留有余地——种子机搭建指南更详细地讲解了这类负载的存储部分。
只要还在运行,就不是一个文件
世界上最常见的损坏备份,就是对一个正在运行的数据库做直接文件拷贝。它完成时不会报错,体积也刚刚好,可一旦拿去恢复,存储引擎却拒绝打开这张表。拷贝进行时数据库正处于写入过程中;你保存下来的,只是一张正在翻页瞬间的照片。
有三种解法,按投入的精力递增排列。转储它:mysqldump --single-transaction能在不锁定写入方的情况下给出一致的InnoDB转储,PostgreSQL则用pg_dump做同样的事。快照它:冻结文件系统,或者做一次LVM或ZFS快照,从快照里拷贝,再释放它——数据量大到没法每晚转储时,就靠这一招。或者直接停掉它:对一个小型服务来说,凌晨4点停机两分钟是完全站得住脚的一致性策略,也是唯一没有边界情况的一种。
同样的逻辑不止适用于数据库。容器的可写层是可以随意丢弃的,但它的数据卷不是,旁边的docker compose文件和环境变量同样不是——一份只恢复数据、不恢复定义的备份,会让你只能凭记忆重建整套技术栈。消息队列、开启了持久化的Redis,以及MTA正在写入的邮件队列,都应该获得同样的对待:先静置、快照或转储,永远不要直接拷贝然后祈祷。
该备份什么,以及所有人都会忘记的部分
大多数人只备份最显眼的部分——数据库和应用目录——然后在压力之下手工重建剩下的一切。真正耗费时间的正是这个重建过程。一份能让你恢复到一个可用系统、而不只是一堆正确数据的备份,还应该包括这些不起眼的部分:
- 完整的
/etc目录,加上你自己写的systemd单元和定时器,以及任何存放在它之外的crontab。 - TLS证书及其私钥,至少也要有ACME账户密钥,这样证书才能续期,而不用从零开始。
- 防火墙规则和软件包列表,这两者合在一起,能比任何记忆都更快地重建出这台机器的样子。
- 应用密钥和环境变量文件——那些被特意排除在代码仓库之外的东西,也因此不会出现在别的任何地方。
- 以文本形式导出的DNS记录,包括反向DNS和PTR记录,这些信息存放在服务商那里,而不在服务器上。
没测试过的恢复只是个传闻
备份软件会自己报告状态,而且它老老实实报告的往往是错的那件事。"快照已完成"的意思是数据被写进了仓库,它完全没说这个仓库能不能在另一台机器上、被一个已经不记得十一个月前是怎么配置的人读出来。
先从便宜的完整性检查做起——定期运行restic check --read-data-subset=5%或borg check --verify-data——但要清楚它们验证的是归档本身,而不是你使用它的能力。真正的演练完全不同,只需要花一个下午,做一次就够。按小时租一台你平时不用的地区的全新服务器。只凭仓库地址、密码短语和你自己的笔记,把它恢复上去。把服务跑起来,给整个过程计时,然后销毁这台机器。总花费不过几美元,而这是唯一能产出一个你可以信任的数字的演练。
它稳定暴露出来的从来不是数据本身,而是没人记录下来的缺失软件包、活在备份路径之外的配置、只存在于你正打算替换的那台服务器shell历史里的密码短语,以及能读懂你仓库格式的工具版本。这些问题每一个都能提前轻松修好,却会在故障期间让人痛苦不堪。
把演练给出的两个数字写下来:一次恢复花了多久,以及这个备份计划能承受损失多少工作量。这两个数字才是真正的备份策略,上面的一切都只是为它们服务的实现细节。
把它自动化,让它持续发生
用systemd定时器来运行这个任务,而不是cron。你能获得集中在一处的日志、一份关于最近一次运行的真实记录,以及一个能扛过重启的计划——这些cron如果不额外花功夫都给不了你。别把密码短语放进unit文件本身,因为任何有shell访问权限的人都能直接用systemctl cat把它读出来。
接下来要解决真正坑人的失败模式,它不是一个错误,而是沉默。一个六周前就已经停止运行的备份,和一个运行得完美无缺的备份看起来一模一样,因为两者都不产生任何输出。要为"没有发生"而报警,而不是为"失败"而报警。让任务在成功时ping一个监控器,由监控器在ping没有按时到达时报警——并且把这个监控器放在被监控服务器之外的任何地方,因为一台已经宕机的机器没法报告自己宕机了。
刻意设置保留策略,而不是用默认值。类似--keep-daily 7 --keep-weekly 4 --keep-monthly 6这样的设置,既能覆盖你今晚就会发现的失误,也能覆盖你到了春天才发现的损坏,而且不会无限增长。如果你已经采用了只追加写入,就在目标端做清理,这也正是采用只追加写入的意义所在。传输流量在我们的网络上几乎从不构成瓶颈——每个套餐的带宽都不限量——所以排期时优先考虑一致性,而不是配额,并对照你自己的空闲时段来核对时间。围绕这一切更广泛的习惯,在服务器反侦察指南里有介绍。
浓缩版
如果这篇文章你只打算做一件事,那就按大致这个顺序做完这六件事:
- 在第二个服务商、第二个司法辖区放一份副本,付款方式和第一份一样私密。
- 让那份副本只能追加写入,或者由目标端主动拉取,这样被攻破的服务器就无法销毁它。
- 让工具在源端完成加密,并把密钥放在两台机器之外。
- 转储数据库,停掉或快照任何正在运行的东西;永远不要对运行中的状态直接拷贝。
- 把身份密钥单独备份——onion、WireGuard、DKIM、节点种子——因为这些东西无法重新生成。
- 找一台一次性服务器实际恢复一次,给它计时,并写下缺失了什么。
这些都不是什么稀奇的操作,也都用不了一个周末。只需要一个下午的搭建和一次演练,就能对抗那类足以终结项目的损失。在一个刻意不保留你任何信息的平台上,你自己做的那份副本,是唯一真正存在的副本——这是这种安排的代价,也是公平的代价。在不同于第一台的司法辖区开一台第二服务器,让今晚的备份有个地方可以落脚。