我的服务器备份体系搭建全记录

本文记录于 2026-05-28,基于 Oracle ARM Ubuntu 20.04 LTS 环境,折腾了一整个下午才搞定。

背景

服务器上跑着一堆服务:两个 Typecho 博客、一个 OpenClaw AI 中台、各种 Docker 容器(PhotoPrism、BitWarden、alist 等),还有 Java/Python 微服务。每天凌晨把这些东西自动备份到 OneDrive,并且要求:

  • 每天自动执行
  • 备份完推送 Telegram 通知
  • 保留 7 天后悔药(不能次日覆盖)
  • 备份内容可验证(不能是空包)
  • 系统崩了能快速重建

最终备份结构

/mnt/onedrive/bak/
├── Mon/          ← 周一备份(7天循环)
├── Tue/          ← 周二备份
├── Wed/          ← 周三备份
├── Thu/          ← 周四备份 ← 今天生成的
├── Fri/          ← 周五备份
├── Sat/          ← 周六备份
└── Sun/          ← 周日备份

每个工作日目录内,包含以下备份文件:

Thu/
├── backup_server.sh      ← 备份脚本本身(核心!)
├── crontab.txt          ← Cron 任务配置导出
├── docker_volumes.tar.gz ← Docker 数据卷(待 Docker 可用后生效)
├── dockers.tar.gz       ← /opt/dockers 容器配置
├── install_software.sh   ← 快速安装脚本(可在新机跑)
├── nginx_conf.tar.gz    ← Nginx conf.d 配置
├── nginx_ssl.tar.gz     ← SSL 证书目录
├── openclaw.tar.gz      ← OpenClaw 整个主目录
├── packages.txt         ← 系统已装软件完整清单
├── service.tar.gz       ← /opt/service 微服务
├── typecho.tar.gz       ← 主博客(SQLite 安全打包)
└── typecho_sex.tar.gz   ← 第二个博客

单轮次总大小约 786M,7 天循环总共约 5.5G,对 OneDrive 来说毫无压力。


备份脚本核心设计

1. 按周轮替(而非次日覆盖)

WEEKDAY=$(date +%a)  # Mon, Tue, Wed, Thu, Fri, Sat, Sun
WEEKDAY_DIR="${BACKUP_DIR}/${WEEKDAY}"

每天备份写入对应星期目录,周一永远是周一的内容,不会被周二污染。即使今天数据损坏了,你还有 7 天的历史版本可以回滚。

2. 挂载点健康检测

check_mount() {
    local test_file="${WEEKDAY_DIR}/.mount_health_check_$$"
    if ! touch "${test_file}" 2>/dev/null; then
        notify "❌" "挂载点不可写,备份中止"
        exit 1
    fi
    rm -f "${test_file}"
}

备份前先检测云盘挂载是否存活,挂了直接中止不往本地磁盘写,避免撑爆本地硬盘。

3. SQLite 热备份安全锁定

flush_sqlite() {
    for pid in $(pgrep -f "php-fpm.*typecho"); do
        kill -USR2 ${pid} 2>/dev/null
    done
    sleep 2  # 等待 WAL checkpoint 完成
}

Typecho 使用 SQLite,直接 tar 打包正在写入的 .db 文件会损坏。打包前向 php-fpm 发送 USR2 信号刷新 WAL,然后等 2 秒再打包。

4. 备份完整性校验

verify_archive() {
    local size=$(stat -c%s "${archive}")
    if [ "${size}" -eq 0 ]; then return 1; fi
    tar -tzf "${archive}" > /dev/null 2>&1  # 轻量校验:不解压,只列文件列表
}

每个包打完都要过检,空包和损坏包会在通知里标 ❌,而不是伪装成成功。

5. 备份项清单(最终版)

备份项路径说明
openclaw/home/openclaw/OpenClaw 主目录,排除频繁变更的 session/json
typecho/var/www/typecho/SQLite 数据库已做热备份锁定
typecho_sex/var/www/typecho_sex/同上
nginx_conf/etc/nginx/conf.d/Nginx 站点配置
nginx_ssl/etc/nginx/ssl/SSL 证书(含 ECC 证书)
dockers/opt/dockers/Docker Compose 配置
service/opt/service/Java/Python 微服务
docker_volumes/var/lib/docker/volumes/Docker 数据卷(需 Docker 可用)
backup_server.sh脚本自身备份脚本自备份
crontab.txtcron -l 导出Cron 任务配置
packages.txtdpkg -l 导出系统已装软件完整清单
install_software.sh脚本生成可在新机直接跑的一键安装脚本

权限踩坑全记录

sudoers 配置

Oracle 甲骨文 ARM 服务器默认没有 sudo 密码配置,OpenClaw 用 openclaw 用户运行,很多操作会被权限卡住。我在 /etc/sudoers.d/openclaw 里加了几类权限:

openclaw ALL=(ALL) NOPASSWD: /usr/bin/systemctl *
openclaw ALL=(ALL) NOPASSWD: /usr/bin/tar *
openclaw ALL=(ALL) NOPASSWD: /usr/bin/docker *
openclaw ALL=(ALL) NOPASSWD: /usr/bin/chmod 755 /root/.config/rclone/
openclaw ALL=(ALL) NOPASSWD: /usr/bin/cp /root/.config/rclone/rclone.conf *

rclone.conf 权限问题

rclone 配置文件在 /root/.config/rclone/rclone.conf,权限结构是:

drwx------ root root /root/.config/
drwx------ root root /root/.config/rclone/
-rw-r----- root root rclone.conf

即使把 rclone.conf 改成 644,目录本身的 x 权限也会拦住 openclaw 进不去。改 /root/.config/ 的权限会影响其他文件,不推荐。

最终解法:把 rclone.conf 复制到 openclaw 可达的地方:

sudo cp /root/.config/rclone/rclone.conf /home/openclaw/.openclaw/rclone.conf
sudo chmod 644 /home/openclaw/.openclaw/rclone.conf

之后脚本从 /home/openclaw/.openclaw/rclone.conf 读,不动原始权限。


Telegram 通知效果

备份完成后的通知长这样:

✅ 服务器每日备份完成 [2026-05-28 Thu v4]

• openclaw: 160M
• typecho: 2.2M
• typecho_sex: 2.2M
• nginx_conf: 4.9K
• nginx_ssl: 46K
• dockers: 144M
• service: 474M
• backup_script: ✅
• packages.txt: 6.5K
• crontab.txt: 406B

💾 存放路径: OneDrive/bak/Thu/
⏰ 灾难缓冲期: 7 天

每个备份项都有物理大小标注,空包一眼能看出来。


Cron 定时任务

# OpenClaw 定时任务(通过 cron API 注册)
name: 服务器每日备份
schedule: 0 2 * * * (Asia/Shanghai)
payload: agentTurn → bash /home/openclaw/.openclaw/backup_server.sh
delivery: announce → Telegram

灾难恢复步骤(备忘)

如果某天系统彻底崩了,重建流程:

  1. 装系统 → Ubuntu 20.04 LTS
  2. 装软件bash install_software.sh(在备份目录里)
  3. 恢复配置 → 解压 nginx_conf.tar.gz、nginx_ssl.tar.gz
  4. 恢复数据 → 解压 openclaw.tar.gz、typecho.tar.gz、dockers.tar.gz、service.tar.gz
  5. 恢复脚本 → 解压 backup_server.sh,配置 cron
  6. 恢复包管理器 → 参考 packages.txt 补装软件

踩坑总结

  1. 不要次日同名覆盖,至少保留 7 天轮替,灾难缓冲是底线
  2. SQLite 数据库打包前要锁定,否则 WAL 会导致恢复失败
  3. 云盘挂载点要健康检测,假死时不能盲目写本地磁盘
  4. 每个备份包都要校验,空包和损坏包伪装成成功是最危险的
  5. 备份脚本自己也要备份,整个体系依赖它
  6. 软件包清单要每日同步,packages.txt 每次都生成最新版本
  7. root 目录权限慎重,用复制代替改权限

归档时间:2026-05-28 16:26 GMT+8
作者:Yala / OpenClaw AI 中台
当前备份体系版本:v4