4129 字
21 分钟
Cloudflare R2备份脚本
Cloudflare R2备份脚本
📜 完整脚本源码
#!/bin/bash
# Cloudflare R2备份脚本# 支持交互式选择和命令行参数调用# 使用方法: sh r2_backup.sh [选项]# 选项: 1 - 全量备份
# 颜色定义RED='\033[0;31m'GREEN='\033[0;32m'YELLOW='\033[1;33m'BLUE='\033[0;34m'NC='\033[0m' # No Color
# R2配置变量R2_BUCKET_NAME="bucket_name"R2_ENDPOINT="https://xxx.r2.cloudflarestorage.com"R2_ACCESS_KEY_ID="xxx"R2_ACCESS_KEY_SECRET="xxx"R2_REGION="WNAM"R2_REMOTE_NAME="cloudflare-r2"
# 备份配置BACKUP_TARGET_DIR="/home/r2_backup_$(date +%Y%m%d_%H%M%S)" # 本地备份目录(带时间戳)# 备份整个存储桶,保持完整目录结构
# 日志函数log_info() { echo -e "${BLUE}[INFO]${NC} $1"}
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"}
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"}
log_error() { echo -e "${RED}[ERROR]${NC} $1"}
# 检查rclone是否已安装check_rclone() { log_info "检查rclone是否已安装..."
if command -v rclone &> /dev/null; then local version=$(rclone version | head -n 1) log_success "rclone已安装: $version" return 0 else log_warning "rclone未安装" return 1 fi}
# 安装rcloneinstall_rclone() { log_info "开始安装rclone..."
# 检查系统类型 if [[ -f /etc/redhat-release ]] || [[ -f /etc/centos-release ]] || [[ -f /etc/alios-release ]]; then # CentOS/RHEL/Alibaba Cloud Linux log_info "检测到CentOS/RHEL/Alibaba Cloud Linux系统"
# 使用官方推荐的安装方法 curl https://rclone.org/install.sh | sudo bash
if [[ $? -eq 0 ]]; then log_success "rclone安装成功" else log_error "rclone安装失败" exit 1 fi else log_error "不支持的系统类型,请手动安装rclone" exit 1 fi}
# 配置rclone for Cloudflare R2configure_rclone() { log_info "配置rclone连接到Cloudflare R2..."
# 检查配置是否已存在,静默覆盖 if rclone listremotes | grep -q "^${R2_REMOTE_NAME}:$"; then log_info "rclone配置 '${R2_REMOTE_NAME}' 已存在,将更新配置" fi
# 创建rclone配置 log_info "创建rclone配置文件..."
# 确保配置目录存在 mkdir -p ~/.config/rclone
# 生成配置内容 cat > ~/.config/rclone/rclone.conf << EOF[${R2_REMOTE_NAME}]type = s3provider = Cloudflareaccess_key_id = ${R2_ACCESS_KEY_ID}secret_access_key = ${R2_ACCESS_KEY_SECRET}region = ${R2_REGION}endpoint = ${R2_ENDPOINT}acl = privateEOF
# 测试连接 log_info "测试rclone连接..." if rclone lsd ${R2_REMOTE_NAME}: &> /dev/null; then log_success "rclone配置成功,连接测试通过" else log_error "rclone配置失败,连接测试未通过" exit 1 fi}
# 全量备份函数full_backup() { log_info "开始执行全量备份..." log_info "备份源: ${R2_REMOTE_NAME}:${R2_BUCKET_NAME}/ (整个存储桶)" log_info "备份目标目录: ${BACKUP_TARGET_DIR}"
# 创建本地备份目录 mkdir -p "${BACKUP_TARGET_DIR}"
# 创建备份日志目录 local log_dir="/var/log/r2_backup" sudo mkdir -p "$log_dir" local log_file="$log_dir/backup_$(date +%Y%m%d_%H%M%S).log"
# 执行备份 - 备份整个存储桶,保持完整目录结构 log_info "开始从Cloudflare R2同步整个存储桶到本地..."
rclone sync "${R2_REMOTE_NAME}:${R2_BUCKET_NAME}/" "${BACKUP_TARGET_DIR}/" \ --progress \ --transfers 4 \ --checkers 8 \ --retries 3 \ --low-level-retries 10 \ --stats 30s \ --log-file "$log_file" \ --log-level INFO
if [[ $? -eq 0 ]]; then log_success "全量备份完成" log_info "备份日志: $log_file"
# 显示备份统计信息 log_info "获取备份统计信息..." rclone size "${R2_REMOTE_NAME}:${R2_BUCKET_NAME}/${BACKUP_REMOTE_DIR}" else log_error "全量备份失败" log_error "请查看日志文件: $log_file" exit 1 fi}
# 显示菜单show_menu() { echo echo "==================================" echo " Cloudflare R2 数据备份工具" echo " (从R2下载数据到本地服务器)" echo "==================================" echo "1. 全量备份 (从R2同步到本地)" echo "2. 查看备份状态" echo "3. 测试R2连接" echo "4. 删除R2目录" echo "5. 重新配置rclone" echo "0. 退出" echo "=================================="}
# 查看备份列表list_backups() { log_info "查看备份列表..."
echo echo "=== 本地备份目录 ===" if [[ -d "${BACKUP_TARGET_DIR}" ]]; then ls -la "${BACKUP_TARGET_DIR}" echo echo "备份目录大小:" du -sh "${BACKUP_TARGET_DIR}" else echo "本地备份目录不存在: ${BACKUP_TARGET_DIR}" fi
echo echo "=== R2存储桶内容 ===" rclone lsd "${R2_REMOTE_NAME}:${R2_BUCKET_NAME}" --max-depth 2}
# 测试连接test_connection() { log_info "测试Cloudflare R2连接..." if rclone lsd "${R2_REMOTE_NAME}:" &> /dev/null; then log_success "连接测试成功" rclone about "${R2_REMOTE_NAME}:" else log_error "连接测试失败" fi}
# 删除R2存储桶中的指定顶层目录delete_directory() { log_info "删除R2存储桶中的顶层目录..."
echo echo "=== R2存储桶顶层目录列表 ==="
# 获取顶层目录列表 local dirs=$(rclone lsd "${R2_REMOTE_NAME}:${R2_BUCKET_NAME}" --max-depth 1 2>/dev/null | awk '{print $5}' | grep -v '^$')
if [[ -z "$dirs" ]]; then log_warning "存储桶中没有找到任何目录" return 1 fi
# 显示目录列表 local dir_array=() local index=1 while IFS= read -r dir; do if [[ -n "$dir" ]]; then echo "$index. $dir" dir_array+=("$dir") ((index++)) fi done <<< "$dirs"
echo "0. 取消操作" echo
# 用户选择 read -p "请选择要删除的目录编号 [0-$((index-1))]: " choice
# 验证输入 if [[ ! "$choice" =~ ^[0-9]+$ ]] || [[ "$choice" -lt 0 ]] || [[ "$choice" -ge "$index" ]]; then log_error "无效的选择" return 1 fi
# 取消操作 if [[ "$choice" -eq 0 ]]; then log_info "取消删除操作" return 0 fi
# 获取选择的目录 local selected_dir="${dir_array[$((choice-1))]}"
# 二次确认 echo log_warning "警告:即将删除目录 '${selected_dir}' 及其所有内容" log_warning "此操作不可逆!" read -p "确认删除? 请输入 'DELETE' 来确认: " confirm
if [[ "$confirm" != "DELETE" ]]; then log_info "取消删除操作" return 0 fi
# 执行删除 log_info "正在删除目录: ${selected_dir}"
if rclone purge "${R2_REMOTE_NAME}:${R2_BUCKET_NAME}/${selected_dir}" 2>/dev/null; then log_success "目录 '${selected_dir}' 删除成功" else log_error "目录 '${selected_dir}' 删除失败" return 1 fi}
# 主函数main() { echo "Cloudflare R2备份脚本启动..."
# 处理命令行参数 - 直接执行模式 if [[ $# -gt 0 ]]; then # 检查并安装rclone if ! check_rclone; then install_rclone fi
# 配置rclone configure_rclone
case $1 in 1) full_backup exit 0 ;; 2) list_backups exit 0 ;; 3) test_connection exit 0 ;; 4) delete_directory exit 0 ;; 5) configure_rclone exit 0 ;; *) log_error "无效的参数: $1" echo "使用方法: $0 [1|2|3|4|5]" echo "1 - 全量备份" echo "2 - 查看备份列表" echo "3 - 测试连接" echo "4 - 删除R2目录" echo "5 - 重新配置rclone" exit 1 ;; esac fi
# 交互式菜单模式 while true; do show_menu read -p "请选择操作 [0-4]: " choice
case $choice in 1) # 检查并安装rclone if ! check_rclone; then install_rclone fi # 配置rclone configure_rclone full_backup ;; 2) # 检查并安装rclone if ! check_rclone; then install_rclone fi # 配置rclone configure_rclone list_backups ;; 3) # 检查并安装rclone if ! check_rclone; then install_rclone fi # 配置rclone configure_rclone test_connection ;; 4) # 检查并安装rclone if ! check_rclone; then install_rclone fi # 配置rclone configure_rclone delete_directory ;; 5) # 检查并安装rclone if ! check_rclone; then install_rclone fi configure_rclone ;; 0) log_info "退出程序" exit 0 ;; *) log_error "无效选择,请重新输入" ;; esac
echo read -p "按回车键继续..." -r done}
# 脚本入口main "$@"📋 项目介绍
这是一个功能完整的 Cloudflare R2 存储桶管理工具,支持数据备份、目录删除等操作。该脚本基于 rclone 工具开发,提供了友好的交互式界面和命令行参数支持。
✨ 功能特性
- 🔄 全量备份: 从 Cloudflare R2 存储桶同步数据到本地服务器
- 📊 状态查看: 查看本地备份和远程存储桶状态
- 🔗 连接测试: 测试与 Cloudflare R2 的连接状态
- 🗑️ 目录删除: 安全删除 R2 存储桶中的指定目录
- ⚙️ 配置管理: 自动安装和配置 rclone
- 📝 日志记录: 详细的操作日志和彩色输出
- 🎛️ 双模式支持: 交互式菜单 + 命令行参数
🛠️ 环境要求
系统支持
- CentOS 7+
- RHEL 7+
- Alibaba Cloud Linux
- 其他 Linux 发行版(需手动安装 rclone)
依赖工具
curl- 用于下载 rclonesudo- 管理员权限bash- Shell 解释器
📋 配置说明
R2 配置参数
在使用脚本前,需要修改以下配置变量:
R2_BUCKET_NAME="your-bucket-name" # R2 存储桶名称R2_ENDPOINT="https://xxx.r2.cloudflarestorage.com" # R2 端点地址R2_ACCESS_KEY_ID="your-access-key" # 访问密钥 IDR2_ACCESS_KEY_SECRET="your-secret-key" # 访问密钥R2_REGION="WNAM" # 区域设置获取 R2 配置信息
- 登录 Cloudflare Dashboard
- 进入 R2 Object Storage
- 选择您的存储桶
- 在 Settings 中获取端点地址
- 在 API tokens 中创建并获取访问密钥
🚀 使用方法
交互式模式
# 启动交互式菜单sh r2_backup.sh命令行模式
# 全量备份sh r2_backup.sh 1
# 查看备份状态sh r2_backup.sh 2
# 测试连接sh r2_backup.sh 3
# 删除R2目录sh r2_backup.sh 4
# 重新配置rclonesh r2_backup.sh 5📖 功能详解
1. 全量备份
- 从 R2 存储桶完整同步数据到本地
- 保持原有目录结构
- 自动创建带时间戳的备份目录
- 支持断点续传和重试机制
2. 查看备份状态
- 显示本地备份目录内容和大小
- 展示 R2 存储桶结构
- 提供详细的统计信息
3. 测试连接
- 验证 rclone 配置正确性
- 测试网络连接状态
- 显示存储桶基本信息
4. 删除 R2 目录
- 列出存储桶顶层目录
- 交互式选择删除目标
- 二次确认防止误操作
- 安全删除指定目录及内容
5. 配置管理
- 自动检测和安装 rclone
- 生成 R2 连接配置
- 验证配置有效性
📂 目录结构
/home/r2_backup_YYYYMMDD_HHMMSS/ # 备份根目录├── [存储桶内容] # 保持原有结构/var/log/r2_backup/ # 日志目录├── backup_YYYYMMDD_HHMMSS.log # 备份日志~/.config/rclone/ # rclone配置├── rclone.conf # 配置文件⚠️ 注意事项
安全提醒
- 访问密钥安全: 确保 R2 访问密钥的安全性,不要泄露
- 删除确认: 删除操作不可逆,请谨慎操作
- 权限管理: 脚本需要 sudo 权限进行系统操作
性能优化
- 网络带宽: 大文件传输需要稳定的网络环境
- 存储空间: 确保本地有足够的存储空间
- 并发设置: 可根据服务器性能调整
--transfers和--checkers参数
备份策略
- 定期备份: 建议设置定时任务进行定期备份
- 监控日志: 定期检查备份日志确保操作成功
- 版本管理: 考虑实现备份版本管理机制
🛠️ 故障排除
常见问题
Q: rclone 安装失败
# 手动安装 rclonecurl https://rclone.org/install.sh | sudo bashQ: 连接测试失败
- 检查网络连接
- 验证 R2 配置参数
- 确认访问密钥权限
Q: 备份中断
- 检查磁盘空间
- 查看网络状态
- 重新运行备份命令
Q: 权限不足
# 确保脚本有执行权限chmod +x r2_backup.sh日志分析
备份日志位于 /var/log/r2_backup/ 目录下,包含详细的操作记录:
# 查看最新日志tail -f /var/log/r2_backup/backup_*.log
# 搜索错误信息grep -i error /var/log/r2_backup/backup_*.log🔧 高级配置
自定义 rclone 参数
可在脚本中修改以下参数以优化性能:
--transfers 4 # 并发传输数量--checkers 8 # 并发检查器数量--retries 3 # 重试次数--low-level-retries 10 # 底层重试次数--stats 30s # 统计更新间隔定时备份设置
使用 crontab 设置定时备份:
# 编辑 crontabcrontab -e
# 每天凌晨 2 点执行全量备份0 2 * * * /path/to/r2_backup.sh 1 >> /var/log/r2_backup/cron.log 2>&1📜 完整脚本源码
#!/bin/bash
# Cloudflare R2备份脚本# 支持交互式选择和命令行参数调用# 使用方法: sh r2_backup.sh [选项]# 选项: 1 - 全量备份
# 颜色定义RED='\033[0;31m'GREEN='\033[0;32m'YELLOW='\033[1;33m'BLUE='\033[0;34m'NC='\033[0m' # No Color
# R2配置变量R2_BUCKET_NAME="twenhub-bucket"R2_ENDPOINT="https://xxx.r2.cloudflarestorage.com"R2_ACCESS_KEY_ID="xxx"R2_ACCESS_KEY_SECRET="xxx"R2_REGION="WNAM"R2_REMOTE_NAME="cloudflare-r2"
# 备份配置BACKUP_TARGET_DIR="/home/r2_backup_$(date +%Y%m%d_%H%M%S)" # 本地备份目录(带时间戳)# 备份整个存储桶,保持完整目录结构
# 日志函数log_info() { echo -e "${BLUE}[INFO]${NC} $1"}
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"}
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"}
log_error() { echo -e "${RED}[ERROR]${NC} $1"}
# 检查rclone是否已安装check_rclone() { log_info "检查rclone是否已安装..."
if command -v rclone &> /dev/null; then local version=$(rclone version | head -n 1) log_success "rclone已安装: $version" return 0 else log_warning "rclone未安装" return 1 fi}
# 安装rcloneinstall_rclone() { log_info "开始安装rclone..."
# 检查系统类型 if [[ -f /etc/redhat-release ]] || [[ -f /etc/centos-release ]] || [[ -f /etc/alios-release ]]; then # CentOS/RHEL/Alibaba Cloud Linux log_info "检测到CentOS/RHEL/Alibaba Cloud Linux系统"
# 使用官方推荐的安装方法 curl https://rclone.org/install.sh | sudo bash
if [[ $? -eq 0 ]]; then log_success "rclone安装成功" else log_error "rclone安装失败" exit 1 fi else log_error "不支持的系统类型,请手动安装rclone" exit 1 fi}
# 配置rclone for Cloudflare R2configure_rclone() { log_info "配置rclone连接到Cloudflare R2..."
# 检查配置是否已存在,静默覆盖 if rclone listremotes | grep -q "^${R2_REMOTE_NAME}:$"; then log_info "rclone配置 '${R2_REMOTE_NAME}' 已存在,将更新配置" fi
# 创建rclone配置 log_info "创建rclone配置文件..."
# 确保配置目录存在 mkdir -p ~/.config/rclone
# 生成配置内容 cat > ~/.config/rclone/rclone.conf << EOF[${R2_REMOTE_NAME}]type = s3provider = Cloudflareaccess_key_id = ${R2_ACCESS_KEY_ID}secret_access_key = ${R2_ACCESS_KEY_SECRET}region = ${R2_REGION}endpoint = ${R2_ENDPOINT}acl = privateEOF
# 测试连接 log_info "测试rclone连接..." if rclone lsd ${R2_REMOTE_NAME}: &> /dev/null; then log_success "rclone配置成功,连接测试通过" else log_error "rclone配置失败,连接测试未通过" exit 1 fi}
# 全量备份函数full_backup() { log_info "开始执行全量备份..." log_info "备份源: ${R2_REMOTE_NAME}:${R2_BUCKET_NAME}/ (整个存储桶)" log_info "备份目标目录: ${BACKUP_TARGET_DIR}"
# 创建本地备份目录 mkdir -p "${BACKUP_TARGET_DIR}"
# 创建备份日志目录 local log_dir="/var/log/r2_backup" sudo mkdir -p "$log_dir" local log_file="$log_dir/backup_$(date +%Y%m%d_%H%M%S).log"
# 执行备份 - 备份整个存储桶,保持完整目录结构 log_info "开始从Cloudflare R2同步整个存储桶到本地..."
rclone sync "${R2_REMOTE_NAME}:${R2_BUCKET_NAME}/" "${BACKUP_TARGET_DIR}/" \ --progress \ --transfers 4 \ --checkers 8 \ --retries 3 \ --low-level-retries 10 \ --stats 30s \ --log-file "$log_file" \ --log-level INFO
if [[ $? -eq 0 ]]; then log_success "全量备份完成" log_info "备份日志: $log_file"
# 显示备份统计信息 log_info "获取备份统计信息..." rclone size "${R2_REMOTE_NAME}:${R2_BUCKET_NAME}/${BACKUP_REMOTE_DIR}" else log_error "全量备份失败" log_error "请查看日志文件: $log_file" exit 1 fi}
# 显示菜单show_menu() { echo echo "==================================" echo " Cloudflare R2 数据备份工具" echo " (从R2下载数据到本地服务器)" echo "==================================" echo "1. 全量备份 (从R2同步到本地)" echo "2. 查看备份状态" echo "3. 测试R2连接" echo "4. 删除R2目录" echo "5. 重新配置rclone" echo "0. 退出" echo "=================================="}
# 查看备份列表list_backups() { log_info "查看备份列表..."
echo echo "=== 本地备份目录 ===" if [[ -d "${BACKUP_TARGET_DIR}" ]]; then ls -la "${BACKUP_TARGET_DIR}" echo echo "备份目录大小:" du -sh "${BACKUP_TARGET_DIR}" else echo "本地备份目录不存在: ${BACKUP_TARGET_DIR}" fi
echo echo "=== R2存储桶内容 ===" rclone lsd "${R2_REMOTE_NAME}:${R2_BUCKET_NAME}" --max-depth 2}
# 测试连接test_connection() { log_info "测试Cloudflare R2连接..." if rclone lsd "${R2_REMOTE_NAME}:" &> /dev/null; then log_success "连接测试成功" rclone about "${R2_REMOTE_NAME}:" else log_error "连接测试失败" fi}
# 删除R2存储桶中的指定顶层目录delete_directory() { log_info "删除R2存储桶中的顶层目录..."
echo echo "=== R2存储桶顶层目录列表 ==="
# 获取顶层目录列表 local dirs=$(rclone lsd "${R2_REMOTE_NAME}:${R2_BUCKET_NAME}" --max-depth 1 2>/dev/null | awk '{print $5}' | grep -v '^$')
if [[ -z "$dirs" ]]; then log_warning "存储桶中没有找到任何目录" return 1 fi
# 显示目录列表 local dir_array=() local index=1 while IFS= read -r dir; do if [[ -n "$dir" ]]; then echo "$index. $dir" dir_array+=("$dir") ((index++)) fi done <<< "$dirs"
echo "0. 取消操作" echo
# 用户选择 read -p "请选择要删除的目录编号 [0-$((index-1))]: " choice
# 验证输入 if [[ ! "$choice" =~ ^[0-9]+$ ]] || [[ "$choice" -lt 0 ]] || [[ "$choice" -ge "$index" ]]; then log_error "无效的选择" return 1 fi
# 取消操作 if [[ "$choice" -eq 0 ]]; then log_info "取消删除操作" return 0 fi
# 获取选择的目录 local selected_dir="${dir_array[$((choice-1))]}"
# 二次确认 echo log_warning "警告:即将删除目录 '${selected_dir}' 及其所有内容" log_warning "此操作不可逆!" read -p "确认删除? 请输入 'DELETE' 来确认: " confirm
if [[ "$confirm" != "DELETE" ]]; then log_info "取消删除操作" return 0 fi
# 执行删除 log_info "正在删除目录: ${selected_dir}"
if rclone purge "${R2_REMOTE_NAME}:${R2_BUCKET_NAME}/${selected_dir}" 2>/dev/null; then log_success "目录 '${selected_dir}' 删除成功" else log_error "目录 '${selected_dir}' 删除失败" return 1 fi}
# 主函数main() { echo "Cloudflare R2备份脚本启动..."
# 处理命令行参数 - 直接执行模式 if [[ $# -gt 0 ]]; then # 检查并安装rclone if ! check_rclone; then install_rclone fi
# 配置rclone configure_rclone
case $1 in 1) full_backup exit 0 ;; 2) list_backups exit 0 ;; 3) test_connection exit 0 ;; 4) delete_directory exit 0 ;; 5) configure_rclone exit 0 ;; *) log_error "无效的参数: $1" echo "使用方法: $0 [1|2|3|4|5]" echo "1 - 全量备份" echo "2 - 查看备份列表" echo "3 - 测试连接" echo "4 - 删除R2目录" echo "5 - 重新配置rclone" exit 1 ;; esac fi
# 交互式菜单模式 while true; do show_menu read -p "请选择操作 [0-4]: " choice
case $choice in 1) # 检查并安装rclone if ! check_rclone; then install_rclone fi # 配置rclone configure_rclone full_backup ;; 2) # 检查并安装rclone if ! check_rclone; then install_rclone fi # 配置rclone configure_rclone list_backups ;; 3) # 检查并安装rclone if ! check_rclone; then install_rclone fi # 配置rclone configure_rclone test_connection ;; 4) # 检查并安装rclone if ! check_rclone; then install_rclone fi # 配置rclone configure_rclone delete_directory ;; 5) # 检查并安装rclone if ! check_rclone; then install_rclone fi configure_rclone ;; 0) log_info "退出程序" exit 0 ;; *) log_error "无效选择,请重新输入" ;; esac
echo read -p "按回车键继续..." -r done}
# 脚本入口main "$@"注意: 使用前请务必修改脚本中的 R2 配置参数,并确保访问密钥的安全性。
Cloudflare R2备份脚本
https://twenhub.com/posts/cloudflare-r2bei-fen-jiao-ben/