477 lines
13 KiB
Bash
477 lines
13 KiB
Bash
#!/bin/bash
|
|
|
|
# BorgBackup 智能安装配置脚本
|
|
set -e
|
|
|
|
# 颜色定义
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# 日志函数
|
|
log() {
|
|
echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
}
|
|
|
|
warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
}
|
|
|
|
error() {
|
|
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
exit 1
|
|
}
|
|
|
|
# 检查系统
|
|
check_system() {
|
|
log "检查系统环境..."
|
|
|
|
# 检查操作系统
|
|
if [ ! -f /etc/os-release ]; then
|
|
error "无法检测操作系统"
|
|
fi
|
|
|
|
source /etc/os-release
|
|
log "检测到系统: $NAME $VERSION"
|
|
|
|
# 检查架构
|
|
ARCH=$(uname -m)
|
|
log "系统架构: $ARCH"
|
|
|
|
# 检查磁盘空间
|
|
DISK_SPACE=$(df /tmp | awk 'NR==2 {print $4}')
|
|
if [ "$DISK_SPACE" -lt 1048576 ]; then # 小于 1GB
|
|
warn "磁盘空间可能不足 (当前: ${DISK_SPACE}KB)"
|
|
read -p "是否继续? (y/N): " -n 1 -r
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
error "安装中止"
|
|
fi
|
|
fi
|
|
|
|
# 检查内存
|
|
MEMORY=$(free -m | awk 'NR==2{print $2}')
|
|
if [ "$MEMORY" -lt 512 ]; then
|
|
warn "内存较小 (当前: ${MEMORY}MB),可能会影响备份性能"
|
|
fi
|
|
}
|
|
|
|
# 安装依赖
|
|
install_dependencies() {
|
|
log "安装系统依赖..."
|
|
|
|
# 根据系统类型安装依赖
|
|
if command -v apt >/dev/null 2>&1; then
|
|
# Debian/Ubuntu
|
|
sudo apt update || warn "apt update 失败,尝试继续..."
|
|
sudo apt install -y \
|
|
python3 \
|
|
python3-pip \
|
|
curl \
|
|
wget \
|
|
fuse \
|
|
pv \
|
|
cron \
|
|
|| error "依赖安装失败"
|
|
|
|
elif command -v yum >/dev/null 2>&1; then
|
|
# CentOS/RHEL
|
|
sudo yum install -y \
|
|
python3 \
|
|
python3-pip \
|
|
curl \
|
|
wget \
|
|
fuse \
|
|
pv \
|
|
cronie \
|
|
|| error "依赖安装失败"
|
|
|
|
elif command -v dnf >/dev/null 2>&1; then
|
|
# Fedora
|
|
sudo dnf install -y \
|
|
python3 \
|
|
python3-pip \
|
|
curl \
|
|
wget \
|
|
fuse \
|
|
pv \
|
|
cronie \
|
|
|| error "依赖安装失败"
|
|
|
|
else
|
|
error "不支持的包管理器"
|
|
fi
|
|
}
|
|
|
|
# 安装 BorgBackup
|
|
install_borg() {
|
|
log "安装 BorgBackup..."
|
|
|
|
# 检查是否已安装
|
|
if command -v borg >/dev/null 2>&1; then
|
|
CURRENT_VERSION=$(borg --version)
|
|
log "BorgBackup 已安装: $CURRENT_VERSION"
|
|
read -p "是否重新安装? (y/N): " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# 多种安装方式
|
|
log "尝试通过系统包管理器安装..."
|
|
if command -v apt >/dev/null 2>&1; then
|
|
sudo apt install -y borgbackup && return 0
|
|
elif command -v yum >/dev/null 2>&1; then
|
|
sudo yum install -y borgbackup && return 0
|
|
elif command -v dnf >/dev/null 2>&1; then
|
|
sudo dnf install -y borgbackup && return 0
|
|
fi
|
|
|
|
# 包管理器安装失败,使用 pip
|
|
warn "包管理器安装失败,尝试使用 pip 安装..."
|
|
sudo pip3 install borgbackup || {
|
|
# 如果 pip 安装失败,尝试使用 conda
|
|
if command -v conda >/dev/null 2>&1; then
|
|
warn "尝试使用 conda 安装..."
|
|
conda install -c conda-forge borgbackup || error "BorgBackup 安装失败"
|
|
else
|
|
error "所有安装方式都失败,请手动安装"
|
|
fi
|
|
}
|
|
|
|
log "BorgBackup 安装成功: $(borg --version)"
|
|
}
|
|
|
|
# 安装 rclone
|
|
install_rclone() {
|
|
log "安装 rclone..."
|
|
|
|
if command -v rclone >/dev/null 2>&1; then
|
|
log "rclone 已安装: $(rclone version | head -n1)"
|
|
return 0
|
|
fi
|
|
|
|
# 使用官方安装脚本
|
|
curl https://rclone.org/install.sh | sudo bash || {
|
|
# 如果脚本安装失败,尝试包管理器
|
|
warn "脚本安装失败,尝试包管理器..."
|
|
if command -v apt >/dev/null 2>&1; then
|
|
sudo apt install -y rclone
|
|
elif command -v yum >/dev/null 2>&1; then
|
|
sudo yum install -y rclone
|
|
else
|
|
error "rclone 安装失败"
|
|
fi
|
|
}
|
|
|
|
log "rclone 安装成功"
|
|
}
|
|
|
|
# 交互式配置 rclone
|
|
configure_rclone() {
|
|
log "配置云存储..."
|
|
|
|
echo
|
|
echo "=== 云存储服务商选择 ==="
|
|
echo "1) Cloudflare R2 (推荐)"
|
|
echo "2) AWS S3"
|
|
echo "3) Backblaze B2"
|
|
echo "4) Google Cloud Storage"
|
|
echo "5) 阿里云 OSS"
|
|
echo "6) 腾讯云 COS"
|
|
echo "7) 其他 S3 兼容服务"
|
|
echo "8) 跳过(仅本地备份)"
|
|
|
|
read -p "请选择服务商 [1-8]: " provider_choice
|
|
|
|
case $provider_choice in
|
|
1)
|
|
remote_name="r2"
|
|
provider="Cloudflare R2"
|
|
endpoint_prompt="R2 端点 (通常为: https://<account-id>.r2.cloudflarestorage.com)"
|
|
region="auto"
|
|
;;
|
|
2)
|
|
remote_name="s3"
|
|
provider="Amazon S3"
|
|
endpoint_prompt="S3 端点 (留空使用默认): "
|
|
region_prompt="区域 (例如: us-east-1): "
|
|
;;
|
|
3)
|
|
remote_name="b2"
|
|
provider="Backblaze B2"
|
|
endpoint_prompt="B2 端点 (留空使用默认): "
|
|
region=""
|
|
;;
|
|
4)
|
|
remote_name="gcs"
|
|
provider="Google Cloud Storage"
|
|
endpoint_prompt="GCS 端点 (留空使用默认): "
|
|
region=""
|
|
;;
|
|
5)
|
|
remote_name="oss"
|
|
provider="Aliyun OSS"
|
|
endpoint_prompt="OSS 端点 (例如: https://oss-cn-hangzhou.aliyuncs.com): "
|
|
region=""
|
|
;;
|
|
6)
|
|
remote_name="cos"
|
|
provider="Tencent COS"
|
|
endpoint_prompt="COS 端点 (例如: https://cos.ap-beijing.myqcloud.com): "
|
|
region=""
|
|
;;
|
|
7)
|
|
remote_name="s3-custom"
|
|
provider="自定义 S3 兼容"
|
|
endpoint_prompt="S3 兼容端点: "
|
|
region_prompt="区域: "
|
|
;;
|
|
8)
|
|
log "跳过远程存储配置"
|
|
return 0
|
|
;;
|
|
*)
|
|
error "无效选择"
|
|
;;
|
|
esac
|
|
|
|
# 获取配置信息
|
|
echo
|
|
echo "=== 配置 $provider ==="
|
|
read -p "请输入远程存储名称 [默认: $remote_name]: " input_remote
|
|
remote_name=${input_remote:-$remote_name}
|
|
|
|
read -p "$endpoint_prompt" endpoint
|
|
if [ -n "$endpoint" ]; then
|
|
endpoint_option="$endpoint"
|
|
fi
|
|
|
|
if [ -n "$region_prompt" ]; then
|
|
read -p "$region_prompt" region
|
|
fi
|
|
|
|
echo
|
|
echo "=== API 密钥信息 ==="
|
|
echo "在哪里找到密钥:"
|
|
case $provider_choice in
|
|
1) echo "- Cloudflare Dashboard → R2 → API Tokens" ;;
|
|
2) echo "- AWS Console → IAM → Users → Security credentials" ;;
|
|
3) echo "- Backblaze → My Account → App Keys" ;;
|
|
4) echo "- Google Cloud Console → Storage → Settings → Interoperability" ;;
|
|
5) echo "- 阿里云控制台 → 访问控制 → 用户管理" ;;
|
|
6) echo "- 腾讯云控制台 → 访问管理 → API密钥管理" ;;
|
|
7) echo "- 查看您的 S3 兼容服务商文档" ;;
|
|
esac
|
|
echo
|
|
|
|
read -p "Access Key ID: " access_key
|
|
read -s -p "Secret Access Key: " secret_key
|
|
echo
|
|
|
|
# 配置 rclone
|
|
log "配置 rclone 远程存储: $remote_name"
|
|
|
|
rclone config create \
|
|
"$remote_name" \
|
|
s3 \
|
|
provider "Other" \
|
|
env_auth false \
|
|
access_key_id "$access_key" \
|
|
secret_access_key "$secret_key" \
|
|
${endpoint:+"endpoint" "$endpoint"} \
|
|
${region:+"region" "$region"} \
|
|
acl private \
|
|
|| error "rclone 配置失败"
|
|
|
|
# 测试连接
|
|
log "测试连接..."
|
|
if rclone lsd "$remote_name:" >/dev/null 2>&1; then
|
|
log "连接测试成功!"
|
|
else
|
|
warn "连接测试失败,但配置已保存。请检查网络和密钥。"
|
|
fi
|
|
|
|
REMOTE_CONFIGURED=1
|
|
CONFIGURED_REMOTE="$remote_name"
|
|
}
|
|
|
|
# 创建备份脚本
|
|
create_backup_scripts() {
|
|
log "创建备份脚本..."
|
|
|
|
local scripts_dir="$HOME/backup-scripts"
|
|
mkdir -p "$scripts_dir"
|
|
|
|
# 主备份脚本
|
|
cat > "$scripts_dir/backup-system.sh" << 'EOF'
|
|
#!/bin/bash
|
|
# BorgBackup 系统备份脚本
|
|
|
|
set -e
|
|
|
|
# 配置
|
|
BACKUP_NAME="$(hostname)-system"
|
|
LOCAL_REPO="$HOME/borg-repo"
|
|
LOG_FILE="$HOME/backup-scripts/backup.log"
|
|
CONFIG_FILE="$HOME/backup-scripts/backup.conf"
|
|
|
|
# 加载配置
|
|
if [ -f "$CONFIG_FILE" ]; then
|
|
source "$CONFIG_FILE"
|
|
fi
|
|
|
|
# 颜色
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
log() { echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"; }
|
|
|
|
# 初始化仓库
|
|
init_repo() {
|
|
if [ ! -d "$LOCAL_REPO" ]; then
|
|
log "初始化 Borg 仓库..."
|
|
borg init --encryption=repokey-blake2 "$LOCAL_REPO" 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
# 执行备份
|
|
create_backup() {
|
|
local archive_name="$BACKUP_NAME-$(date +%Y%m%d-%H%M%S)"
|
|
|
|
log "创建备份: $archive_name"
|
|
|
|
sudo borg create \
|
|
--compression lz4 \
|
|
--stats \
|
|
--progress \
|
|
--exclude-caches \
|
|
--exclude '/var/cache/*' \
|
|
--exclude '/var/tmp/*' \
|
|
--exclude '/tmp/*' \
|
|
--exclude '/proc/*' \
|
|
--exclude '/sys/*' \
|
|
--exclude '/dev/*' \
|
|
--exclude '/mnt/*' \
|
|
--exclude '/media/*' \
|
|
--exclude '/run/*' \
|
|
--exclude '/boot/*' \
|
|
--exclude '/lost+found' \
|
|
--exclude '*.pyc' \
|
|
--exclude '*.swap' \
|
|
--exclude '*.tmp' \
|
|
"$LOCAL_REPO::$archive_name" \
|
|
/ 2>&1 | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# 清理旧备份
|
|
prune_backups() {
|
|
log "清理旧备份..."
|
|
|
|
borg prune --list --stats \
|
|
--keep-daily=7 \
|
|
--keep-weekly=4 \
|
|
--keep-monthly=3 \
|
|
"$LOCAL_REPO" 2>&1 | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# 同步到远程
|
|
sync_to_remote() {
|
|
if [ -n "$REMOTE_CONFIG" ]; then
|
|
log "同步到远程存储: $REMOTE_CONFIG"
|
|
rclone sync "$LOCAL_REPO" "$REMOTE_CONFIG" --progress 2>&1 | tee -a "$LOG_FILE"
|
|
fi
|
|
}
|
|
|
|
# 主函数
|
|
main() {
|
|
log "=== 开始备份任务 ==="
|
|
|
|
init_repo
|
|
create_backup
|
|
prune_backups
|
|
sync_to_remote
|
|
|
|
log "=== 备份任务完成 ==="
|
|
}
|
|
|
|
main "$@"
|
|
EOF
|
|
|
|
# 如果配置了远程存储,更新配置文件
|
|
if [ "$REMOTE_CONFIGURED" = "1" ]; then
|
|
echo "REMOTE_CONFIG=\"$CONFIGURED_REMOTE:backups/$(hostname)\"" > "$scripts_dir/backup.conf"
|
|
fi
|
|
|
|
chmod +x "$scripts_dir/backup-system.sh"
|
|
log "备份脚本创建完成: $scripts_dir/backup-system.sh"
|
|
}
|
|
|
|
# 显示总结信息
|
|
show_summary() {
|
|
echo
|
|
echo "=== 安装完成 ==="
|
|
echo -e "${GREEN}✓ BorgBackup 已安装${NC}"
|
|
echo -e "${GREEN}✓ rclone 已安装${NC}"
|
|
|
|
if [ "$REMOTE_CONFIGURED" = "1" ]; then
|
|
echo -e "${GREEN}✓ 远程存储已配置: $CONFIGURED_REMOTE${NC}"
|
|
else
|
|
echo -e "${YELLOW}⚠ 未配置远程存储(仅本地备份)${NC}"
|
|
fi
|
|
|
|
echo
|
|
echo "=== 下一步操作 ==="
|
|
echo "1. 首次备份: ~/backup-scripts/backup-system.sh"
|
|
echo "2. 设置定时任务: crontab -e"
|
|
echo "3. 查看备份: borg list ~/borg-repo"
|
|
|
|
if [ "$REMOTE_CONFIGURED" = "1" ]; then
|
|
echo "4. 查看远程备份: rclone lsd $CONFIGURED_REMOTE:"
|
|
fi
|
|
|
|
echo
|
|
echo "=== 重要提醒 ==="
|
|
echo "• 备份 Borg 密钥: ~/borg-repo/keyfile"
|
|
echo "• 定期测试恢复功能"
|
|
echo "• 监控备份日志: ~/backup-scripts/backup.log"
|
|
}
|
|
|
|
# 主函数
|
|
main() {
|
|
clear
|
|
echo -e "${BLUE}"
|
|
echo "╔══════════════════════════════════════╗"
|
|
echo "║ BorgBackup 智能安装脚本 ║"
|
|
echo "║ 适用于多平台系统备份 ║"
|
|
echo "╚══════════════════════════════════════╝"
|
|
echo -e "${NC}"
|
|
|
|
# 检查 root 权限
|
|
if [ "$EUID" -eq 0 ]; then
|
|
warn "不建议使用 root 用户运行此脚本"
|
|
read -p "是否继续? (y/N): " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
error "请使用普通用户运行"
|
|
fi
|
|
fi
|
|
|
|
# 执行安装步骤
|
|
check_system
|
|
install_dependencies
|
|
install_borg
|
|
install_rclone
|
|
configure_rclone
|
|
create_backup_scripts
|
|
show_summary
|
|
}
|
|
|
|
# 运行主函数
|
|
main "$@"
|