控制面板里的快照按钮,是我们客户中心里使用最多、也被误解最深的功能。快照就像安全带:它能让您免受自己下一条命令的伤害。但它和服务器存放在同一台宿主机上,所以当您丢失宿主机、整个机房或者账户时,它救不了您。下面就是我们推荐的三层备份方案,其中包含一份每月只需几美元的 restic 实操配方,以及每月一次的恢复测试,正是它让这套方案成为真正的备份,而不是一厢情愿。
三层方案,对应三类故障
| 层级 | 可防范 | 无法防范 | 恢复时间 |
|---|---|---|---|
| 控制面板快照 | 糟糕的升级、敲错的 rm、损坏的配置 | 宿主机丢失、机房丢失、账户被攻破 | 2 到 5 分钟 |
| 异地 restic 仓库 | 以上所有情况,外加宿主机和机房丢失 | 攻击者拿到您的 restic 密钥后删除仓库 | 文件只需几分钟,完整重建需要一小时 |
| 第二份副本,不同服务商,仅追加 | 以上所有情况,外加服务器被入侵 | 两把密钥都丢失 | 同上,只是要从更冷的存储中取回 |
第一层:用好快照
每次升级或做有风险的改动之前,都先创建一个快照;快照是增量的,速度很快。保留两三个滚动快照就够了,不要留三十个:快照只是同一块 NVMe 上的一个时间点,旧快照不过是多占的、还得您费心留意的磁盘空间。恢复快照会把整块磁盘回滚,所以快照之后写入的所有内容都会丢失,包括数据库里的行。这在升级搞砸时正是您想要的,但把它当作“上周二的备份”来用,就不是您想要的了。
第二层:用 restic 备份到异地存储桶
restic 支持去重,在客户端完成加密,并且能对接任何兼容 S3 的存储桶。任何对象存储都可以;对于位于法兰克福的 CheapServ 服务器,最理想的是另一家服务商在欧洲区域的存储桶。安装并初始化:
apt install -y restic
cat > /etc/restic.env <<'EOF'
export RESTIC_REPOSITORY=s3:https://s3.example-storage.com/backup-web01
export RESTIC_PASSWORD=long-random-passphrase-stored-in-your-password-manager
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
EOF
chmod 600 /etc/restic.env && . /etc/restic.env
restic init
把文件和数据库转储一起备份,然后按计划清理过期的备份:
cat > /usr/local/bin/backup.sh <<'EOF'
#!/bin/bash
set -euo pipefail
. /etc/restic.env
mkdir -p /var/backups/db
sudo -u postgres pg_dumpall --clean | gzip > /var/backups/db/pg-$(date +%u).sql.gz
restic backup /etc /srv /var/backups/db /home --exclude-caches --exclude '/srv/**/node_modules' --tag daily
restic forget --keep-daily 14 --keep-weekly 8 --keep-monthly 12 --prune
restic check --read-data-subset=5%
EOF
chmod +x /usr/local/bin/backup.sh
systemd-run --on-calendar='03:15' --unit=restic-backup /usr/local/bin/backup.sh # or a proper timer unit
有三个细节很重要:要转储数据库,而不是备份它的文件(对运行中的 PostgreSQL 直接拷贝文件,得到的副本是不一致的);--exclude-caches 和 node_modules 这条规则能让仓库保持精简;restic check --read-data-subset 每晚回读一部分数据,这样在您真正需要恢复之前,就能发现数据损坏。
一台典型的 Web 服务器,去重之后每月产生的唯一数据量是 1 到 5 GB。按对象存储的价格算,这远不到一美元;这一整层的成本,比一杯咖啡还便宜。
第三层:服务器删不掉的副本
如果攻击者拿到了 root 权限,就能拿到 /etc/restic.env,进而对您唯一的备份执行 restic forget --prune。有两种解决办法:给服务器所用的密钥只授予存储桶的只写权限(大多数服务商都支持不含 DeleteObject 的策略),或者在另一台独立的机器上运行 restic copy,把数据复制到第二个仓库中,而服务器永远接触不到这个仓库的密钥。放在另一个机房的一台 $3 的 VPS-1,每晚用它自己的凭据去拉取数据,就是一个相当合格的第三层。
每月一次的测试
没经过测试的备份,只是一厢情愿。每月一次,设一个日历提醒:
- 在控制面板中部署一台临时的 VPS-1(一分钟,几美分的余额)。
- 安装 restic,复制
/etc/restic.env,执行restic restore latest --target /restore。 - 把数据库转储导入一个全新的 PostgreSQL,执行一条真实的查询;再打开一个恢复出来的文件。
- 记下花了多长时间。这个数字就是您真实的恢复时间。
- 取消这台临时服务器。
第一次测试,总会发现点什么:一个您忘记备份的路径,一份因为 cron 用户权限不足而为空的转储文件,一个事后才发现很重要却被排除掉的目录。这正是测试在起作用。把问题修好,第二个月就会平淡无奇了。
不该做的事
- 不要把唯一的一份备份放在同一台服务器上的
/backups里。它会随着磁盘一起消失。 - 不要用 rsync 去同步运行中的数据库文件,请转储它们。
- 不要只把 restic 密码短语保存在服务器上。服务器没了,备份的钥匙也就跟着没了。
- 不要什么都备份。
/var/lib/docker下的镜像、缓存和软件包归档都可以重新生成;请备份数据,以及用来生成它们的配置。
三层方案到位之后,最坏的情况,也就是服务器凭空消失,只会变成一个下午的工作量,而不是一场足以让公司倒闭的灾难。一周里其余的小状况,交给控制面板快照就够了。
