All systems operational 12 elite locations · Europe & Asia Pay with crypto · 0 KYC
首页 / 指南 / VPS 备份与恢复:独立服务器上的 3-2-1 原则
指南

VPS 备份与恢复 —— 独立服务器上的 3-2-1 原则

VPSbit offsite backup still: two racks syncing across arrows

把状态数据与可重建部分分开,三份副本存于两种介质,并定期实测恢复。面向独立服务器的 Borg 与 Restic 实操方案,年付每月低至 $4.80。

简答

把状态数据与可重建部分分开,三份副本存于两种介质,并定期实测恢复。面向独立服务器的 Borg 与 Restic 实操方案,年付每月低至 $4.80。

先划清「状态」这条线

最快的恢复,是那种几乎不碰磁盘大多数内容的恢复——所以备份规划的第一步不是复制,而是删减。在一台典型的独立服务器上,真正不可再生的数据集其实很小:数据库、上传的文件、TLS 私钥,以及那些花了一周才调好的配置文件。操作系统本身是可以重现的。对机器上的每一条路径,先问一个问题:如果它在凌晨三点消失了,你会重新敲出来,还是重新搭出来?如果诚实的答案是「重新搭」,那它就不该进你的备份仓库。

这条线把工作分成两类产物:属于状态的,做副本;属于可重建的,写成脚本。一份你真正持续维护的简短 Ansible playbook 或 cloud-init 文件,胜过一台你早已遗忘的黄金镜像,因为脚本是可审阅、可版本化、可在闲置机器上提前验证的。回报就是恢复速度:从仓库拉回 3 GB 真实状态只需几分钟,而重装并重新调优一台手工搭建的服务器,稳定吃掉一个工作日。恢复速度真正的来源,就是把重建过程自动化——这是整个项目里性价比最高的一小时。

做盘点要用真实路径,而不是凭感觉。/etc 存放配置和 WireGuard 密钥,/var/lib/postgresql 或 /var/lib/mysql 存放数据库状态,/home 存放用户密钥和代码仓库,/srv 或 /var/www 存放上传文件和站点根目录。用 du -sh 逐个测量并记录数字;在一台 80 GB NVMe 磁盘的服务器上,状态总量通常只有个位数 GB。这个数字决定了下游的一切:仓库的大小、目标机的配置、首次同步所需的带宽,以及真正出事时恢复所需的分钟数。

有两个错误会毁掉这一步。第一个是「求稳」式全量夜备:仓库膨胀,每次运行越来越慢,而你真正需要的状态反而淹没在永远不会去恢复的噪声里。第二个是黄金镜像:一份调优后服务器的快照,随着软件包和内核悄然漂移而慢慢腐坏,等到唯一一次用它重装系统时,镜像本身就是坏的。每月都跑一次的构建脚本始终忠于这台机器;一年没重建过的镜像,只是一个带文件扩展名的猜测,而猜测总在最糟糕的时刻失效。

线划好了、数字记下了,3-2-1 模式就告诉你副本该放在哪里、各自承担什么职责。这个模式历久弥新,是因为它确实有效,也是因为它的大多数失败都是自己造成的:下一节会把每一份副本对应到它所防御的灾难,并说明为什么其中一份必须能活得比这台机器更久。

VPS $4.80* 起(年付期限),存储 1–5 TB NVMe 年付折合 $24/月起,带 IPMI 的独立服务器 $39.20/月起。加密货币账单,免 KYC。

立即启动

三份副本、两种介质、一次真正跑过的恢复

3-2-1 规则听起来像口口相传的经验,但它其实是一张故障域地图:之所以要三份副本,是因为有三种不同的东西会坏。在线数据是第一份副本,而当你需要这条规则时,它按定义已经在出事了。第二份是机器本地的快照,用于秒级回滚——比如那个你两分钟内就想撤掉的失败部署。第三份是脱离本机的备份,它能在机器本身消亡后幸存,是唯一能应对供应商倒闭、机架断电或加密勒索事件的那一份。每份副本各司其职;麻烦从你让一份副本包办三件事开始。

两种介质同样关键:本地 NVMe 用于以秒计的恢复,再加上一份真正隔离的存储副本——无论是另一个账户、另一家供应商,还是按需挂载的冷存储。从本地 NVMe 恢复只是一条 cp 的事;而通过 1 Gbps 不限流量端口拉取一个大仓库,大数据集要跑一整夜,小数据集只需一杯咖啡的工夫。介质隔离的意义在于:单块控制器故障,或一个拿着这台机器自身凭据运行的勒索进程,无法在同一分钟内同时触及两份副本。

第三条——经过实测的恢复——是压力之下唯一还有人记得的规则。把它排进日程:每个季度,在日历上安排一次恢复到临时目录并与源数据做 diff 的运行。未经测试的备份会静默失效,直到某天 diff 告诉你,你以为的 40 GB 其实只有 4 GB,或者你唯一需要的那份文件三周前就被一条没人审核过的保留策略清掉了。恢复测试就是审计本身;这条规则里的其他一切,都是为它服务的记账工作。

这里最经典的错误是算术上的自我安慰:把 RAID 1 镜像算作第二份副本,或者把机器本地快照当作离机备份。它们都活在你想投保的同一个故障域里——同一块硬盘、同一个控制器、同一个宿主机,有时还是同一个机架。同一家供应商上的两份副本是 2-1-1,而一次拿到已挂载存储访问权限的勒索事件,会在你察觉之前把它打回 1-1-1。把第三份副本放在这台机器用自身持有的凭据够不到的地方,这条规则才真正开始发挥作用。

三个角色都点名之后,工具各就各位:Borg 和 Restic 用内置的加密与去重构建离机这一腿,平台的快照附加项则承担快速回滚的角色。两者经常被混为一谈,下一节会在这种混淆让你付出一次恢复的代价之前,把界线画清楚。

快照是回滚,不是备份

平台快照让人感觉像备份,因为两者都能把文件找回来,但它们应对的是不同的灾难。快照与在线机器同属一个平台,常常还在同一个存储池、同一个集群、同一家公司里。对于你自己造成的故障,它是恰到好处的工具:失败的部署、搞砸的模组包更新、一处改完起不来的配置。对于平台自身造成的故障,以及那些带着加密而来的故障,它都是错误的工具——因为这两种灾难完全可能把快照层连同在线机一起带走。

在 VPSbit 上,快照作为结算附加项随 VPS 套餐提供,这就是它诚实的定位:适合变更前回滚,但太浅,单靠它称不上一套策略。离机这一腿才是第二台机器体现价值的地方:在你自己掌控的目标机上建一个 Borg 或 Restic 仓库,副本就能与源机走同一条仅加密货币、免 KYC 的轨道,且目标机永远不持有明文——下一节会把这一点固化为铁律。这两层加起来每月只多花几分钟,却能应对任何一层单独应对不了的故障。

按第一节记下的状态数字来定目标机的规格:仓库装进 80 GB NVMe 时,选 Core,牌价 $6/mo——年付折合 $4.80/mo;当去重后的历史数据需要 320 GB 空间和不限流量的 10 Gbps 端口来加速首次同步时,升级到 Titan,牌价 $24,年付折合 $19.20。一张账单全部搞定,而十二座城市让你可以把副本放进与源机不同的司法辖区——如果你希望副本位于源机法律管辖范围之外的话。

本节收尾是两个快照特有的陷阱。第一,大多数快照实现恢复的是整块磁盘而非单个文件:为了救一份配置而回滚,会把机器上所有数据库一并拉回同一时刻——这正是本指南后面数据库专属流水线存在的理由,哪怕快照已经开启。第二是保留策略:快照按代数保存,一个月的备份可能深藏三代,而且不会主动告诉你。快照为速度而生;备份为生存而设;让第七节的恢复测试同时看住它们——因为谁都不会主动坦白自己的局限。

只要你在源端正确配置了加密,你刚租下的目标机就永远读不到你发给它的内容。这一项设置能让被偷走的仓库变成一场虚惊,这正是下一节的主题。

在源端加密,让目标机永远不成为风险

整个备份设计里最可怕的那台机器,是存放所有副本的那台——除非它一份也读不了。客户端加密彻底改变了威胁模型:Borg 和 Restic 在第一个字节离开源机之前就完成加密,目标机存的是密文,被攻陷的目标机不等于数据泄露,一个在目标机上拿到 root 的好奇旁观者看到的只是一片噪声。这也是为什么离机这一腿永远不该是裸的未加密 rsync 到某个目录——哪怕第一天看起来再方便。

两款工具都把默认路径设计成了正确路径。borg init --encryption=repokey 创建的仓库,其密钥由你的口令派生并保存在仓库内部;restic init 在首次备份时做等价的事情。两者在 Borg 官方文档和 Restic 手册里都有清晰的说明。口令通过环境变量 BORG_PASSPHRASE 和 RESTIC_PASSWORD 传递,这正是无人值守的每夜运行成为可能的原因——不需要人守在提示符前。Keyfile 模式则把密钥拆成 ~/.config/borg/keys/ 下的一个文件,更严格,但多出一件可能丢失的东西。选定一种模式,写进运维手册,并在仓库的整个生命周期里保持不变。

接下来收掉这个悖论:加密密钥如今是整个设计里唯一不可恢复的状态。没有口令的仓库就是随机噪声,Borg 和 Restic 不会替你暴力破解,也没有任何工单能修复一个被遗忘的口令。所以密钥本身也要享受 3-2-1 待遇:口令放进密码管理器,在威胁模型允许的前提下打印一份锁进抽屉,并在运维手册里写明仓库用的是哪种模式。丢了密钥等于同时丢掉所有副本——这是这个阶段你仍能制造的唯一的单点故障。

常见的失败都是操作层面的,不是数学层面的。为了让 cron 能跑,把口令粘进 .bashrc,意味着任何能读你 dotfiles 的东西都能读到你的备份身份。周五创建的 repokey,口令写在便利贴上、便利贴跟着笔记本一起报销,四年的历史就变成了噪声。还有更隐蔽的一种:密钥今天能用,是因为它还缓存在你的 shell 里,但在全新会话里做恢复测试时,系统会要求输入一个谁也想不起来的口令。这些问题每一个都会被季度恢复测试当场抓住——这也是它被排进日程、而不是靠英雄主义临场发挥的又一个理由。

现在,文件、配置和密钥都以加密且去重的方式传输了。数据库还需要在上面再加一层,因为它们的状态在复制过程中会不断变化,对运行中的引擎做文件级快照就是碰运气——下一节用一条专属流水线来解决这个问题。

数据库需要自己的流水线

直接复制一个正在运行的数据库目录不是备份;那是多绕几步的损坏抽奖。PostgreSQL 或 MySQL 这类引擎会把数据分散到许多文件里,并把写入缓冲在内存中,所以一次在半路上截取的逐字节复制,可能漏掉存在于某个文件、却不在另一个文件里的事务。副本也许能完整恢复,也许只能恢复一部分,也许干脆起不来——而你没跑过恢复测试,就永远不会知道是哪一种。数据库之所以配得上一条专属流水线,是因为它的一致性存在于事务边界,而不是文件边界。

底线是一致性逻辑转储:pg_dump -Fc 在事务边界上取得一致快照,自带压缩,可用 pg_restore 恢复。MySQL 对应的答案是 mysqldump --single-transaction,对 InnoDB 表做等价的事情,且不会把读请求挡在外面。在文件级备份之前先跑转储,转储文件随其他数据一起运走,每日底线就守住了:平台和引擎支持的地方,数据库上连续归档;每日转储作为兜底——总比什么都没有强。

连续归档是升级版,PostgreSQL 官方文档写得很清楚:设置 wal_level=replica,把 archive_command 指向一个复制目标,每个写前日志段一写满就运到离机存储,详见连续归档章节。用基础备份加归档段做重放,你可以到达任意时间点,而不仅仅是昨晚——下午 3 点的一次误操作,可以变成恢复到下午 2:59,而不是赔掉一整天。这就是「有一份备份策略」和「拥有恢复能力」的区别,而代价只是一行配置,外加在两次运出之间存放日志段的磁盘。

典型错误是版本和漂移。把转储恢复到更新的大版本也许能行;恢复到更旧的版本一定不行,所以要把引擎版本记在转储旁边,或者把 pg_dump --version 纳入归档命名。第二,在服务器运行期间 rsync /var/lib/postgresql——每夜文件任务让人误以为这没什么,直到恢复时数据库起不来。第三,从未被恢复过的转储:一个能通过 pg_restore --list 的文件只证明了它能被解析,没证明它能被恢复。下一节的季度测试证明的才是第二件事,而那才是要紧的。

状态被一致地捕获并加密运出之后,剩下的就是算术了:多久跑一次,保留多久,仓库需要装下多少历史。下一节讲调度与保留——两者都由数字决定,而不是由心情决定。

调度与保留,由数学而非心情决定

「多久备份一次」本身就是个错误的问题,因为诚实的答案取决于两个你还没写下来的数字:你能承受丢失多少分钟的工作,以及你能承受宕机多久。前者决定调度,后者塑造设计。对大多数机器来说,答案比想象中平淡:文件每日一次,数据库连续归档,再加一条排练过的恢复路径。这也是为什么本指南通篇的底线是每日而不是每小时,以及为什么每小时一次很少能扛住自己的带宽账单。

文件以每日运行为底线;数据库在支持的地方上连续归档,见上面的流水线。保留策略则做成一架梯子:borg prune --keep-daily 7 --keep-weekly 4 --keep-monthly 6 保留七份日备、四份周备、六份月备——这个 7-4-6 默认值适配大多数负载。Restic 用同样的语法表达:restic forget --keep-daily 7。两条 prune 命令都应和备份本身放在同一组 crontab 条目里,cron 格式让周期性运行变得轻而易举。仓库不会每晚增长一整个副本,因为去重只存储变化的块,而以文本为主的状态往往能压缩到原始大小的很小一部分。

带宽算术让调度保持诚实。80 GB 的首次推送走 1 Gbps 不限流量端口,线速下约十一分钟,算上协议开销和磁盘瓶颈,现实中也就是一个晚上;之后的每夜增量只要几秒到几分钟。不限流量在这里很重要:备份任务恰恰是让按量计费变得不可预测的那种负载,而为了省带宽而跳过的离机副本,就是你其实没有的副本。把首次同步当项目来预算,把每日运行当反射来对待。

失败模式全都出在时序上。先 prune 后校验,昨晚引入的一次损坏就可能把最后一份完好的代次清掉,所以要先跑 borg check 或 restic check 再 prune,顺序不能反。两个重叠的 cron 运行会损坏锁文件并交错写入;用 flock 包住任务,或者改用拒绝重叠的 timer。保留策略设得太紧——只有七份日备、后面空空如也——意味着你今天才发现的慢性损坏早已轮转出仓库。梯子的存在,正是为了那些要几周才会被察觉的故障。

现在调度已经无人值守地运转了,而这恰恰是为什么最后一块必须以同样的纪律排进日程:恢复测试——它决定这一切到底是备份,还是业余爱好。它是第七节,也是唯一真正要紧的一节。

季度恢复测试:唯一算数的审计

未经测试的备份只是一种希望,不是备份,而在凌晨 4 点失效的恰恰就是希望。恢复测试不是应急活动;它是一次排进日程的运行,每季度一次,恢复到临时目录并做 diff。它的产出不是安全感,而是两个数字:恢复花了多久,有多少字节不一致。本指南的其他一切,都是为了等来这样一个早晨——这两个数字出现在日历邀请里,而不是事故频道里——而这两个早晨之间的差距,就是这项纪律的全部回报。

机制故意做得枯燥。mkdir /srv/restore-test,然后 borg extract 或 restic restore 把最新归档恢复进去,再用 diff -r 对比源路径,并对那些真正挣钱养家的文件做 sha256sum 抽查。数据库有自己的考场:pg_restore 恢复到一个一次性集群里,对它跑应用的 schema 检查,再数一数业务真正读取的两三张表的行数。记下耗时,因为那个数字才是你真实的恢复时间目标,它应该写进运维手册,而不是留在你的记忆里。

每年升级一次测试:用 Ansible playbook、仓库,除此之外什么都不用,在一台空白 VM 上做一次完整重建。这一跑验证的是运维手册,而不仅仅是仓库,也是对真实灾难的唯一一次彩排——机器没了,替身是空白的,仅有的输入就是脚本和副本。一年一小时的彩排,远比在最糟时刻临场发挥一整天便宜,而且彩排通常能找出那一步谁都没写下来的操作。

测试有两种撒谎方式。在同一台机器上、用缓存凭据做测试,证明的是仓库而不是运维手册——因为环境变量里的口令不是你脑子里的口令。只测解压,证明的是字节而不是服务:一个恢复到 /srv/restore-test 却从未启动过的 Web 应用,可能带着 diff 看不见的状态假设。把测试像备份一样按季度排进日程,用同样的 cron 纪律——因为未经测试的恢复会静默失败,而安静恰恰是这个日历条目存在的意义。

状态线、副本、加密、数据库流水线、保留策略、测试:六个部件,要么环环相扣,要么各自散架。最后一节把它们组装成一套可以从头跑到尾的操作顺序——在一台全新的机器上,一次坐下完成。

3-2-1 备份例程:按这个顺序执行

从那条线开始。巡一遍机器,列出状态路径——/etc、数据库目录、/home、/srv——用 du -sh 测量并记下数字,因为这些数字决定目标机的规格,也预测恢复所需的时间。同一次坐下来,顺手刷新重建脚本:那份能把空白镜像变成这台服务器的 Ansible playbook 或 cloud-init 文件。如果脚本已经过时,现在更新它就是备份工作的一部分,而不是另一件杂事——因为等到需要它的那天,才发现它引用的软件包早已不存在,就晚了。

第二步,租下目标机并初始化仓库。用第二台机器做 Borg 或 Restic 的目标,让离机这一腿跑在你已经信任的轨道上;第一天就带加密初始化——borg init --encryption=repokey 或 Restic 的等价命令——并把口令放到一台笔记本坏掉也丢不了的地方。第三步,赶在其他一切之前先接好数据库流水线,因为它的一致性要求最苛刻:至少要有 pg_dump -Fc,引擎和日程支持就上 WAL 归档,InnoDB 用单事务转储。数据库这步打头阵,因为其他一切都能容忍文件级复制,而它不能。

第四步,把每日文件任务连同保留梯子一起排进日程——borg prune --keep-daily 7 --keep-weekly 4 --keep-monthly 6——用 flock 包住以防运行重叠,并把校验排在 prune 之前。第五步,把平台快照作为变更前仪式排进日历:模组包更新和风险部署之前先打快照,让快速回滚这一腿始终保持新鲜——游戏服务器指南里有这套仪式的实战示范。两条腿应对不同的故障,顺序也很重要:离机副本保护你免受平台的伤害,快照保护平台免受你的伤害。

第六步,在调度上线的同一周就跑第一次恢复测试,而不是等到理论上该跑的那个季度:恢复到 /srv/restore-test,用 diff -r 对比源数据,把数据库恢复进一个临时集群并让应用对着它启动。然后把季度循环写进日历,并把耗时数字记在旁边。收尾工作是写运维手册:口令位置、keyfile 副本、仓库模式,以及那两个恢复数字——好让下一个不是你的人,能在凌晨 4 点照着执行。

从那以后,整套例程自我运转:每日任务自动 prune,季度测试持续验证,唯一周期性的人工事务,是让重建脚本始终忠于不断演化的这台机器。当状态增长超过目标机磁盘时,先扩目标机,再扩仓库,顺序绝不能反——因为一个装不下的仓库,就是一个会静默清掉自己历史的仓库。

快照算备份吗?

不算——快照是与在线机器同平台的高速回滚,它能覆盖一次失败的部署,却覆盖不了供应商故障或勒索软件。把它们留给变更前回滚,让离机的加密副本——Borg 或 Restic 推到第二台机器——成为应对平台级灾难的那一层。

应该多久备份一次?

数据库:支持的地方上连续归档,每日作为底线。文件:每日一次。恢复测试按季度排进日程,因为未经测试的恢复会静默失效——产出副本的调度只是工作的一半,经过测试的恢复才是决定这一切是否真正有效的那一半。

可以从其他供应商的服务器备份到 VPSbit 的机器上吗?

可以。任何有 SSH 的服务器都能通过 SFTP 或原生 Borg、Restic 协议推送到你的机器,且目标机无从得知源机托管在哪里。在源端加密,让目标机只持有密文,副本就能从头到尾保持你仅加密货币、免 KYC 的姿态。

独立服务器怎么备份?

同样的模式,更大的数据集:裸金属上没有快照,所以离机这一腿承担整个设计——按数据量选一档 VPS,通过 SSH 用 Borg 或 Restic 拉取。把 RAID 当冗余,别当备份:镜像能应对一块坏盘,应对不了坏掉的整机或被误删的目录。

备份目标机该多大?

从用 du 测出的状态大小出发,乘以保留深度,再除以第一个月后观察到的去重比——以文本为主的仓库通常远低于原始大小。80 GB 目标机装得下小型状态集,320 GB 能吸收持续增长的历史,更快的端口则能缩短首次同步。

准备启动?

配置主机 — VPS、存储或裸金属服务器 — 设置密码,支付随后生成的账单。