本文主要讲述在使用宝塔面板的Linux服务器中使用Reclone搭配宝塔面板的定日任务功能实现网站目录的增量备份以及历史版本(以OneDrive为例)
- 本地操作系统:Windows 11
- 服务器操作系统:Debian 12
- 宝塔面板版本:v11.5.0
- 备份目标网盘:OneDrive (Microsoft 365 E5)
一、准备工作
如果你还没有安装宝塔面板,先前往宝塔官网安装宝塔面板,或直接执行下面的通用命令进行安装(此命令为宝塔官方提供的邀请安装命令,请放心使用)
【宝塔开年福利,使用此命令安装宝塔,可免费领取企业版和专业版】
if [ -f /usr/bin/curl ];then curl -sSO https://dg2.bt.cn/py.sh;else wget -O py.sh https://dg2.bt.cn/py.sh;fi;bash py.sh ZOQZM3
同时,你还需要在Linux服务器上安装Reclone,并下载Windows或Mac版的Reclone(必须同时准备好)为后续操作做好准备
Linux Reclone安装指令如下(如果您的服务器是在中国大陆,可能需要等待较长的时间)
curl https://rclone.org/install.sh | sudo bash
当终端显示以下内容时代表安装完成,此时可以进行下一步
rclone v1.xx.x has successfully installed.
二、配置授权
由于 Linux 服务器没有浏览器,无法直接弹出微软登录页面。我们需要采用“服务器发起 -> 电脑授权 -> 回填令牌”的方式。
1.在服务器发起配置
1)请在终端输入:
rclone config
2)创建新配置文件,输入 n
3)配置文件名,任意即可,但是需要记住。本教程在这里使用 onedrive
4)找到 Microsoft OneDrive 对应的数字(Microsoft Onedrive是 41,但是版本不同,代号可能会不同,所以在操作前请注意检查)
5)client_id> 直接 回车 (留空)
6)client_secret> 直接 回车 (留空)
7)此时,Reclone会让你选择你的OneDrive版本,如图

对于中国的用户,无论是个人账户,还是企业或E5账户,都应该选择第一个选项 Microsoft Cloud Global
除非你明确的知道你使用的是世纪互联代理的OneDrive,此时,你应当选择第四个
8)然后你会看到如下图的服务主体询问

对于大部分人来说,这个设置项都是用不到的,我们只需要按 回车 跳过
9)Edit advanced config? 输入 n (不编辑高级选项)
10)然后Reclone会进行一个是否有浏览器的询问,由于大部分的Linux服务器都没有GUI,所以无法使用浏览器,此时我们需要输入 n ,使用本地电脑辅助授权

2.使用本地电脑辅助授权
此时来到本地电脑,解压缩下载到的文件并进入该文件夹,在地址栏中输入 cmd 直接打开命令提示符或终端
1)在打开的终端中执行命令,随后在自动打开的网页中登录目标网盘的账号,直到你看到如下页面
.\rclone.exe authorize "onedrive"

2)此时回到终端,复制返回的accesskey,格式如下
{"access_token":"eyJ0eXAB……4iuj8w","token_type":"……","refresh_token":"1.AVYAQv……obp0ySN0","expiry":"……","expires_in":……}
3.回填令牌到服务器
1)将获取到的accesskey填入,随后会让你选择账号类型,如图所示。一般情况下选择第一种,除非你明确的知道你的账号属于其他的六类

2)随后会询问你选择哪个网盘,一般情况下只有一个(如下图),我们直接选择就好了

3)确认网盘路径 Found drive ... Is that okay? 输入 y
4)保存配置 Keep this "onedrive" remote? 输入 y
5)退出配置 在Current remotes: 看到 onedrive 后,输入 q 退出。
三、验证连接
在终端输入以下命令,如果能列出您网盘里的文件夹,说明连接成功:
rclone lsd onedrive:
提示: 这里的
onedrive:后面必须带冒号。
四、配置备份
此时打开我们安装好的宝塔面板,然后点击侧边栏的计划任务,选择添加 Shell 脚本,设置好自动任务的时间,在脚本内容输入框中输入备份脚本(例子在下面)
五、备份脚本
本博客提供三种备份脚本,分别为适用于所有网站的基础版以及根据DiscuzX和WoedPress深度优化的定制版,你只需要修改两处:SITE_NAME 和 REMOTE_NAME
基础版
#!/bin/bash
# ================= 配置区域 =================
# 1. 你的网站根目录
SITE_NAME="你的网站文件夹"
SOURCE_DIR="/www/wwwroot/${SITE_NAME}"
# 2. 基础配置
REMOTE_NAME="你的Reclone配置文件"
BASE_PATH="${REMOTE_NAME}:/Backup/${SITE_NAME}"
DEST_DIR="${BASE_PATH}/Current"
LOG_BASE_DIR="/www/server/panel/logs/sitebackup/${SITE_NAME}"
mkdir -p $LOG_BASE_DIR
# 3. 自动化流水号
DATE_STR=$(date +%Y%m%d)
COUNTER=1
while [ -f "${LOG_BASE_DIR}/${DATE_STR}$(printf "%03d" $COUNTER).log" ]; do let COUNTER++; done
SERIAL_NO="${DATE_STR}$(printf "%03d" $COUNTER)"
FULL_LOG_PATH="${LOG_BASE_DIR}/${SERIAL_NO}.log"
BACKUP_DIR="${BASE_PATH}/History/${SERIAL_NO}"
# ================= 执行区域 =================
echo "------------------------------------------------"
echo "▶ 任务流水号: $SERIAL_NO"
echo "▶ 启动时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "▶ 正在执行 ${SITE_NAME} 增量备份..."
# 排除规则
rclone sync "$SOURCE_DIR" "$DEST_DIR" \
--backup-dir "$BACKUP_DIR" \
--transfers 8 \
--checkers 12 \
--buffer-size 32M \
--ignore-errors \
--log-file="$FULL_LOG_PATH" \
--log-level INFO \
--exclude ".git/**"
RCLONE_EXIT_CODE=$?
# ================= 统计区域 =================
sleep 1
echo ""
echo "==== 备份执行总结 (Summary) ===="
if [ -f "$FULL_LOG_PATH" ]; then
grep "Transferred:" "$FULL_LOG_PATH" | tail -n 1 | sed 's/.*INFO : //'
grep "Checks:" "$FULL_LOG_PATH" | tail -n 1 | sed 's/.*INFO : //'
grep "Elapsed time:" "$FULL_LOG_PATH" | tail -n 1 | sed 's/.*INFO : //'
fi
if [ $RCLONE_EXIT_CODE -eq 0 ]; then
echo "------------------------------------------------"
echo "✅ 备份成功!"
echo "▶ 最新镜像: ${DEST_DIR}"
echo "▶ 历史归档: ${BACKUP_DIR}"
else
echo "------------------------------------------------"
echo "❌ 备份存在异常,请查看日志: ${LOG_BASE_DIR}"
fi
WordPress优化版
#!/bin/bash
# ================= 配置区域 =================
# 1. 你的 WordPress 网站根目录
SITE_NAME="你的Reclone配置文件"
SOURCE_DIR="/www/wwwroot/${SITE_NAME}"
# 2. 基础配置
REMOTE_NAME="你的Reclone配置文件"
BASE_PATH="${REMOTE_NAME}:/Backup/${SITE_NAME}"
DEST_DIR="${BASE_PATH}/Current"
LOG_BASE_DIR="/www/server/panel/logs/sitebackup/${SITE_NAME}"
mkdir -p $LOG_BASE_DIR
# 3. 自动化流水号
DATE_STR=$(date +%Y%m%d)
COUNTER=1
while [ -f "${LOG_BASE_DIR}/${DATE_STR}$(printf "%03d" $COUNTER).log" ]; do let COUNTER++; done
SERIAL_NO="${DATE_STR}$(printf "%03d" $COUNTER)"
FULL_LOG_PATH="${LOG_BASE_DIR}/${SERIAL_NO}.log"
BACKUP_DIR="${BASE_PATH}/History/${SERIAL_NO}"
# ================= 执行区域 =================
echo "------------------------------------------------"
echo "▶ 任务流水号: $SERIAL_NO"
echo "▶ 启动时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "▶ 正在执行 ${SITE_NAME} 增量备份..."
# WordPress 专用排除规则
rclone sync "$SOURCE_DIR" "$DEST_DIR" \
--backup-dir "$BACKUP_DIR" \
--transfers 8 \
--checkers 12 \
--buffer-size 32M \
--ignore-errors \
--log-file="$FULL_LOG_PATH" \
--log-level INFO \
--exclude "/wp-content/cache/**" \
--exclude "/wp-content/upgrade/**" \
--exclude "/wp-content/backups/**" \
--exclude "/wp-content/debug.log" \
--exclude "/node_modules/**" \
--exclude ".git/**"
RCLONE_EXIT_CODE=$?
# ================= 统计区域 =================
sleep 1
echo ""
echo "==== 备份执行总结 (Summary) ===="
if [ -f "$FULL_LOG_PATH" ]; then
grep "Transferred:" "$FULL_LOG_PATH" | tail -n 1 | sed 's/.*INFO : //'
grep "Checks:" "$FULL_LOG_PATH" | tail -n 1 | sed 's/.*INFO : //'
grep "Elapsed time:" "$FULL_LOG_PATH" | tail -n 1 | sed 's/.*INFO : //'
fi
if [ $RCLONE_EXIT_CODE -eq 0 ]; then
echo "------------------------------------------------"
echo "✅ 备份成功!"
echo "▶ 最新镜像: ${DEST_DIR}"
echo "▶ 历史归档: ${BACKUP_DIR}"
else
echo "------------------------------------------------"
echo "❌ 备份存在异常,请查看日志: ${LOG_BASE_DIR}"
fi
DiscuzX优化版
#!/bin/bash
# ================= 配置区域 =================
# 1. 你的 DiscuzX 网站根目录
SITE_NAME="你的网站文件夹"
SOURCE_DIR="/www/wwwroot/${SITE_NAME}"
# 2. 基础配置
REMOTE_NAME="你的Reclone配置文件"
BASE_PATH="${REMOTE_NAME}:/Backup/${SITE_NAME}"
DEST_DIR="${BASE_PATH}/Current"
LOG_BASE_DIR="/www/server/panel/logs/sitebackup/${SITE_NAME}"
mkdir -p $LOG_BASE_DIR
# 3. 自动化流水号
DATE_STR=$(date +%Y%m%d)
COUNTER=1
while [ -f "${LOG_BASE_DIR}/${DATE_STR}$(printf "%03d" $COUNTER).log" ]; do let COUNTER++; done
SERIAL_NO="${DATE_STR}$(printf "%03d" $COUNTER)"
FULL_LOG_PATH="${LOG_BASE_DIR}/${SERIAL_NO}.log"
BACKUP_DIR="${BASE_PATH}/History/${SERIAL_NO}"
# ================= 执行区域 =================
echo "------------------------------------------------"
echo "▶ 任务流水号: $SERIAL_NO"
echo "▶ 启动时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "▶ 正在执行 ${SITE_NAME} 增量备份..."
# DiscuzX 专用排除规则
rclone sync "$SOURCE_DIR" "$DEST_DIR" \
--backup-dir "$BACKUP_DIR" \
--transfers 8 \
--checkers 12 \
--buffer-size 32M \
--ignore-errors \
--log-file="$FULL_LOG_PATH" \
--log-level INFO \
--exclude "/data/cache/**" \
--exclude "/data/template/**" \
--exclude "/data/threadcache/**" \
--exclude "/data/log/**" \
--exclude "/data/sysdata/**" \
--exclude "/data/download/**" \
--exclude "/data/attachment/temp/**" \
--exclude "/data/attachment/image/**" \
--exclude "/uc_server/data/cache/**" \
--exclude "/uc_server/data/logs/**" \
--exclude ".git/**"
RCLONE_EXIT_CODE=$?
# ================= 统计区域 =================
sleep 1
echo ""
echo "==== 备份执行总结 (Summary) ===="
if [ -f "$FULL_LOG_PATH" ]; then
grep "Transferred:" "$FULL_LOG_PATH" | tail -n 1 | sed 's/.*INFO : //'
grep "Checks:" "$FULL_LOG_PATH" | tail -n 1 | sed 's/.*INFO : //'
grep "Elapsed time:" "$FULL_LOG_PATH" | tail -n 1 | sed 's/.*INFO : //'
fi
if [ $RCLONE_EXIT_CODE -eq 0 ]; then
echo "------------------------------------------------"
echo "✅ 备份成功!"
echo "▶ 最新镜像: ${DEST_DIR}"
echo "▶ 历史归档: ${BACKUP_DIR}"
else
echo "------------------------------------------------"
echo "❌ 备份存在异常,请查看日志: ${LOG_BASE_DIR}"
fi
六、常见问题与报错
以下是我在部署期间遇到的问题,我让AI帮我整理了一下,希望可以对你有所帮助
如果你在配置过程中遇到其他问题,欢迎在评论区留言交流!
1. 安装时提示 Operation not permitted
现象:
在终端执行 curl https://rclone.org/install.sh | sudo bash 时,提示无法在 /usr/bin/ 创建文件,即使是 root 用户也不行。
原因:
宝塔面板的系统加固或文件锁机制锁定了关键系统目录。
解决方案:
需要先解锁目录,安装完后再(可选)锁回去:codeBash
# 解锁目录
chattr -i /usr/bin/rclone
chattr -i /usr/bin
# 再次执行安装命令
curl https://rclone.org/install.sh | sudo bash
2. 报错 destination and parameter to --backup-dir mustn't overlap
现象:
脚本运行失败,日志提示目标目录和备份目录不能重叠。
原因:
这是 Rclone 的安全机制。例如,你的目标目录是 /Backup,而历史版本目录设置为了 /Backup/History。Rclone 认为历史目录包含在目标目录里,会导致无限循环备份。
解决方案:
采用平级结构,不要用包含结构。
- ❌ 错误结构:Dest: /Backup , History: /Backup/History
- ✅ 正确结构:
- 最新镜像:/Backup/Current
- 历史归档:/Backup/History
3. 报错 error reading source root directory: directory not found
现象:
日志提示找不到源目录,备份直接退出。
原因:
- 脚本中的 SOURCE_DIR 路径写错了(拼写错误)。
- 变量赋值时多了空格(这是最隐蔽的)。例如 SOURCE_DIR=" /www/..."(引号内开头有个空格)。
解决方案:
使用 ls -l 确认真实路径,并检查脚本变量赋值的等号后面是否有空格。
4. 进度卡在 98% 或出现 429 Too Many Requests
现象:
- 备份进度条卡在最后一点点不动。
- 速度降至几十 B/s,剩余时间显示好几天。
- 日志中出现 Errors: 16 (retrying may help)。
(上面的脚本在正常使用的情况下不会出现此问题,若出现此问题,请按照以下方法修改)
原因:
并发设置过高(如 --transfers 16),触发了微软 OneDrive API 的 QPS 限制(限流)。微软会暂时“拉黑”你的连接,或者极度降低响应速度。
解决方案:
降低并发,并强制限制 API 请求频率(温和策略):codeBash
# 核心参数调整
--transfers 4 \ # 降低并发文件数
--checkers 6 \ # 降低扫描线程
--tpslimit 10 \ # 强制限制每秒事务数为10 (解封关键)
--timeout 60s \ # 增加超时容忍度
5. 日志一直刷 SetModTime (Set directory modification time)
现象:
文件似乎都传完了,但日志还在疯狂刷屏 Set directory modification time,看起来像死循环。
原因:
这不是报错! 这是 Rclone 在做收尾工作。它在将服务器上文件夹的“最后修改时间”同步到网盘上,确保属性完全一致。对于 Discuz/WordPress 这种文件夹层级很深系统,这一步需要一点时间。
解决方案:
无需处理,耐心等待即可,这代表备份即将成功。
6. 为什么要排除 /data/cache 或 /wp-content/cache?
问题:
有些新手倾向于“全盘备份”,不加排除规则,结果备份速度极慢。
原因:
Discuz 和 WordPress 的缓存目录包含成千上万个小文件(HTML/PHP缓存)。
- Listed (总扫描数) 可能高达 30,000+。
- Checks (有效检查) 可能只有 10,000+。
- 如果不排除,Rclone 需要耗费大量时间去扫描这些可再生、无备份价值的垃圾文件,严重拖慢速度并浪费网盘空间。
解决方案:
在脚本中务必加入 --exclude 规则。
- Discuz 排除: /data/cache/**, /data/template/**, /data/threadcache/**
- WordPress 排除: /wp-content/cache/**, /wp-content/upgrade/**
7. 恢复后网站报 403 Forbidden 或无法上传图片
现象:
使用 rclone copy 将文件从网盘拉回服务器后,网站无法打开或图片上传失败。
原因:
Rclone 默认使用 root 用户运行,恢复回来的文件所有者是 root。而宝塔建立的网站(Nginx/Apache)使用的是 www 用户,导致没有权限读取或写入文件。
解决方案:
恢复文件后,必须执行权限修复命令:codeBash
# 1. 修复所有者 (改为 www 用户)
chown -R www:www /www/wwwroot/你的网站目录
# 2. 修复读写权限 (通常为 755)
chmod -R 755 /www/wwwroot/你的网站目录
8. 恢复数据时应该用 sync 还是 copy?
建议:
永远优先使用 copy。
- rclone sync:是镜像同步。如果网盘里的文件比本地少,它会删除本地文件。操作失误可能导致数据清空。
- rclone copy:是增量复制。只把网盘有的拉回来,绝不删除本地现有文件。

Comments NOTHING