Restic
本页面讨论了 restic 备份工具,提供了一个“快速入门”指南,并提出了在 Arch Linux 环境下的最佳实践。
Restic 的主要特性和优点是
- 加密备份
- 远程备份
- 内置压缩支持
- 高效存储(基于块的增量,数据不重复)
- 可以灵活使用自定义调度器,例如 cron 或 systemd
- 使用 Go 编写,提供独立的二进制文件
安装
安装 restic,然后在空目录中初始化仓库(用于本地备份),使用
$ restic init --repo /path/to/backup/directory/
请参阅官方教程。
安全
Restic 规定了使用时的威胁模型假设。
它对仓库使用对称加密。这给计划备份带来了一些问题[1][2],因为密钥通常必须以纯文本形式存储,以便自动化进程能够创建备份。理想情况下,应该有非对称加密,允许使用公钥(在 restic 的自动化脚本中使用)创建快照,但只能使用私钥解密快照,但这目前不支持。
作为 restic 对称加密的优势,它具有 restic-key(1) 命令来管理仓库的多个密钥。因此,可以添加主密钥和辅助密钥。此外,可以使用 --password-command
选项从密钥库中获取密钥。结合使用,可以保护主密钥并使用辅助密钥
- 用于只追加备份仓库,
- 通过类似 systemd-creds 的密钥库或第二因素令牌来保护它。
上述方法可以为系统(root 用户)和普通用户配置,从而限制与备份仓库的纯文本密码凭据相关的风险。
计划任务
Systemd 定时器
与其他工具如 timeshift[3] 不同,restic 不包含计划任务功能。您需要使用 cron 或 systemd 定时器。
您可以使用现成的项目,例如 restic-automatic-backup-scheduler,或者遵循此示例,该示例创建本地(完整)系统备份,应以 root 用户身份运行。
此示例假设存在一个现有目录,其中已初始化了现有的 restic 仓库(请参阅 #安装)。
创建独立卷
此步骤是可选的,但最好在此处挂载一个单独的卷,以防止自动备份过程可能消耗操作系统可用的所有空间。
首次 restic 备份将需要克隆整个操作系统,因此所需的最小空间量等于操作系统占用的空间(受制于下面描述的路径排除)或您决定备份的任何其他目录。
当然,您需要空间来存储未来任何额外的增量更改,因此最好创建一个卷,其大小是被备份数据的 2 倍甚至 3 倍。例如,如果 /
占用 55G
,那么您可以创建 /mnt/restic
,大小为 110G
。
Systemd 服务
您将需要一个服务单元。创建一个
/etc/systemd/system/restic-backup.service
[Unit] Description=Backup system [Service] ExecStart=systemd-inhibit /usr/local/bin/restic-backup
配置资源约束
使用 systemd 使您可以选择对备份过程施加资源约束。例如,您可以限制内存和/或 CPU 的量。这是您将在 systemd 服务单元中配置的内容。请参阅 systemd.resource-control(5)。
限制 restic 使用的资源的另一种方法是使用 GOMAXPROCS
环境变量,如官方文档中所述。
Systemd 定时器
您还需要一个定时器单元(此定时器每 15 分钟运行一次)
/etc/systemd/system/restic-backup.timer
[Unit] Description=Timer for full system backups [Timer] OnBootSec=5min OnUnitActiveSec=15min Unit=restic-backup.service [Install] WantedBy=timers.target
备份脚本
您还需要创建一个小的 shell 脚本来传入所有必需的选项,例如
/usr/local/bin/restic-backup
#!/bin/bash if pgrep -f 'restic backup' > /dev/null; then echo 'restic is already running...' 1>&2 exit 0 fi set -e set -v export RESTIC_REPOSITORY='/mnt/restic' export RESTIC_PASSWORD_COMMAND='/usr/local/bin/get-restic-password' export RESTIC_COMPRESSION='off' export RESTIC_CACHE_DIR=~/.cache/restic mkdir -p "${RESTIC_CACHE_DIR}" restic unlock restic backup / --exclude-file=/etc/restic/excludes.txt --tag scheduled restic check --with-cache --read-data-subset=5G restic forget --prune --keep-hourly 24 --keep-daily 30 --keep-monthly 6 --keep-weekly 4 --keep-yearly 3
/usr/local/bin/get-restic-password
#!/bin/bash echo VerySecurePassword123
# chmod 744 /usr/local/bin/restic-backup # chmod 700 /usr/local/bin/get-restic-password
压缩
如果您要备份尚未压缩的数据(例如大型文本文件),您可能需要考虑在 restic 中启用压缩以节省空间。
快照保留
如果需要,调整上面脚本中的 restic forget --prune --keep-hourly 24 --keep-daily 30 --keep-monthly 6 --keep-weekly 4 --keep-yearly 3
值。
配置优先级
您可能还希望调整备份过程的优先级。如果您经常运行备份,您可能需要降低资源使用率,以防止其影响交互式使用。但是,您应该检查备份需要多长时间,并确保它们不重叠(即,在前一个备份尚未完成时启动新的备份)。
您可以使用 nice(1) 来做到这一点。您可能希望通过在资源密集型命令的开头添加 nice 来调整备份脚本,例如
# nice -n 19 restic backup ... # nice -n 19 restic check ...
或者,如果您使用 ananicy-cpp,您可能需要确保在 /etc/ananicy.d/
下的配置文件中配置了优先级。
/etc/ananicy.d/00-types.types
{"type":"file-sync","nice":19,"ionice":7}
/etc/ananicy.d/99-custom/file-sync/restic.rules
{"name": "restic", "type": "file-sync"}
有关更多信息,请参阅 restic FAQ。
排除列表
在 /etc/restic
下添加排除文件,例如
/etc/restic/excludes.txt
/data/** /dev/** /home/*/**/*.pyc /home/*/**/__pycache__/** /home/*/**/node_modules/** /home/*/.cache/** /home/*/.local/lib/python*/site-packages/** /home/*/.mozilla/firefox/*/Cache/** /lost+found/** /media/** /mnt/** /proc/** /root/** /run/** /swapfile /sys/** /tmp/** /var/cache/** /var/cache/pacman/pkg/** /var/lib/docker/** /var/lib/libvirt/** /var/lock/** /var/log/** /var/run/**
启用
不要忘记启用 restic-backup.timer
。
远程只追加备份仓库
与大多数备份解决方案一样,restic 备份通常可以由执行备份的用户修改。这使得备份数据容易受到操纵和勒索软件等威胁。虽然上面的示例以 root 用户身份运行备份,从而防止了本地非特权用户的简单修改,但系统遭到入侵将允许恶意软件也删除/覆盖备份数据,即使该数据位于远程仓库中(因为本地用户已通过身份验证连接到远程仓库)。为了设置无法修改的安全备份解决方案,restic 可以与 rclone 结合使用,以利用其只追加功能在受限的远程系统上运行。
--keep-within
选项。通过 ssh 设置受限的 'rclone serve'
以下设置会将用户限制为指定的命令,有效地仅允许向路径 /home/myuser/backup
添加新数据,同时防止修改现有文件。
/etc/ssh/sshd_config
/etc/ssh/sshd_config Match user myuser ForceCommand rclone serve restic --stdio --append-only ./backup
通过 rclone 运行 restic
在远程 ssh 服务器上初始化备份仓库
restic -o rclone.program='ssh myuser@backup.tld' -r rclone: init
使用 rclone 作为传输执行 restic 备份
restic -o rclone.program='ssh myuser@backup.tld' -r rclone: backup /home/myuser/importantData
只追加脚本
请注意,不再可能使用 prune 选项来删除旧备份,因为现在无法修改远程仓库上的任何数据。用户只能写入追加新文件并读取现有备份数据以进行恢复。
/usr/local/bin/restic-backup
#!/bin/bash if pgrep -f 'restic backup' > /dev/null; then echo 'restic is already running...' 1>&2 exit 0 fi set -e set -v export RESTIC_REPOSITORY="rclone:" export RESTIC_PASSWORD_COMMAND='/usr/local/bin/get-restic-password' export RESTIC_COMPRESSION='off' export RESTIC_CACHE_DIR=~/.cache/restic RCLONE_EXEC="rclone.program=ssh myuser@backup.tld forced-command" DATA_PATH="/home/myuser/importantData" mkdir -p "${RESTIC_CACHE_DIR}" restic -o "${RCLONE_EXEC}" unlock restic -o "${RCLONE_EXEC}" backup ${DATA_PATH} --exclude-file="$HOME/.local/scripts/excludes" --tag scheduled restic -o "${RCLONE_EXEC}" check --with-cache --read-data-subset=5G
恢复备份数据
restic -o rclone.program='ssh myuser@backup.tld forced-command' -r rclone: restore latest --target /tmp/restoredData
技巧与诀窍
使用令牌作为第二因素的密码
以下示例使用 Universal 2nd Factor 令牌,在本例中为 YubiKey,来派生用于使用其 --password-command
选项解锁 restic 仓库的密码。先决条件是已设置的 challenge-response 插槽,因为它可用于多种目的。
首先,生成一个随机用户密钥,并将其馈送到令牌的 challenge-response 函数中,以获得其令牌唯一的哈希值
$ dd if=/dev/urandom of=/home/username/resticblob bs=512 count=1 $ chmod 400 /home/username/resticblob $ ykchalresp -2 -i/home/username/resticblob 71832e30cf9d5adb8672154d7a83fa1684f544d3
其次,复制粘贴哈希值,将其作为用户访问密钥添加到 restic 仓库。
$ restic -r /home/username/restic/ key add enter password for repository: repository 045a06ef opened (version 2, compression level auto) enter new password: enter password again: saved new key with ID 1991e876106f203c245e45a401b59dedec4aae6656f89152b66eca180385c1b
现在,可以使用令牌透明地访问仓库
$ restic -r /home/username/restic unlock --password-command "ykchalresp -2 -i/home/username/resticblob" repository 045a06ef opened (version 2, compression level auto)
注意,对于非交互式使用,此方法需要令牌配置,该配置对于 challenge-response 方法没有用户存在(触摸)验证,并且某些令牌不允许配置该功能。相同的限制适用于其他方法,除非使用 --password-command
选项来执行 shell 脚本以相应地准备其输出。也可以使用 --password-file
选项,例如,请参阅。