构建 VPS → OP8P → WRT 三级联动数据备份自动化方案
2025年12月30日 · 1024 字 · 3 分钟
为了确保数据的安全性和多地冗余,我构建了一套跨服务器的联动备份系统。这套系统将云端服务数据、本地生产数据进行多级汇总,最终统一存储到备灾设备中。
1. 备份架构设计
整个系统由三部分组成,通过 rsync 进行数据流转:
- VPS (源端):主要运行 Docker 服务,承载公网业务。
- OP8P (汇总端):本地核心服务器,运行本地 Docker 服务,同时拉取 VPS 数据进行第一级汇总。
- WRT (备份端):最终的存储设备,挂载大容量硬盘,接收来自 OP8P 的全量数据汇总。
2. 核心备份脚本 (/home/ban/sync.sh)
该脚本部署在 OP8P 上,作为整个流程的控制中心。它具备预检查机制,并能通过钉钉机器人实时反馈备份状态。
脚本实现逻辑
#!/bin/bash
# --- 配置区 ---
RSYNC_BIN="/usr/bin/rsync"
VPS_HOST="vps"
WRT_HOST="wrt"
LOCAL_DOCKER_DIR="/home/ban/Docker"
TOKEN="${ding_token}"
# --- 函数定义:钉钉推送 ---
send_dingtalk() {
local msg="[HA] $1"
/usr/bin/curl -s "https://oapi.dingtalk.com/robot/send?access_token=${TOKEN}" \
-H 'Content-Type: application/json' \
-d "{\"msgtype\": \"text\",\"text\": {\"content\":\"$msg\"}}" > /dev/null
}
# --- 函数定义:错误处理 ---
error_exit() {
local err_msg="备份失败: $1"
echo -e "\033[31m[ERROR] $err_msg\033[0m" >&2
send_dingtalk "$err_msg (时间: $(date '+%Y-%m-%d %H:%M:%S'))"
exit 1
}
# --- 任务开始 ---
echo "--- 正在进行预检查 ---"
# 发送开始通知(可选)
# send_dingtalk "数据备份任务开始执行..."
# 1. 检查必要工具和目录
[ ! -x "$RSYNC_BIN" ] && error_exit "找不到 rsync"
[ ! -d "$LOCAL_DOCKER_DIR" ] && error_exit "本地目录 $LOCAL_DOCKER_DIR 不存在"
# 2. 检查网络连通性
for HOST in "$VPS_HOST" "$WRT_HOST"; do
if ! /usr/bin/ssh -o ConnectTimeout=5 -o BatchMode=yes "$HOST" exit 2>/dev/null; then
error_exit "无法连接主机: $HOST"
fi
done
# --- 第一阶段:VPS -> OP8P ---
echo -e "\n>>> Phase 1: VPS -> OP8P"
$RSYNC_BIN -avz \
--exclude 'blog' \
--exclude '.*' \
--exclude 'ttrss/postgres' \
--exclude 'virt-sysprep-firstboot.log' \
"$VPS_HOST":/root/ "$LOCAL_DOCKER_DIR/" || error_exit "VPS -> OP8P 同步出错"
# --- 第二阶段:OP8P -> WRT ---
echo -e "\n>>> Phase 2: OP8P -> WRT"
# 2-1. 同步 Docker 核心文件
$RSYNC_BIN -avz \
--exclude 'photoprism/database' \
--exclude 'photoprism/storage' \
--exclude 'gitlab/config' \
--exclude 'gitlab/logs' \
--exclude 'gitlab/data' \
--exclude 'homeassistant/config' \
"$LOCAL_DOCKER_DIR/" "$WRT_HOST":/opt/Docker/ || error_exit "Docker 核心文件同步出错"
# 2-2. 独立同步 HA Backups
$RSYNC_BIN -avz "$LOCAL_DOCKER_DIR/homeassistant/config/backups/" "$WRT_HOST":/opt/Docker/homeassistant/config/backups/ || error_exit "HA Backups 同步出错"
# 2-3. 资料库循环同步
TASKS=(
"/home/ban/Pictures/:/opt/Pictures/"
"/home/ban/Documents/:/opt/Documents/"
"/home/ban/Music/:/opt/Music/"
"/home/ban/script/:/opt/script/"
)
for TASK in "${TASKS[@]}"; do
SOURCE="${TASK%%:*}"
DEST_PATH="${TASK##*:}"
DEST="$WRT_HOST:$DEST_PATH"
if [ -d "$SOURCE" ]; then
$RSYNC_BIN -av "$SOURCE" "$DEST" || error_exit "资料同步出错: $SOURCE"
fi
done
# --- 任务完成 ---
FINISH_TIME=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "\n✅ 所有任务完成!"
send_dingtalk "数据备份成功完成。 (时间: $FINISH_TIME)"
3. 部署与自动化
SSH 免密配置
为了让脚本在无人值守下运行,需要在 OP8P 上生成 SSH 密钥并分发到 VPS 和 WRT:
ssh-copy-id vps
ssh-copy-id wrt
Crontab 定时任务
使用 crontab -e 配置每天凌晨自动执行。特别注意在配置中显式定义变量,确保 cron 能够正确调用钉钉 API:
0 3 * * * export ding_token=xxxxxx; /bin/bash /home/ban/sync.sh >> /home/ban/sync.log 2>&1
4. 方案优势
- 汇总式备份:OP8P 作为中心节点,将云端和本地数据合二为一,简化了最终备份端的同步逻辑。
- 异常拦截:通过
error_exit机制,任何一步同步出错都会立即触发钉钉告警,避免出现“备份已死却无人知晓”的情况。 - 灵活扩展:通过
TASKS数组可以轻松添加新的同步目录,无需修改核心逻辑。
通过这套方案,我实现了从公网到内网、从服务到资料的全自动化备份闭环。