国内云厂商
以腾讯云为例可以结合云函数调用服务器提供商的快照 api 实现定期自动备份。
其他 VPS
前者不一定所有厂商都有,而且不一定免费。具体使用 restic + rclone 来备份(Rclone 支持在不同对象存储、网盘间同步、上传、下载,且支持增量备份;而 Restic 是文件加密,增量备份工具,并且支持快照,并且备份与恢复策略都可灵活配置)。
可以结合使用,利用 Rclone
访问广泛的存储后端和 Restic
的加密及去重备份功能。
Rclone
安装 Rclone
- Rclone 也可以从大多数 Linux 发行版的官方仓库安装。例如,在基于 Debian 的系统上,使用:
sudo apt-get update
sudo apt-get install rclone
对于 macos
brew install rclone
配置 Rclone
Rclone 支持多种云存储服务,包括但不限于 Amazon S 3, Google Drive, Dropbox, OneDrive 等。它能够处理文件同步、文件传输以及数据备份任务。
同时配置好的 Rclone 进行迁移也很方便,只要配置一次后,可以在不同的服务器上迁移,只要将配置文件 rclone.conf
进行复制迁移到配置文件夹中就行。
通过 rclone config file
查看配置文件夹位置。
Rclone 连接 OneDrive
更多其他的云存储、云盘挂载见 rclone 文档。
为了在不同服务器间迁移配置,OneDrive 挂载方式推荐通过 webdav
,而不是 api
。
- 启动 Rclone 配置向导:
- 输入
rclone config
。这将启动 Rclone 的配置向导。 - 创建新的远程存储配置,选择
n
新建配置。
- 输入
- 命名远程存储:
- 向导接下来会询问为这个远程存储配置起一个名字为
xx_onedrive
- 向导接下来会询问为这个远程存储配置起一个名字为
- 选择存储类型:
- 向导会展示出支持的存储类型列表。对于通过 WebDAV 挂载 OneDrive,需要找到并选择
WebDAV
(注意,这个列表可能会随 Rclone 版本更新而变化)。
- 向导会展示出支持的存储类型列表。对于通过 WebDAV 挂载 OneDrive,需要找到并选择
- 配置 WebDAV 参数:
- URL:接下来,向导会要求输入 WebDAV 服务器的 URL。OneDrive 的 WebDAV 地址通常形式
https://xxxxxxxcn-my.sharepoint.com/personal/YOUR_ONEDRIVE_USERID/Documents
。这里YOUR_ONEDRIVE_USERID
需要替换成你的 OneDrive 用户 ID。 # Choose a number from below, or type in your own value# 选择 3 / Sharepoint
- 然后输入 email 账号和密码
bearer_token
默认留空
- URL:接下来,向导会要求输入 WebDAV 服务器的 URL。OneDrive 的 WebDAV 地址通常形式
配置完成后通过 rclone ls xx_onedrive:
查看是否正常连接。
Rclone 在配置文件中保存密码时,使用的是 NaCl (Networking and Cryptography library) 的加密库进行加密,但仍需要保管好 rclone.conf
文件。
如果你的系统支持 FUSE,还可以将 OneDrive 通过 WebDAV 挂载到本地文件系统:
rclone mount xx_onedrive:/ /path/to/mountpoint --daemon
使用 Rclone
虽然 Rclone 也支持增量加密备份,但是不支持快照和版本管理。 所以需要增量备份,版本管理的文件,用 Resitc 就比较合适,把 Rclone 作为 Resitc 的后端;而常规文件的远程备份归档,或者多个云存储服务之间迁移数据,直接用 Rclone 就很合适。
常规文件的远程备份归档
这里以 /home/user/data
为例。使用 tar
命令来压缩这个文件夹:
tar -czvf data_backup.tar.gz /home/user/data
使用 gpg
对压缩文件进行对称加密,这里建议使用强加密算法如 AES 256。(虽然 Rclone 也支持在远端指定创建加密文件夹)
gpg --symmetric --cipher-algo AES256 data_backup.tar.gz
执行此命令后,系统会提示输入密码,用于加密文件。这会生成一个名为 data_backup.tar.gz.gpg
的加密文件。
在上传文件之前,确保已经设置好了指向 OneDrive 的 Rclone 远程配置,使用 Rclone 在 OneDrive 上创建指定存放备份的文件夹,比如 normal_backup
:
rclone mkdir xx_onedrive:/normal_backup
上传
rclone copy data_backup.tar.gz.gpg xx_onedrive:/normal_backup
不同的云存储服务之间迁移
使用 Rclone 的 copy
或 sync
命令来迁移数据。copy
命令会将源位置的文件复制到目标位置,而 sync
命令会同步源位置和目标位置的内容,使目标位置的内容与源位置完全一致,包括删除目标位置上在源位置不存在的文件。
使用 copy
迁移数据(不会删除目标中多余的文件):
rclone copy onedrive:Photos gdrive:PhotosBackup
这个命令会将 OneDrive 中 Photos
文件夹的内容复制到 Google Drive 中的 PhotosBackup
文件夹。如果 PhotosBackup
文件夹不存在,Rclone 会自动创建。
使用 sync
迁移数据(使目标与源同步,包括删除操作):
rclone sync onedrive:Photos gdrive:PhotosBackup
这个命令会同步 OneDrive 中 Photos
文件夹的内容到 Google Drive 中的 PhotosBackup
文件夹,使 PhotosBackup
中的内容与 Photos
完全一致。
简单对云存储管理
增加(上传)文件(及过滤规则使用)
已经介绍了的增加(上传)文件,再介绍一些过滤规则使用。
rclone copy / remote:backup --dry-run \
--include "/root/**" --include "/home/**" \
--exclude "/root/.*" \
--exclude "/home/code/**" --exclude "/home/config/test/**"
在这个命令中:
copy / remote:backup
表示将根目录(/
)下的内容复制到远程存储的backup
目录。实际上传的内容将受到下面定义的包含和排除规则的影响。--include "/root/**"
和--include "/home/**"
表示包含/root
和/home
目录及其所有子目录和文件。--exclude "/root/.*"
排除了/root
目录下所有以点(.
)开头的文件和文件夹。--exclude "/home/code/**"
和--exclude "/home/config/test/**"
分别排除了/home/code
和/home/config/test
目录及其所有子目录和文件
删除文件
删除远程存储中的单个文件: 使用 deletefile
命令删除指定的单个文件。
rclone deletefile remote:path/to/file -i
删除远程存储中的整个文件夹: 使用 purge
命令删除整个文件夹及其内容。
rclone purge remote:path/to/folder -i
使用 --dry-run
或 -i
(交互模式)选项可以预览将要执行的操作,而不实际执行,避免误删除。
修改文件
rclone
并不直接支持修改远程存储中的文件内容(例如,编辑文件)。修改通常涉及下载文件,进行本地编辑,然后重新上传覆盖原文件。但有移动操作 move
, 移动操作会将源文件或文件夹删除,仅在目标位置保留副本。
rclone move source:path/to/file_or_folder dest:path/to/dest_folder
rclone move /path/to/local/file_or_folder remote:path/to/dest #从本地移动到远程存储
rclone move remote:path/to/source/file_or_folder remote:path/to/dest #在远程存储内移动
查看文件和文件夹
列出远程文件夹的内容: 使用 ls
命令列出远程文件夹中的文件。
rclone ls remote:path/to/folder
递归列出文件夹及其子文件夹的内容: 使用 lsf
命令以递归方式列出文件夹及其所有子文件夹的内容,可以使用 -R
选项。
rclone lsf -R remote:path/to/folder
查看文件详情: 使用 lsd
命令列出远程文件夹的详细信息,包括子文件夹。
rclone lsd remote:path/to/folder
关键词查询只能用管道符:
rclone lsf remote:path/to/folder | grep "keyword"
Rclone 性能优化
调整并行传输数 --transfers
Rclone 默认同时运行四个文件传输。在带宽允许的情况下,增加 --transfers
参数的值可以显著提高传输速度,特别是在传输大量小文件时。例如,将并行传输数增加到 10:
export RCLONE_TRANSFERS=10
或者
rclone copy /path/to/source remote:destination --transfers 10
调整检查者数量 --checkers
Rclone 使用检查者来检查文件是否需要传输。增加检查者的数量可以加快这一过程,尤其是在有大量文件需要检查时。例如,将检查者数量增加到 20:
rclone sync /path/to/source remote:destination --checkers 20
Restic
Restic 主要特性包括:
- 去重:
Restic
在备份数据时采用去重技术。它将数据分割成小块,并对每块进行哈希处理。如果数据块的内容已经存在于备份仓库中,则不会再次存储,从而有效减少了存储空间的需求。 - 加密:
Restic
默认对所有备份数据进行端到端加密。它在数据离开本地机器之前就进行加密,确保了数据的安全性。 - 快照:
Restic
以快照的形式存储备份。每次备份都是一个完整的快照,但由于去重技术的使用,每个新快照只增加了自上次备份以来变化的数据量。 具体介绍见文档
安装 Restic
大多数 Linux 发行版都可以通过包管理器安装 Restic。例如,在基于 Debian 的系统上,可以使用:
sudo apt install restic
macOS:
brew install restic
配置 Restic
初始化备份仓库: 首先,需要初始化一个备份仓库,这可以是本地目录、远程服务器或任何 Restic
支持的后端存储。
初始化需输入两次密码例如,初始化一个本地仓库:
restic init --repo /path/to/restic-repo
结合已经配置好的 Rclone 初始化 Restic 仓库:
- 使用 rclone 作为后端,初始化 Restic 仓库:
restic -r rclone:OneDrive/backup init
使用 Restic
创建备份
restic -r rclone:OneDrive:backup backup /path/to/your/data
日常使用时常结合多个过滤需求
restic -r rclone:OneDrive:backup backup /root /home \
--exclude '/root/.*' \
--exclude '/home/code' \
--exclude '/home/config/test'
也可由文件读取对应参数,见后面的脚本示例。
同时为了方便管理和识别不同的备份,可在备份时创建添加标签(--tag
)或指定主机名(--host
)
- 使用标签:
restic -r rclone:OneDrive:backup backup /path/to/data --tag mytag
- 使用主机名:
restic -r rclone:OneDrive:backup backup /path/to/data --host myhost
查看备份
要列出所有的备份快照,可以使用 restic snapshots
命令:
restic -r rclone:OneDrive:backup snapshots
查看特定快照的详细信息
可以查看某个特定快照的更详细信息,包括快照中包含的文件和目录结构。使用 restic ls
命令加上快照 ID 来实现:
restic -r rclone:OneDrive:backup ls <snapshot-id>
使用标签、主机名和时间过滤快照
- 按标签过滤:
restic -r rclone:OneDrive:backup snapshots --tag <tag-name>
- 按主机名过滤:
restic -r rclone:OneDrive:backup snapshots --host <host-name>
- 按时间过滤:
restic -r rclone:OneDrive:backup snapshots --last 24h
- 查看快照之间的差异:
Restic
还提供了一个强大的功能,允许比较两个快照之间的差异,看看在两次备份之间哪些文件被改变、添加或删除:
restic -r rclone:OneDrive:backup diff <snapshot-id1> <snapshot-id2>
Restic 仓库挂载为一个文件系统
restic mount
命令允许将 Restic 仓库挂载为一个文件系统,这样用户就可以使用标准的文件浏览器或命令行工具来访问备份数据。这是通过使用 FUSE (Filesystem in Userspace) 技术实现的,它允许创建一个用户空间的文件系统。
restic -r /path/to/repository mount /path/to/mountpoint
管理备份
随着时间的推移,备份快照可能会占用大量存储空间。使用 restic forget
命令可以删除不再需要的旧快照。结合 restic prune
命令,可以进一步清理未被任何快照引用的数据,释放存储空间。注意使用 --dry-run
选项进行模拟操作
# 删除快照列表信息
$ restic -r rclone:OneDrive:backup snapshots
$ restic -r rclone:OneDrive:backup forget 6eda7c7d
# 清除未引用的数据
# 快照中文件引用的数据仍然存储在存储库中
$ restic -r rclone:OneDrive:backup prune
restic -r rclone:OneDrive:backup forget --keep-last 10 --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --keep-yearly 3 --dry-run
这个命令会根据保留策略删除一些旧快照,例如,仅保留最近 10 个快照、每天一个快照保留 7 天等。
恢复快照
恢复备份快照是 Restic
最重要的功能之一。除了基本的恢复操作外,Restic
还提供了一些高级实用操作,使得从备份中恢复数据更加灵活和高效。
restic -r rclone:OneDrive:backup snapshots --time "2024-02-25"
# 只需使用以下命令就可以将最新快照的内容恢复
$ restic -r rclone:OneDrive:backup \
restore 79766175 --target /tmp/restore-work
恢复特定文件或目录
如果只需要从快照中恢复特定的文件或目录,而不是整个快照,可以使用 --include
或 --exclude
选项来指定恢复范围。
restic -r rclone:OneDrive:backup restore <snapshot-id> --target /path/to/restore --include "/path/to/file.txt"
restic -r rclone:OneDrive:backup restore <snapshot-id> --target /path/to/restore --include "/path/to/large_directory/" --exclude "/path/to/large_directory/exclude_this_subdir"
恢复备份时的安全检查
当使用 restic restore
命令恢复数据时,添加 --verify
选项将指示 Restic
在恢复每个文件后立即对其内容进行校验。这意味着 Restic
会比较文件的内容哈希值与仓库中记录的哈希值,以确保它们完全匹配。
restic -r rclone:OneDrive:backup restore <snapshot-id> --target /path/to/restore --verify
常见异常处理
锁定机制
Restic 使用锁定机制来确保备份仓库的数据一致性和完整性。在进行备份、恢复或维护操作时,Restic 会在备份仓库中创建一个特殊的锁文件。这个锁文件包含了操作的类型、开始时间以及操作者的信息。如果存在一个活动锁,Restic 会阻止其他可能会影响数据一致性的操作执行,直到该锁被释放。
- 独占锁: 用于备份和修剪操作,确保在这些操作执行期间,没有其他操作可以修改仓库数据。
- 共享锁: 允许多个读取操作同时进行,例如列出快照或检查仓库,但阻止写入操作。
在命令行中使用 Restic 时,锁定机制是自动管理的。用户不需要手动创建或释放锁。但是,如果操作被非正常终止(如进程崩溃或网络断开),可能会留下孤立的锁文件。Restic 提供了 unlock
命令来清理这些孤立的锁:
restic -r /path/to/repository unlock
实践结合 Restic 与 Rclone 自动备份及备份状态推送
步骤 1: 创建配置文件
创建一个配置文件 backup_config.conf
,在其中定义备份仓库、密码文件、备份路径、排除规则文件以及日志文件路径。例如放置于 /usr/local/bin/restic_backup
# backup_config.conf
# The repository location for restic backups. This is specified using the rclone backend syntax.
# Format: "rclone:<rclone remote name>:<path within the remote>"
RESTIC_REPOSITORY="rclone:OneDrive:backup"
# Path to the file containing the password for the restic repository.
# This file should be secured with appropriate permissions to prevent unauthorized access.
PASSWORD_FILE="/usr/local/bin/restic_backup/restic_password_file"
# File containing a list of paths to include in the backup. Each path should be on a separate line.
# File containing patterns to exclude from the backup. Each pattern should be on a separate line.
EXCLUDE_FILE="/usr/local/bin/restic_backup/exclude_rules.txt"
# Path to the log file where backup operation details will be recorded.
LOG_FILE="/var/log/restic_backup.log"
# A tag to assign to all snapshots created by this backup for easy identification and management.
BACKUP_TAG="automated_backup"
# The number of most recent snapshots to keep. Older snapshots exceeding this count will be pruned.
KEEP_SNAPSHOTS=5 # Number of snapshots to retain
# Rclone performance optimization settings
# The number of file transfers to run in parallel. Increasing this can improve transfer speeds,
# especially for a large number of small files, assuming the bandwidth allows for it.
# The default in rclone is 4 parallel transfers.
RCLONE_TRANSFERS=10
# The number of checkers to use. Checkers are used by rclone to determine if a file needs to be transferred.
# Increasing this number can speed up this checking process, which can be beneficial when dealing with
# a large number of files. This setting helps in speeding up the comparison between source and destination.
RCLONE_CHECKERS=20
# Telegram notification settings
# TELEGRAM_TOKEN: The API token of your Telegram bot. Leave this empty if you do not wish to send Telegram notifications.
# TELEGRAM_CHAT_ID: The chat ID where notifications will be sent. This can be a personal chat ID or a group chat ID.
# Leave these empty to disable Telegram notifications.
TELEGRAM_TOKEN="1111111223:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
TELEGRAM_CHAT_ID="123433545"
创建密码文件注意路径与 PASSWORD_FILE
参数对应
可适当修改RCLONE_TRANSFERS和RCLONE_CHECKERS参数可提高在备份大量小文件时的性能。
以及添加Telegram消息推送备份结果
步骤 2: 创建相关文件
创建密码文件:
echo "your_restic_password" > /usr/local/bin/restic_backup/restic_password_file
# 设置文件权限
chmod 600 /usr/local/bin/restic_backup/restic_password_file
创建备份路径文件:
/home
/root
创建排除规则文件:
创建一个排除规则文件 exclude_rules.txt
,在其中列出所有要排除的文件夹和文件类型。注意路径与 EXCLUDE_FILE
文件对应。
# exclude_rules.txt
/home/user/documents/temp
/home/user/photos/drafts
*.tmp
*.cache
# 排除所有以点开头的隐藏文件和文件夹
.*
# 但保留特定的文件,如 .zshrc
!.zshrc
步骤 3: 编写备份脚本及清理脚本
编写一个新的备份脚本 restic_backup.sh
,使用配置文件,实现日志记录以及错误处理和重试机制,并在脚本结束时提供备份摘要和推送备份结果。
#!/bin/bash
source /usr/local/bin/restic_backup/backup_config.conf
# Check for required commands
for cmd in restic curl hostname; do
if ! command -v $cmd &> /dev/null; then
echo "Error: Required command '$cmd' not found. Exiting."
exit 1
fi
done
export RCLONE_TRANSFERS=$RCLONE_TRANSFERS
export RCLONE_CHECKERS=$RCLONE_CHECKERS
backup_success=true
# Function to send Telegram notification
send_telegram() {
local message=$1
if [[ -z "$TELEGRAM_TOKEN" || -z "$TELEGRAM_CHAT_ID" ]]; then
echo "Telegram token or chat ID not set. Skipping notification."
return 1
fi
if ! curl -s -X POST https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage -d chat_id=$TELEGRAM_CHAT_ID -d text="$message" > /dev/null; then
echo "Warning: Failed to send Telegram notification."
fi
}
# Backup function with retry logic
backup() {
local retries=2
local delay=10 # Initial retry delay in seconds
local attempt=0
while [ $attempt -le $retries ]; do
local start_time=$(date +%s)
echo "Starting backup at $start_time, attempt $((attempt+1))" >> "$LOG_FILE"
if restic -r "$RESTIC_REPOSITORY" --password-file "$PASSWORD_FILE" backup --files-from "$FILES_FROM" --exclude-file="$EXCLUDE_FILE" --tag "$BACKUP_TAG" >> "$LOG_FILE" 2>&1; then
local end_time=$(date +%s)
echo "Backup completed successfully at $end_time. Duration: $((end_time - start_time)) seconds." >> "$LOG_FILE"
return 0
else
local end_time=$(date +%s)
echo "Backup failed, attempt $((attempt+1)) at $end_time. Check log $LOG_FILE for details." >> "$LOG_FILE"
attempt=$((attempt + 1))
sleep $delay
delay=$((delay * 2)) # Exponential backoff
fi
done
echo "Backup failed after $retries retries at $(date +%Y-%m-%d\ %H:%M:%S)." >> "$LOG_FILE"
backup_success=false
}
# Retrieve hostname and IP address
HOSTNAME=$(hostname)
IP_ADDRESS=$(curl -s ip.sb)
# Function to summarize backup operation and send Telegram notification
backup_summary() {
local end_time=$(date +"%Y-%m-%d %H:%M:%S")
if $backup_success; then
local stats_output=$(restic -r "$RESTIC_REPOSITORY" --password-file "$PASSWORD_FILE" stats | awk '/Stats in restore-size mode:/,0')
echo "All backups completed successfully at $end_time" >> "$LOG_FILE"
send_telegram "🎉 Backup completed successfully at $end_time 🎉
🖥️ Hostname: $HOSTNAME
🌐 IP Address: $IP_ADDRESS
💾 Repository: $RESTIC_REPOSITORY
🤖 Repository Stats:
$stats_output"
else
echo "One or more backups failed at $end_time, see log $LOG_FILE for details." >> "$LOG_FILE"
send_telegram "❌ Backup failed at $end_time ❌
🖥️ Hostname: $HOSTNAME
🌐 IP Address: $IP_ADDRESS
💾 Repository: $RESTIC_REPOSITORY
Check log $LOG_FILE for details."
fi
}
echo "Starting backup process at $(date +"%Y-%m-%d %H:%M:%S")" >> "$LOG_FILE"
backup
if ! $backup_success; then
echo "Performing detailed check due to previous failures..." >> "$LOG_FILE"
restic -r "$RESTIC_REPOSITORY" --password-file "$PASSWORD_FILE" check >> "$LOG_FILE" 2>&1
send_telegram "Restic repository check performed due to backup failure. Check log $LOG_FILE for details."
else
echo "Skipping detailed check as all backups were successful." >> "$LOG_FILE"
fi
backup_summary
赋予脚本执行权限:chmod +x /path/to/restic_backup.sh
。
编写清理快照脚本,具体要保留的快照数量可以在配置文件中自行修改,注意具有不同的路径或标签,它们被视为不同的备份集合,会单独计算保存的快照数量。
#!/bin/bash
source /usr/local/bin/restic_backup/backup_config.conf
HOSTNAME=$(hostname)
IP_ADDRESS=$(curl -s ip.sb)
send_telegram() {
local message=$1
if [[ -z "$TELEGRAM_TOKEN" || -z "$TELEGRAM_CHAT_ID" ]]; then
echo "Telegram token or chat ID not set. Skipping notification."
return 1
fi
if ! curl -s -X POST https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage -d chat_id=$TELEGRAM_CHAT_ID -d text="$message" > /dev/null; then
echo "Warning: Failed to send Telegram notification."
fi
}
cleanup_snapshots() {
echo "Starting cleanup process at $(date +"%Y-%m-%d %H:%M:%S")" >> "$LOG_FILE"
if restic -r "$RESTIC_REPOSITORY" --password-file "$PASSWORD_FILE" forget --keep-last "$KEEP_SNAPSHOTS" --prune 2>>"$LOG_FILE"; then
local stats_output=$(restic -r "$RESTIC_REPOSITORY" --password-file "$PASSWORD_FILE" stats | awk '/Stats in restore-size mode:/,0')
echo "Cleanup completed successfully at $(date +"%Y-%m-%d %H:%M:%S"). Kept the last $KEEP_SNAPSHOTS snapshots." >> "$LOG_FILE"
send_telegram "🧹 Cleanup completed successfully at $(date +"%Y-%m-%d %H:%M:%S").
🖥️ Hostname: $HOSTNAME
🌐 IP Address: $IP_ADDRESS
💾 Repository: $RESTIC_REPOSITORY
Kept the last $KEEP_SNAPSHOTS snapshots.
🤖 Repository Stats:
$stats_output"
else
echo "Cleanup failed at $(date +"%Y-%m-%d %H:%M:%S"), see log for details." >> "$LOG_FILE"
send_telegram "❌ Cleanup failed at $(date +"%Y-%m-%d %H:%M:%S").
🖥️ Hostname: $HOSTNAME
🌐 IP Address: $IP_ADDRESS
💾 Repository: $RESTIC_REPOSITORY
Check log $LOG_FILE for details."
fi
}
cleanup_snapshots
赋予脚本执行权限:chmod +x /path/to/restic_cleanup.sh
。
步骤 4: 配置定时任务
crontab -e
在编辑器中,添加一行以定义新的计划任务。以下是一些常见的时间设置示例:
# 每个月的第二天的凌晨 2 点 1 分执行
0 2 1 * * /bin/bash /path/to/your_backup_script.sh >> /path/to/backup_cron.log 2>&1
# 每3个月执行一次清理
0 2 1 */3 * /bin/bash /path/to/restic_cleanup.sh >> /path/to/cleanup_cron.log 2>&1
运行 crontab -l
来列出所有已经安排的 cron
作业,确保的备份任务已经被正确添加。