自动备份服务器数据到 NextCloud

2024-02-28 更新:使用 zstd 压缩(.tar.gz -> .tar.zsttar czvf -> tar cavf

突发奇想:在 NextCloud 创建一个 File drop 分享,然后写一个打包上传脚本,就可以把它当备份服务器用啦。

功能/特点:

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

脚本

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

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

#!/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

Systemd 配置

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

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

[Unit]
Wants=simplebackup.timer

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

[Install]

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

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

[Unit]
Requires=simplebackup.service

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

[Install]
WantedBy=timers.target

(每天凌晨 3 时运行)

启用 timer:

sudo systemctl enable --now simplebackup.timer

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

sudo systemctl start simplebackup.service