[b]背景:[/b]
买的小鸡部署了nextcloud网盘。想定时把另一台vps上数据备份到nextcloud。想法是:在 NextCloud 创建一个 File drop 分享,然后写一个打包上传脚本,就可以把它当备份服务器用啦。

[b]功能/特点:[/b]

分别备份多个源目录到 tar 文件并上传到 NextCloud share:使用 zstd 压缩(.tar.gz -> .tar.zst;tar czvf -> tar cavf);
每周上传完整备份,每天上传增量备份(利用 tar 增量备份);
只需要 NextCloud 的 File drop 链接,由于 File drop 只能用于上传,禁止列出/下载文件,脚本泄露不会造成其它数据的泄露。

[b]脚本[/b]

需要根据分享链接修改 BASEURL、SHARETOKEN 两个变量,代码中以 [url]https://example.com/s/AAAAAAA[/url] 为例。

以及需要修改 dobackups() 函数,可以调用多次 backup NAME PATH,每次调用会将 PATH 路径打包为 NAME_***.tar.zst 并上传到 File drop。

bash[copy]
#!/bin/bash

BEGIN OF USER CONFIG

BASEURL="https://example.com"
SHARETOKEN="AAAAAAA"

BASE_LISTPATH="/var/lib/backup"
BASE_TMPPATH="/tmp"
FULL_BACKUP_DAY="1" # 1 = Monday; 7 = Sunday

dobackups() {
backup YOUR_DATA_NAME_1 /PATH/TO/YOUR_DATA1
backup YOUR_DATA_NAME_2 /PATH/TO/YOUR_DATA2
}

END OF USER CONFIG

mkdir -p "$BASE_LISTPATH" "$BASE_TMPPATH"

declare -a success=()
declare -a failed=()

backup() {
local label="$1"
local listpath="$BASE_LISTPATH/${label}.snar"
local dirpath="$2"
echo "==> Creating backup '$label' from $dirpath"
if [[ $(date +%u) == $FULL_BACKUP_DAY ]]; then
rm "$listpath"
fi
[[ -f "$listpath" ]] ; full=$?
local packname="${label}_$(date +%Y%m%d_%H%M%S)_$([[ $full == "1" ]] && echo "full" || echo "incremental").tar.zst"
local packpath="$BASE_TMPPATH/$packname"
echo "==> tar file path '$packpath'"
local filecount=$(tar cavf "$packpath" -g "$listpath" "$dirpath" | wc -l)
echo $filecount files packed
if [[ $filecount == "0" ]] && [[ $full == "1" ]] ; then
failed+=("$label")
return 1
fi
echo "==> Uploading $packpath"
curl -T "$packpath" -u "$SHARETOKEN:" -H 'X-Requested-With: XMLHttpRequest' "$BASEURL/public.php/webdav/$packname" && success+=("$label") || failed+=("$label")
echo "==> Delete $packpath"
rm "$packpath"
}

dobackups

echo SUCEESS: ${success[@]}

if [[ ${#failed[@]} -gt 0 ]]; then
echo FAILED: ${failed[@]}
exit 1
fi

[b]Systemd 配置[/b]

为了让脚本定时启动,给 systemd 增加一个 service 和一个 timer。

文件 /etc/systemd/system/simplebackup.service:

[copy]
[Unit]
Wants=simplebackup.timer

[Service]
Type=simple
ExecStart=/etc/backup.sh

[Install]

(假设脚本位于 /etc/backup.sh)

文件 /etc/systemd/system/simplebackup.timer:

[copy]
[Unit]
Requires=simplebackup.service

[Timer]
Unit=mybackup.service
OnCalendar=--* 3:00:00

[Install]
WantedBy=timers.target

(每天凌晨 3 时运行)

[b]启用 timer:[/b]

[copy]
sudo systemctl enable --now simplebackup.timer

作为测试,手动运行一次 service:

[copy]
sudo systemctl start simplebackup.service