restic + rclone 实现 vps 备份
本文最后更新于 2025年9月15日 晚上
每到考试周,就会忍不住折腾,所以今天随便谢谢 vps 备份方案
vps 备份主要是两种,一种是依靠服务器提供商自带的快照和备份;另一种就是自己折腾放到云盘上。
前者不一定所有厂商都有,而且不一定免费;后者更具有折腾性,但往往只能选择备份部分重要数据。
这里采用后者方法,具体使用 restic + rclone 来备份(rclone 主要是用于读写 Google Drive,而 restic 是备份工具)。
原因
我的备份需求:
- 备份分散在各处的配置文件:.vimrc, .bashrc, nginx 配置文件等。
- 备份 ~/documents 以及 docker 相关文件
一个涉及分散文件的备份,一个涉及大型文件的备份。
如果单独采用 rclone,那么两个需求都不好实现:
- rclone 需要运行多次来满足第一个需求,不能从文件中读取所有需要备份的文件。
- rclone 本质是文件同步,尽管有增量功能和每个文件很小,但在有大量文件的情况下,表现极差
而 restic 很好能解决这两个问题并且有额外好处:
- restic 能从文件中读取需要备份的路径
- restic 会将小文件(当然,大文件也是)合并打包到 pack 文件中,再传输
- restic 会进行文件压缩,文件大小也会更小
- restic 支持版本控制,它是有快照概念的
- restic 的备份是加密的,即使是共享云端存储空间,别人也不会知道内容(当然,即使这样也不推荐)
- restic 是多平台的,Windows 也能使用
目标
通过利用 rclone 挂载存储(包括 onedrive, google drive, webdav 等),让 restic 定时备份到指定存储中,同时为了存储大小考虑,定时删除过期快照,提供备份失败邮箱提醒
步骤
下载 rclone
1
sudo -v ; curl https://rclone.org/install.sh | sudo bash配置 rclone 后端
如果已有 rclone 配置文件,可以直接复制使用
类 Unix 系统的 rclone 配置文件位于
~/.config/rclone/rclone.conf。路径与 home 有关,所以不同用户会有不同配置,使用硬链接可以共享配置Windows 系统的 rclone 配置文件位于
%APPDATA%\rclone\rclone.conf如果没有,使用
rclone config命令来引导添加配置下载 restic
1
2sudo apt update
sudo apt install resticrestic 初始化以及备份
1
2restic -r rclone:remote:backup init
restic -r rclone:remote:backup backup -v --files-from /opt/backup/backup_files定时删除
保留最后 3 天(每天一份),最后 5 周(每周一份)。
1
restic -r rclone:remote:backup forget --keep-daily 3 --keep-weekly 5 --prune自动任务
编辑脚本:
1
2
3
4
5
6
7
8#!/usr/bin/env bash
export RESTIC_REPOSITORY="rclone:remote:backup"
export RESTIC_PASSWORD="pass"
restic backup -v --files-from /opt/backup/backup_files
restic forget --keep-daily 3 --keep-weekly 5 --prune使用 cron:
1
sudo crontab -e配置以下:
1
30 17 * * * /opt/backup/backup.sh >> /opt/backup/backup.log 2>&1使用 systemd timer
配置邮件
安装
msmtp:sudo apt install msmtp配置邮件脚本
service-failure-notify.sh:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62#!/usr/bin/env bash
# service-failure-notify.sh
# 用 msmtp (命令行参数模式) 发送 systemd 服务失败告警邮件
set -euo pipefail
# ====== 配置区 ======
SMTP_HOST="smtp.gmail.com"
SMTP_PORT="587"
SMTP_USER=""
SMTP_PASS=""
FROM_ADDR=""
TO_ADDR=""
LOG_LINES=30
# ===================
export SMTP_PASS
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <unit-name>"; exit 1
fi
UNIT="$1"
HOSTNAME="$(hostname -f 2>/dev/null || hostname)"
NOW="$(date '+%Y-%m-%d %H:%M:%S %Z')"
# 收集状态 & 最近日志
STATUS="$(systemctl status --full "$UNIT" 2>&1 || true)"
LOGS="$(journalctl -u "$UNIT" -n "$LOG_LINES" --no-pager 2>&1 || echo 'journalctl not available')"
SUBJECT="[告警] 服务 $UNIT 失败 - $HOSTNAME"
# 构造完整邮件(RFC5322 格式)
BODY=$(cat <<EOF
From: $FROM_ADDR
To: $TO_ADDR
Subject: $SUBJECT
Date: $(LC_ALL=C date -R)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
服务名称: $UNIT
主机名: $HOSTNAME
失败时间: $NOW
服务状态:
$STATUS
最近日志(最新 $LOG_LINES 行):
$LOGS
EOF
)
echo "$BODY" | msmtp \
--host="$SMTP_HOST" \
--port="$SMTP_PORT" \
--auth=on \
--user="$SMTP_USER" \
--passwordeval='echo "$SMTP_PASS"' \
--from="$FROM_ADDR" \
--tls=on \
-t配置邮件 service
/etc/systemd/system/[email protected]:1
2
3
4
5
6
7[Unit]
Description=Notify user of service failure
[Service]
Type=oneshot
User=root
ExecStart=/opt/backup/service-failure-notify.sh %i配置 backup timer, service:
/etc/systemd/system/backup.timer:1
2
3
4
5
6
7
8
9
10
11[Unit]
Description=Run backup script regularly
[Timer]
OnCalendar=*-*-* 01:30:00 Asia/Shanghai
# 默认为同名的 service,可以不用指明
Unit=backup.service
Persistent=true
[Install]
WantedBy=timers.target/etc/systemd/system/backup.service:1
2
3
4
5
6
7[Unit]
Description=Backup service
OnFailure=service-failure-notify@%n
OnSuccess=service-success-notify@%n
[Service]
ExecStart=/opt/backup/backup.sh加载配置
1
2systemctl daemon-reload
systemctl enable backup.timer调试
1
2
3
4# 修改错误 Restic 密码后,尝试;预期会收到邮件
systemctl start backup.service
# 修正 Restic 密码
systemctl start backup.service
rclone
rclone copy 不会删除文件,rclone sync 只对远端操作,会删除文件。
restic
restic 备份是基于路径的,这意味着它会将从根目录
/到你需要备份的文件/path/to/backup路过的文件夹都会备份下来(和 linux 下的压缩有点像),当恢复时,你可以指定路径,例如/tmp/restore,则会得到类似/tmp/restore/home/username/...之类的东西。而且 restic 也提供了挂载的方式来恢复。restic 可以配置环境变量:
RESTIC_REPOSITORY以及RESTIC_PASSWORD来实现每次不用输入-r repository和密码。查看所有快照:
restic snapshots查看某个快照内容:
restic ls <snapshot-id>,同样支持不完整的 id从快照中恢复:
1
2
3
4
5
6
7# 从某个仓库恢复所有文件,恢复到指定路径:
restic -r /srv/restic-repo restore 79766175 --target /tmp/restore-work
# 可以用 latest 代替上面的 79766175,用 path 限制恢复的路径,用 host 限制快照来源。
restic -r /srv/restic-repo restore latest --target /tmp/restore-work --path /home/username --host hostname
# 可以利用 include 和 exclude 进一步限制恢复的文件You can use the command restic ls latest or restic find foo to find the path to the file within the snapshot. This path you can then pass to –include in verbatim to only restore the single file or directory.
其他方案
borg: 作用和用法和 restic 相似,但 restic 对部分的云端有天然的支持。
duplicati: 似乎稳定性有点问题?而且是 .net 所写,linux 下运行需要 mono,所以排除。
duplicacy: 商用付费,个人免费。一个是文档感觉不规范,一个是似乎不支持从多个文件备份,不太符合我的需求,一个是 GitHub 上一堆 Issue 没有处理。但从官网来看,性能似乎是最好的一个(当然从备份角度来讲,性能不是最重要的)。另一个好处就是天然支持大部分云端,不用 rclone。