共计 6613 个字符,预计需要花费 17 分钟才能阅读完成。

在服务器运维过程中,数据安全永远是第一位的。哪怕你技术再牛,也挡不住手一滑删了系统文件,或者硬盘突然罢工。所以,定期备份系统,是每个运维人员必须掌握的基本技能。
然后俺就让AI写了个脚本,它可以自动帮你做系统备份,还能把备份文件上传到阿里云盘,让你的数据更安全,也更方便恢复。
一、这个脚本能干啥?
这个脚本其实就是一个 .sh
文件,运行起来后可以帮你完成以下几件事:
- 增量备份系统文件(只备份变化的部分,节省空间)
- 打包压缩备份数据(生成
.tar.gz
文件) - 上传到远程服务器(比如你家里的 NAS 或者另一台 VPS)
- 上传到阿里云盘(自动备份到云端)
- 自动清理旧备份(默认保留 7 天以内的备份)
二、脚本使用前的准备(建议使用root权限账号)
1. 安装必要工具
首先,你需要确保你的 Linux 系统已经安装了以下工具(rsync
用于高效同步文件,tar
用于打包文件,gzip
用于压缩文件,pv
用于实时查看管道中数据传输进度。):
sudo apt update
sudo apt install -y rsync tar gzip pv
如果你用的是 CentOS 或者 RedHat,换成:
sudo yum install -y rsync tar gzip pv
2. 创建备份目录
脚本默认会把备份文件存在 /sys-backup
目录下,你可以手动创建一下:
sudo mkdir -p /sys-backup/{rsyncback,backups,log}
三、安装和配置阿里云盘 CLI
这个脚本还支持把备份上传到阿里云盘,所以你得先装一个叫 aliyunpan
的命令行工具。
1. 下载安装
你可以从 GitHub 下载这个工具:
apt安装,适用于apt包管理器的系统,例如Ubuntu,国产deepin深度操作系统等。目前只支持amd64和arm64架构的机器,下面大概意思就是添加公钥,配置源,安装
sudo curl -fsSL http://file.tickstep.com/apt/pgp | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/tickstep-packages-archive-keyring.gpg > /dev/null && echo "deb [signed-by=/etc/apt/trusted.gpg.d/tickstep-packages-archive-keyring.gpg arch=amd64,arm64] http://file.tickstep.com/apt aliyunpan main" | sudo tee /etc/apt/sources.list.d/tickstep-aliyunpan.list > /dev/null && sudo apt-get update && sudo apt-get install -y aliyunpan
然后测试一下是否安装成功:
aliyunpan --version
2. 绑定阿里云账号
运行下面这个命令,会让你登录阿里云账号:
aliyunpan login
它会提示你打开一个链接,在浏览器中扫码登录,然后输入验证码。登录成功后,你的 Token 会被保存下来,以后上传文件就不用再登录了。
四、脚本怎么用?
1. 创建脚本文件
#!/bin/bash
set -e
# ===== 配置部分 =====
BACKUP_ROOT="/sys-backup"
RSYNC_DIR="${BACKUP_ROOT}/rsyncback"
TAR_DIR="${BACKUP_ROOT}/backups"
LOG_DIR="${BACKUP_ROOT}/log"
LOG_FILE="${LOG_DIR}/backup.log"
# 远程服务器配置(可选)
REMOTE_SERVER="" # "user@your.remote.server.com"
REMOTE_BACKUP_DIR="/backup"
# 阿里云盘配置
ALIYUN_REMOTE_DIR="/系统备份"
# 先创建必要目录(不重定向输出)
mkdir -p "${RSYNC_DIR}" "${TAR_DIR}" "${LOG_DIR}"
# 确保日志文件存在
touch "${LOG_FILE}"
# 获取服务器 IP
SERVER_IP=$(hostname -I | awk '{print $1}')
DATE=$(date +%Y%m%d-%H%M%S)
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "${LOG_FILE}"
# 显示进度信息到终端
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 安装进度条工具
install_pv() {
if ! command -v pv &> /dev/null; then
echo "正在安装进度条工具 pv..."
if command -v apt &> /dev/null; then
apt update && apt install -y pv
elif command -v yum &> /dev/null; then
yum install -y pv
else
echo "无法自动安装pv。请手动安装: apt install pv 或 yum install pv"
return 1
fi
fi
return 0
}
# rsync 增量备份
do_incremental_backup() {
local INC_DIR="${BACKUP_ROOT}/.rsync-inc"
log "开始增量备份..."
# 清理旧临时目录
if [ -d "${INC_DIR}" ]; then
rm -rf "${INC_DIR}" &>> "${LOG_FILE}"
fi
mkdir -p "${INC_DIR}" &>> "${LOG_FILE}"
# 定义排除路径
local EXCLUDES=(
"/proc" "/sys" "/lost+found" "/mnt" "/media" "/run" "/tmp"
"/sys-backup" "/*.usr-is-merged" "/patch"
)
# 构建 rsync 排除参数
local RSYNC_EXCLUDE_ARGS=()
for path in "${EXCLUDES[@]}"; do
RSYNC_EXCLUDE_ARGS+=( --exclude="$path" )
done
# 执行 rsync 增量备份
if [ "$(ls -A "${RSYNC_DIR}")" ]; then
log "执行增量备份到临时目录..."
rsync -ah --info=progress2 --numeric-ids --delete \
"${RSYNC_EXCLUDE_ARGS[@]}" \
--link-dest="${RSYNC_DIR}" \
/ "${INC_DIR}/" 2>&1
RSYNC_STATUS=${PIPESTATUS[0]}
else
log "首次备份,进行全量复制"
rsync -ah --info=progress2 --numeric-ids --delete \
"${RSYNC_EXCLUDE_ARGS[@]}" \
/ "${INC_DIR}/" 2>&1
RSYNC_STATUS=${PIPESTATUS[0]}
fi
if [ $RSYNC_STATUS -eq 0 ]; then
log "第一阶段备份完成"
else
log "rsync 失败,状态码: $RSYNC_STATUS"
return 1
fi
# 合并到主备份目录
log "合并到主备份目录..."
rsync -ah --info=progress2 --delete "${INC_DIR}/" "${RSYNC_DIR}/" 2>&1
RSYNC2_STATUS=${PIPESTATUS[0]}
if [ $RSYNC2_STATUS -eq 0 ]; then
log "合并完成"
else
log "合并失败,状态码: $RSYNC2_STATUS"
return 1
fi
rm -rf "${INC_DIR}" &>> "${LOG_FILE}"
log "增量备份完成"
}
do_tar_backup() {
local TAR_BASE="system_backup_${SERVER_IP}_${DATE}"
local TAR_NAME="${TAR_DIR}/${TAR_BASE}.tar.gz"
log "开始打包备份..."
log "备份路径: ${RSYNC_DIR}"
log "输出文件: ${TAR_NAME}"
# 获取目录大小
BACKUP_SIZE=$(du -sb "${RSYNC_DIR}" | awk '{print $1}')
echo "目录大小:$(numfmt --to=iec $BACKUP_SIZE 2>/dev/null || echo "$BACKUP_SIZE bytes")"
echo "正在打包,请等待进度条完成..."
# 一步到位:tar + pv + gzip
tar cf - -C "${RSYNC_DIR}" . | \
pv -s "$BACKUP_SIZE" -N "打包中" --wait | \
gzip > "${TAR_NAME}"
TAR_STATUS=${PIPESTATUS[0]}
if [ $TAR_STATUS -ne 0 ]; then
log "打包失败,状态码: $TAR_STATUS"
return 1
fi
# 检查文件是否存在
if [[ -f "$TAR_NAME" ]]; then
TAR_SIZE=$(du -h "$TAR_NAME" | awk '{print $1}')
log "打包完成: ${TAR_NAME} (大小: $TAR_SIZE)"
else
log "错误:打包完成但文件不存在: $TAR_NAME"
return 1
fi
}
# 上传到远程服务器
do_upload_to_remote() {
if [ -z "${REMOTE_SERVER}" ]; then
log "未配置远程服务器,跳过上传"
return 0
fi
local LATEST_TAR=$(ls -t "${TAR_DIR}/system_backup_${SERVER_IP}_*.tar.gz" 2>/dev/null | head -n1)
if [ -z "${LATEST_TAR}" ]; then
log "没有可上传的 tar 文件"
return 1
fi
log "开始上传到远程服务器: ${REMOTE_SERVER}:${REMOTE_BACKUP_DIR}"
if command -v pv &> /dev/null; then
TAR_SIZE=$(du -sb "${LATEST_TAR}" | cut -f1)
echo "文件大小:$(numfmt --to=iec $TAR_SIZE 2>/dev/null || echo "$TAR_SIZE bytes")"
pv "${LATEST_TAR}" | ssh "${REMOTE_SERVER}" "cat > ${REMOTE_BACKUP_DIR}/$(basename "${LATEST_TAR}")"
UPLOAD_STATUS=${PIPESTATUS[0]}
else
scp -v "${LATEST_TAR}" "${REMOTE_SERVER}:${REMOTE_BACKUP_DIR}/" 2>&1 | tee -a "${LOG_FILE}"
UPLOAD_STATUS=$?
fi
if [ $UPLOAD_STATUS -eq 0 ]; then
log "上传完成"
else
log "上传失败,状态码: $UPLOAD_STATUS"
return 1
fi
return 0
}
# 上传到阿里云盘
do_upload_to_aliyunpan() {
echo "${TAR_DIR}"
ls -l ${TAR_DIR}/system_backup_${SERVER_IP}_*.tar.gz
local LATEST_TAR=$(ls -t ${TAR_DIR}/system_backup_${SERVER_IP}_*.tar.gz 2>/dev/null | head -n1)
if [ -z "${LATEST_TAR}" ]; then
log "没有可上传的 tar 文件"
return 1
fi
# 检查aliyunpan命令是否存在
if ! command -v aliyunpan &> /dev/null; then
log "阿里云盘客户端未安装,跳过上传"
return 1
fi
log "开始上传到阿里云盘: ${LATEST_TAR}"
aliyunpan upload "${LATEST_TAR}" "${ALIYUN_REMOTE_DIR}"
log "阿里云盘上传任务已启动"
return 0
}
# 清理旧备份
do_cleanup() {
log "清理 7 天前的 tar 文件"
find "${TAR_DIR}" -type f -name "system_backup_${SERVER_IP}_*.tgz" -mtime +7 -exec rm -f {} \; &>> "${LOG_FILE}"
return 0
}
# ===== 主逻辑 =====
if [ $# -ne 1 ]; then
echo "用法: $0 [incr|tar|upload|clean|all]" | tee -a "${LOG_FILE}"
exit 1
fi
case "$1" in
incr)
do_incremental_backup
;;
tar)
do_tar_backup
;;
upload)
do_upload_to_remote
do_upload_to_aliyunpan
;;
clean)
do_cleanup
;;
all)
do_incremental_backup
do_tar_backup
do_upload_to_remote
do_upload_to_aliyunpan
do_cleanup
;;
*)
echo "无效模式: $1" | tee -a "${LOG_FILE}"
echo "用法: $0 [incr|tar|upload|clean|all]" | tee -a "${LOG_FILE}"
exit 1
;;
esac
log "任务完成: $1"
你可以把脚本保存成一个文件,比如叫 backup.sh
,然后给它执行权限:
chmod +x backup.sh
2. 修改配置
打开脚本,找到开头的配置部分,根据你的实际情况修改:
REMOTE_SERVER="user@your.remote.server.com" # 远程服务器地址(可选)
REMOTE_BACKUP_DIR="/backup" # 远程服务器备份路径
ALIYUN_REMOTE_DIR="/系统备份" # 阿里云盘上的备份目录
如果你不想上传到远程服务器,就把 REMOTE_SERVER
设置为空。
五、运行脚本 ps:阿里云盘有时候上传很慢,具体我也不知道什么情况
脚本支持几种不同的运行模式:
./backup.sh incr # 只做增量备份
./backup.sh tar # 只打包备份
./backup.sh upload # 只上传备份
./backup.sh clean # 清理旧备份
./backup.sh all # 执行全部操作:增量备份 + 打包 + 上传 + 清理
建议你第一次运行用 all
模式,这样会完整跑一遍流程,看看有没有报错。
六、设置定时备份 ps:自动执行,也可以手动执行,根据你的情况来
为了避免手动执行,我们可以用 Linux 的定时任务工具 cron
来每天自动备份,-不建议
运行下面命令打开定时任务编辑器:
crontab -e
添加一行内容(比如每天凌晨 2 点执行):
0 2 * * * /path/to/backup.sh all >> /sys-backup/log/backup_cron.log 2>&1
这样,每天早上 2 点系统就会自动执行备份,把日志写进 /sys-backup/log/backup_cron.log
七、注意事项
- 权限问题:确保脚本能读取系统文件,尤其是
/
目录下的内容。 - 排除目录:脚本默认排除了
/proc
、/sys
、/tmp
这些目录,避免备份无用数据。 - 阿里云盘路径:上传前请确保阿里云盘上有
/系统备份
这个目录,否则会上传失败。 - 日志查看:如果备份失败,可以查看
/sys-backup/log/backup.log
,里面有详细的错误信息。 - 磁盘空间:增量备份虽然节省空间,但也要注意
/sys-backup
所在分区的容量。
八、结语
这个脚本虽然看起来有点复杂,但其实只要配置一次,就能长期帮你自动备份系统,还能上传到阿里云盘,非常实用。对于个人服务器、小公司运维来说,是一个性价比很高的解决方案。
如果有更好的方式方法,欢迎大佬们交流指导