收起左侧

VaultWarden自动备份方案+邮件提醒(飞牛OS/Docker/阿里云OSS/Rclone)

0
回复
53
查看
[ 复制链接 ]

2

主题

2

回帖

0

牛值

江湖小虾

自己搭 VaultWarden 最怕两件事:
1)数据库/附件丢了;

2)备份任务跑没跑成功你根本不知道。

这篇分享一套我亲测可用的方案:

  • 本地先压缩备份(保留最近 7 份)
  • 自动上传阿里云 OSS(保留最近 30 份)
  • 无论成功失败都发邮件提醒(带完整日志)

环境:飞牛 FNOS / Docker / 阿里云 OSS / rclone / msmtp


目录

  • 一、安装 rclone(飞牛自带)
  • 二、rclone 配置对接阿里云 OSS(每一步选什么)
  • 三、验证 rclone 配置是否成功
  • 四、安装 msmtp(QQ 邮箱 SMTP 发信)
  • 五、备份 + 上传 + 邮件提醒脚本(最终版)
  • 六、定时任务/计划任务怎么跑
  • 七、常见坑

一、安装 rclone(飞牛自带)

飞牛系统源里一般直接有 rclone:

apt install rclone

二、配置 rclone 对接阿里云 OSS(每一步选什么)

1)进入交互配置

rclone config

2)新建 remote

看到选项:

  • n) New remote</span>
  • s) Set configuration password</span>
  • q) Quit config</span>

**输入:**n

3)remote 名称

提示:name>
输入:oss

4)选择存储类型 Storage

列表很长,这里选择:

  • 4 / s3(Amazon S3 兼容的,包含 Alibaba)

**输入:**4

5)选择 S3 provider

选择:

  • 2 / Alibaba(阿里云 OSS)

**输入:**2

6)是否从环境变量取 AK(env_auth)

提示:env_auth>

输入:1(等价于 false,表示下一步手动输入 AK/SK)

7)输入 AK / SK(RAM 子账号)

  • access_key_id>:填 RAM 子账号 AK
  • secret_access_key>:填 RAM 子账号 SK

RAM 权限建议给到 bucket 的读写删(备份上传/删除旧备份都要用)。

8)选择 endpoint(地域节点)

会列很多地域,比如北京是:

  • oss-cn-beijing.aliyuncs.com

这一步选择你 bucket 所在地域(北京就选 “North China 2 (Beijing)”)

**在列表里是:**6

注意:rclone 这里要填的是 Endpointoss-cn-beijing.aliyuncs.com),

image.png
不是 bucket 域名bucket-xxx.oss-cn-beijing.aliyuncs.com)。

9)acl(默认对象权限)

ACL 不是账户读写权限,它是对象公开/私有属性。备份建议私有:

选择:1 / private(默认)

**输入:**1

10)storage_class(存储类型)

**选:**2 / STANDARD

**输入:**2

11)Edit advanced config?

选:n(不编辑高级)

**输入:**n

12)确认保存

看到摘要后选:Yes this is OK

**输入:**y


三、验证 rclone 配置是否成功

1)列出 bucket

rclone lsd oss:

示例输出:

# rclone lsd oss: -1 2026-02-09 10:11:38 -1 [bucket名称]

2)列 bucket 内容

rclone lsf oss:[bucket名称]

3)上传测试文件

echo test > /tmp/oss_test.txt
rclone copy /tmp/oss_test.txt oss:[bucket名称]/vw-backups/ -P

4)删除测试文件

rclone deletefile oss:[bucket名称]/vw-backups/oss_test.txt

deletefile 只能删文件,不能删目录;

如果要清空整个前缀,用 rclone deleterclone purge


四、安装 msmtp(用 QQ 邮箱 SMTP 发提醒邮件)

1)安装

apt update
apt install -y msmtp msmtp-mta ca-certificates

安装时会问 Enable AppArmor support?

image.png

建议选:No

2)写配置(/etc/msmtprc)

[YOUR_QQ_AUTH_CODE] 12345@qq.com换成 QQ 邮箱 SMTP 授权码和你的邮箱账户(不加中括号)(不是登录密码):

cat >/etc/msmtprc <<'EOF'
defaults
auth           on
tls            on
tls_starttls   off
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile        /var/log/msmtp.log

account qq
host smtp.qq.com
port 465
from 12345@qq.com
user 12345@qq.com
password [YOUR_QQ_AUTH_CODE]

account default : qq
EOF

chmod 600 /etc/msmtprc

3)测试发邮件

echo -e "Subject: test\n\nhello" | msmtp -t 12345@qq.com

4)查看日志

tail -n 50 /var/log/msmtp.log

看到类似:

smtpstatus=250 ... exitcode=EX_OK

说明发信成功。


五、备份 + 上传 + 邮件提醒脚本

特点:

  • 停止 VaultWarden 容器保证一致性
  • 本地压缩包命名:VaultWarden-full-YYYY-MM-DD_HHMMSS.zip
  • 压缩包只保留一层目录 VaultWarden/…(不带 /vol1/1000 这种长路径)
  • 上传 OSS
  • 本地保留最近 7 份、OSS 保留最近 30 份
  • 无论成功/失败都发邮件,邮件里带完整日志

只改三个变量:MAIL_TOMAIL_FROMREMOTE_DIR

#!/usr/bin/env bash
set -euo pipefail

# ====== 邮件设置(必改) ======
MAIL_TO="666666@qq.com"      # 收件人
MAIL_FROM="12345@qq.com"    # 发件人:与 /etc/msmtprc from 一致
HOST_TAG="$(hostname)"
# ==============================

# ====== 备份设置 ======
SRC_DIR="/vol1/1000/SSD_Files/ProgramFiles/VaultWarden"  #(此处改你的容器数据路径)
LOCAL_DIR="/vol1/1000/SSD_Files/ProgramFiles/backups/vaultwarden"  #(此处改本地备份路径)
REMOTE_DIR="oss:[bucket名称]/vw-backups"
KEEP_LOCAL=7
KEEP_REMOTE=30
CONTAINER_NAME="vaultwarden"  # 改为你的容器名称
# =======================

TS="$(date +%F_%H%M%S)"
ZIP_NAME="VaultWarden-full-${TS}.zip"
ZIP_PATH="${LOCAL_DIR}/${ZIP_NAME}"

mkdir -p "${LOCAL_DIR}"

# 记录日志,邮件里会带上
LOG_FILE="$(mktemp /tmp/vw-backup-${TS}.XXXX.log)"
exec > >(tee -a "$LOG_FILE") 2>&1

START_AT="$(date '+%F %T')"
UPLOAD_OK="NO"

send_report_mail() {
  local status="$1"   # SUCCESS / FAILED
  local exit_code="$2"
  local end_at="$3"
  local local_cnt="$4"
  local oss_cnt="$5"

  local subject="[${status}] VaultWarden backup ${HOST_TAG} ${TS} (exit=${exit_code}, upload=${UPLOAD_OK})"

  {
    echo "From: ${MAIL_FROM}"
    echo "To: ${MAIL_TO}"
    echo "Subject: ${subject}"
    echo "Content-Type: text/plain; charset=UTF-8"
    echo
    echo "Status      : ${status}"
    echo "Host        : ${HOST_TAG}"
    echo "Start       : ${START_AT}"
    echo "End         : ${end_at}"
    echo "Exit code   : ${exit_code}"
    echo "Upload OK   : ${UPLOAD_OK}"
    echo "ZIP Path    : ${ZIP_PATH}"
    echo "Local Keep  : ${KEEP_LOCAL} (now ${local_cnt})"
    echo "OSS Keep    : ${KEEP_REMOTE} (now ${oss_cnt})"
    echo "Remote Dir  : ${REMOTE_DIR}/"
    echo
    echo "===== LOG BEGIN ====="
    cat "$LOG_FILE"
    echo "===== LOG END ====="
  } | msmtp -t || true
}

on_exit() {
  local exit_code=$?
  local end_at
  end_at="$(date '+%F %T')"

  # 不管成功失败,都尽量把容器拉起来
  docker start "$CONTAINER_NAME" >/dev/null 2>&1 || true

  local local_cnt oss_cnt
  local_cnt="$(ls -1 "${LOCAL_DIR}"/VaultWarden-full-*.zip 2>/dev/null | wc -l || true)"
  oss_cnt="$(rclone lsf "${REMOTE_DIR}" --include "VaultWarden-full-*.zip" 2>/dev/null | wc -l || true)"

  local status="SUCCESS"
  [ "$exit_code" -ne 0 ] && status="FAILED"

  send_report_mail "$status" "$exit_code" "$end_at" "$local_cnt" "$oss_cnt"

  rm -f "$LOG_FILE" || true
  exit "$exit_code"
}
trap on_exit EXIT
trap 'echo "[ERR] something failed, try start container..."; docker start "$CONTAINER_NAME" >/dev/null 2>&1 || true' ERR INT TERM

echo "[1/7] Stop container ${CONTAINER_NAME}..."
docker stop "${CONTAINER_NAME}"

echo "[2/7] Zip directory to local..."
PARENT_DIR="$(dirname "$SRC_DIR")"
BASE_DIR="$(basename "$SRC_DIR")"
( cd "$PARENT_DIR" && zip -9 -r -q "$ZIP_PATH" "$BASE_DIR" )

echo "[3/7] Start container ${CONTAINER_NAME}..."
docker start "${CONTAINER_NAME}"

echo "[4/7] Upload to OSS..."
rclone copy "${ZIP_PATH}" "${REMOTE_DIR}/" -P
UPLOAD_OK="YES"

echo "[5/7] Keep only latest ${KEEP_LOCAL} local backups..."
ls -1t "${LOCAL_DIR}"/VaultWarden-full-*.zip 2>/dev/null | tail -n +$((KEEP_LOCAL+1)) | xargs -r rm -f

echo "[6/7] Keep only latest ${KEEP_REMOTE} OSS backups..."
rclone lsf "${REMOTE_DIR}" --include "VaultWarden-full-*.zip" | sort | head -n -${KEEP_REMOTE} \
  | while read -r f; do
      [ -n "$f" ] && rclone deletefile "${REMOTE_DIR}/${f}"
    done

echo "[7/7] Done. Local: ${ZIP_PATH}"
echo "Local backups count: $(ls -1 "${LOCAL_DIR}"/VaultWarden-full-*.zip 2>/dev/null | wc -l)"
echo "OSS backups count: $(rclone lsf "${REMOTE_DIR}" --include "VaultWarden-full-*.zip" | wc -l)"

六、定时任务怎么跑(飞牛任务计划)

在飞牛 应用中心 安装【任务计划】软件新增一个定时任务,Cron 例如每天 03:00:

0 3 * * *

任务内容处->把上面的脚本粘进去保存即可。建议第一次手动点“运行”测试一遍。

运行结果示例:

image.png

image.png

[1/7] Stop container vaultwarden...
vaultwarden
[2/7] Zip directory to local...
[3/7] Start container vaultwarden...
vaultwarden
[4/7] Upload to OSS...
Transferred:   	    2.415 MiB / 2.415 MiB, 100%, 0 B/s, ETA -
Transferred:            0 / 1, 0%
Elapsed time:         0.5s
Transferring:
 *        VaultWarden-full-2026-02-10_113017.zip:100% /2.415Mi, 0/s, -Transferred:   	    2.415 MiB / 2.415 MiB, 100%, 0 B/s, ETA -
Transferred:            1 / 1, 100%
Elapsed time:         0.6s
[5/7] Keep only latest 7 local backups...
[6/7] Keep only latest 30 OSS backups...
[7/7] Done. Local: /vol1/1000/SSD_Files/ProgramFiles/backups/vaultwarden/VaultWarden-full-2026-02-10_113017.zip
Local backups count: 4
OSS backups count: 6

七、注意事项-(定期做恢复测试)

1)endpoint 填错:要填 oss-cn-xxx.aliyuncs.com,不是 bucket 域名。
2)ACL 不是读写权限
:备份建议 private;读写删权限靠 RAM 策略。

3)deletefile 不能删目录:只删对象;清空前缀用 delete/purge
4)QQ 邮箱要用授权码:不是登录密码.
5)脚本中断容器没起来:我脚本里用 trap 尽量自动拉起容器。


收藏
送赞
分享

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则