Rclone 备份本地到云盘
1008 字
5 分钟
Rclone 备份本地到云盘
概述
本方案提供一个可直接运行的 Bash 脚本,用于将本地目录与远端网盘(示例:通过 Openlist 暴露的云盘 WebDAV)进行高可靠同步。脚本内置带宽时间表、模拟运行、安全的日志权限与日志数量上限清理,并针对 WebDAV 链路加入了缓冲、重试与限流优化。
快速开始
安装并配置 rclone
sudo apt-get update && sudo apt-get install -y rclonerclone versionrclone config # 建立并测试名为 myremote 的 WebDAV 远端创建脚本并设置权限
chmod +x ./rclone_sync.shRclone 脚本
#!/bin/bashset -euo pipefailumask 022
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
# ===== 固定参数开始(按需修改)=====LOCAL_DIR="/path/to/source" # 本地要同步的目录(源)REMOTE_PATH="myremote:/path/in/remote" # 远端路径:remote 名称:目标子路径(目的地)BW_SCHEDULE="00:00,12M 08:00,5M 23:00,12M" # 带宽时间表(本地时间循环):08:00–23:00 5M/s,其余 12M/sTRANSFERS=4 # 并发文件传输数,建议 3–4(适中减轻限速/429)CHECKERS=8 # 校验/列目录并发数,建议为 TRANSFERS 的 1.5–2 倍LOG_DIR="/path/to/logs/rclone_sync" # 日志目录(建议 SSD/缓存盘)SIMULATE=true # 模拟运行:true/false(仅打印不改动)MAX_LOG_FILES=30 # 日志数量上限;0 表示不限制LOG_FILE_OWNER="nobody" # 日志文件属主(便于 SMB/Unraid 客户端读取);留空不更改LOG_FILE_GROUP="users" # 日志文件属组;留空不更改BUFFER_SIZE="32M" # 传输缓冲区:常用 16M 或 32M(更大更占内存)RETRIES=6 # 高层重试次数(处理 HTTP 429/网络抖动)RETRIES_SLEEP="10s" # 高层重试间隔LOW_LEVEL_RETRIES=20 # 底层分片/连接重试次数TIMEOUT="5m" # 单次 I/O 超时(读写)CONN_TIMEOUT="20s" # 连接建立超时TPSLIMIT=8 # 每秒请求上限(防 429)TPSLIMIT_BURST=16 # 瞬时突发上限MODIFY_WINDOW="2s" # 修改时间容差;若仍异常可改用 --size-only# ===== 固定参数结束 =====mkdir -p "${LOG_DIR}"
if ! command -v rclone >/dev/null 2>&1; then echo "[ERROR] 未找到 rclone,请先安装与配置 rclone。" >&2 exit 1fi
:
if [[ ! -d "${LOCAL_DIR}" ]]; then echo "[ERROR] 本地目录不存在:${LOCAL_DIR}" >&2 exit 3fi
# 带宽时间表(本地时间,按日循环)和性能参数已固定在上方
TIMESTAMP="$(date +"%Y%m%d_%H%M%S")"LOG_FILE="${LOG_DIR}/rclone_sync_${TIMESTAMP}.log"
echo "[INFO] 开始同步"echo "[INFO] 本地: ${LOCAL_DIR}"echo "[INFO] 远端: ${REMOTE_PATH}"echo "[INFO] 带宽时间表: ${BW_SCHEDULE}"echo "[INFO] 日志: ${LOG_FILE}"if [[ "${SIMULATE}" == "true" ]]; then echo "[INFO] 模拟运行: 已开启 (--dry-run)"else echo "[INFO] 模拟运行: 关闭"fi
# 说明:# --delete-after 默认行为由 sync 决定(保持远端与本地一致),如需先传后删可显式加此项# --stats-one-line 更简洁的进度输出# --log-level INFO 常用日志级别(DEBUG 更详细)# 如使用特定后端(如 drive/s3),可追加相应优化参数(例如 --drive-chunk-size 等)。
# 预创建日志并设置权限/属主(若配置了 LOG_FILE_OWNER/GROUP 且系统存在)touch "${LOG_FILE}" || truechmod 644 "${LOG_FILE}" || truechmod 755 "${LOG_DIR}" || trueif id -u "${LOG_FILE_OWNER}" >/dev/null 2>&1 && getent group "${LOG_FILE_GROUP}" >/dev/null 2>&1; then chown "${LOG_FILE_OWNER}:${LOG_FILE_GROUP}" "${LOG_FILE}" || truefi
CMD=( rclone sync "${LOCAL_DIR}" "${REMOTE_PATH}" --bwlimit "${BW_SCHEDULE}" --transfers "${TRANSFERS}" --checkers "${CHECKERS}" --log-file "${LOG_FILE}" --log-level INFO --stats 30s --stats-one-line --buffer-size "${BUFFER_SIZE}" --retries "${RETRIES}" --retries-sleep "${RETRIES_SLEEP}" --low-level-retries "${LOW_LEVEL_RETRIES}" --timeout "${TIMEOUT}" --contimeout "${CONN_TIMEOUT}" --tpslimit "${TPSLIMIT}" --tpslimit-burst "${TPSLIMIT_BURST}" --modify-window "${MODIFY_WINDOW}")
if [[ "${SIMULATE}" == "true" ]]; then CMD+=(--dry-run)fi
"${CMD[@]}"
EXIT_CODE=$?
if [[ ${EXIT_CODE} -eq 0 ]]; then echo "[INFO] 同步完成"else echo "[ERROR] 同步失败,退出码:${EXIT_CODE}" >&2fi
# 按数量上限清理旧日志if [[ -n "${LOG_DIR}" && -d "${LOG_DIR}" && ${MAX_LOG_FILES} -gt 0 ]]; then # 按时间倒序列出匹配日志文件 mapfile -t _log_files < <(ls -1t "${LOG_DIR}"/rclone_sync_*.log 2>/dev/null || true) total_logs=${#_log_files[@]} if [[ ${total_logs} -gt ${MAX_LOG_FILES} ]]; then to_delete=$(( total_logs - MAX_LOG_FILES )) echo "[INFO] 日志数量 ${total_logs} 超过上限 ${MAX_LOG_FILES},将删除最旧的 ${to_delete} 个日志" # 从时间倒序数组的尾部开始删除(即最旧) for (( i=total_logs-1; i>=MAX_LOG_FILES; i-- )); do rm -f -- "${_log_files[$i]}" || true done fifi
exit ${EXIT_CODE}编辑脚本顶部参数,至少确认:
- LOCAL_DIR:本地源目录
- REMOTE_PATH:目标远端(remote:子路径)
- LOG_DIR:日志目录(建议本地 SSD/缓存盘)
- SIMULATE:首次运行建议设为 true(仅预演不改动)
执行模拟
./rclone_sync.sh # 当 SIMULATE=true 时,仅打印将要执行的操作正式执行
将脚本内 SIMULATE=false 后再次运行:
./rclone_sync.shcrontab(每天 2:30 执行一次):
crontab -e30 2 * * * /bin/bash /path/to/rclone_sync.sh >> /dev/null 2>&1 站点统计
5
3
12
5,470
0 天
0 天前
日
一
二
三
四
五
六