restic + rclone 实现 vps 备份

本文最后更新于 2025年9月15日 晚上

每到考试周,就会忍不住折腾,所以今天随便谢谢 vps 备份方案

vps 备份主要是两种,一种是依靠服务器提供商自带的快照和备份;另一种就是自己折腾放到云盘上。

前者不一定所有厂商都有,而且不一定免费;后者更具有折腾性,但往往只能选择备份部分重要数据。

这里采用后者方法,具体使用 restic + rclone 来备份(rclone 主要是用于读写 Google Drive,而 restic 是备份工具)。

原因

我的备份需求:

  1. 备份分散在各处的配置文件:.vimrc, .bashrc, nginx 配置文件等。
  2. 备份 ~/documents 以及 docker 相关文件

一个涉及分散文件的备份,一个涉及大型文件的备份。

如果单独采用 rclone,那么两个需求都不好实现:

  1. rclone 需要运行多次来满足第一个需求,不能从文件中读取所有需要备份的文件。
  2. rclone 本质是文件同步,尽管有增量功能和每个文件很小,但在有大量文件的情况下,表现极差

而 restic 很好能解决这两个问题并且有额外好处:

  1. restic 能从文件中读取需要备份的路径
  2. restic 会将小文件(当然,大文件也是)合并打包到 pack 文件中,再传输
  3. restic 会进行文件压缩,文件大小也会更小
  4. restic 支持版本控制,它是有快照概念的
  5. restic 的备份是加密的,即使是共享云端存储空间,别人也不会知道内容(当然,即使这样也不推荐)
  6. restic 是多平台的,Windows 也能使用

目标

通过利用 rclone 挂载存储(包括 onedrive, google drive, webdav 等),让 restic 定时备份到指定存储中,同时为了存储大小考虑,定时删除过期快照,提供备份失败邮箱提醒

步骤

  1. 下载 rclone

    1
    sudo -v ; curl https://rclone.org/install.sh | sudo bash
  2. 配置 rclone 后端

    如果已有 rclone 配置文件,可以直接复制使用

    类 Unix 系统的 rclone 配置文件位于 ~/.config/rclone/rclone.conf。路径与 home 有关,所以不同用户会有不同配置,使用硬链接可以共享配置

    Windows 系统的 rclone 配置文件位于 %APPDATA%\rclone\rclone.conf

    如果没有,使用 rclone config 命令来引导添加配置

  3. 下载 restic

    1
    2
    sudo apt update
    sudo apt install restic
  4. restic 初始化以及备份

    1
    2
    restic -r rclone:remote:backup init
    restic -r rclone:remote:backup backup -v --files-from /opt/backup/backup_files
  5. 定时删除

    保留最后 3 天(每天一份),最后 5 周(每周一份)。

    1
    restic -r rclone:remote:backup forget --keep-daily 3 --keep-weekly 5 --prune
  6. 自动任务

    编辑脚本:

    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

      参考

      1. 配置邮件

        msmtp

        安装 msmtpsudo 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
      2. 配置邮件 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
      3. 配置 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
      4. 加载配置

        1
        2
        systemctl daemon-reload
        systemctl enable backup.timer
      5. 调试

        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 和密码。

  • remove files from snapshots

  • 查看所有快照: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。

参考链接

rclone

restic

附录

restic profile

restic on password


restic + rclone 实现 vps 备份
https://lllei.top/2023/12/28/restic + rclone vps 备份/
作者
Lei
发布于
2023年12月28日
更新于
2025年9月15日
许可协议