本文目录导读:

设计一个既安全又可靠的日常备份脚本,核心在于:加密传输与存储、自动验证完整性、3-2-1备份策略、以及防御性编程。
安全是指数据不会被泄露或篡改(防止勒索软件同步备份、防止中间人攻击),可靠是指备份真正可用,而不是一堆损坏的文件。
以下是设计这样一个脚本的详细指南,包含核心原则、关键代码片段和完整模板。
核心原则(安全+可靠)
- 3-2-1 备份策略:至少 3 份副本(1份源+2份备份),存储在 2 种不同介质上(如本地硬盘+云存储),1 份在异地(不同城市/机房)。
- 加密(重中之重):备份数据必须端到端加密,且密钥与备份数据分开存放,推荐使用 GPG 或 age。
- 验证机制:备份完成后,必须自动验证(如校验 SHA256 哈希、测试解压或挂载)。
- 传输安全:远程传输使用 SSH over SFTP、Rsync over SSH 或 HTTPS,绝对避免明文 FTP。
- 幂等性与增量备份:设计脚本使其可以反复运行而不产生重复数据,使用
rsync或restic的增量特性。 - 防御性编程:脚本中必须有错误处理、日志记录、锁文件(防止并发)、以及失败告警。
推荐的技术栈
| 功能 | 推荐工具 | 理由 |
|---|---|---|
| 加密存储 | restic |
自带加密、去重、增量、云备份、验证功能,是目前最安全可靠的方案之一。 |
| 文件同步 | rsync |
增量、校验、可通过 SSH 加密传输,适合本地或纯文件同步。 |
| 加密文件 | age / gpg |
轻量级加密,age 更现代更易用。 |
| 完整性校验 | sha256sum |
标准工具,生成哈希文件。 |
| 通知告警 | curl + Telegram/Slack/邮件 |
实时反馈异常。 |
| 调度器 | systemd timer |
比 crontab 更可控,支持依赖、日志、资源限制。 |
建议:如果你的主要诉求是“安全+可靠”,强烈推荐直接使用 restic,它几乎解决了所有痛点,如果必须手动写 rsync,请参考后面的脚本模板。
完整脚本设计(基于 restic,最安全可靠)
以下脚本满足:增量备份、端到端加密、自动清理、完整性检查、错误告警。
环境准备
# 安装 restic wget -qO- https://github.com/restic/restic/releases/latest/download/restic_linux_amd64.bz2 | bzcat > /usr/local/bin/restic chmod +x /usr/local/bin/restic # 初始化仓库(执行一次) export RESTIC_REPOSITORY="/mnt/backup/my-backup" # 本地或远程路径 export RESTIC_PASSWORD="your-very-strong-password-here" # 加密密码,绝对不能写死!使用密钥文件 restic init
备份脚本 (/usr/local/bin/safe-backup.sh)
#!/bin/bash
set -euo pipefail # 严格模式:遇到错误立即退出,变量未定义时报错
# ---------- 配置区域(安全处理) ----------
# 使用密钥文件而不是环境变量,避免进程列表泄露密码
RESTIC_REPOSITORY="/mnt/backup/my-backup"
RESTIC_PASSWORD_FILE="/etc/restic/password.txt" # 权限为 600,只给 root 读
BACKUP_SOURCE="/var/www/html /home /etc"
EXCLUDE_FILE="/etc/restic/exclude.txt" # *.log, cache/
BACKUP_TAG="daily-auto"
LOG_FILE="/var/log/backup-daily.log"
LOCK_FILE="/tmp/backup-daily.lock"
# 通知配置(使用独立 API 密钥)
TELEGRAM_BOT_TOKEN="your-token"
TELEGRAM_CHAT_ID="your-chat-id"
# ---------- 防御性编程:单例模式 ----------
if [ -f "$LOCK_FILE" ]; then
echo "$(date): 另一个备份进程正在运行,跳过本次执行。" >> "$LOG_FILE"
exit 1
fi
trap 'rm -f "$LOCK_FILE"; exit' EXIT INT TERM
touch "$LOCK_FILE"
# ---------- 日志函数 ----------
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
send_alert() {
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d "chat_id=${TELEGRAM_CHAT_ID}" \
-d "text=⚠️ 备份失败: $1" > /dev/null
}
# ---------- 核心备份逻辑 ----------
log "开始备份: ${BACKUP_SOURCE}"
if restic backup \
--repo "$RESTIC_REPOSITORY" \
--password-file "$RESTIC_PASSWORD_FILE" \
--one-file-system \
--tag "$BACKUP_TAG" \
--exclude-file "$EXCLUDE_FILE" \
--verbose \
$BACKUP_SOURCE 2>&1 | tee -a "$LOG_FILE"; then
log "备份上传完成,开始验证..."
# 可靠性:检查最新快照是否可读
if restic check \
--repo "$RESTIC_REPOSITORY" \
--password-file "$RESTIC_PASSWORD_FILE" \
--read-data-subset=1% 2>&1 | tee -a "$LOG_FILE"; then
log "✅ 完整性验证通过"
else
log "❌ 完整性验证失败,数据可能损坏!"
send_alert "完整性验证失败,请立即检查仓库: ${RESTIC_REPOSITORY}"
exit 2
fi
# 清理策略:保留最近7天每天,最近4周每周,最近6个月每月,其余删除
log "执行清理策略..."
restic forget \
--repo "$RESTIC_REPOSITORY" \
--password-file "$RESTIC_PASSWORD_FILE" \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune 2>&1 | tee -a "$LOG_FILE"
log "✅ 备份成功完成"
else
log "❌ 备份执行失败"
send_alert "备份执行失败,日志在: ${LOG_FILE}"
exit 3 # 退出码 3 表示备份错误
fi
exit 0
如何运行
# 设置密钥文件(绝对安全) echo "your-very-strong-password-here" > /etc/restic/password.txt chmod 600 /etc/restic/password.txt chown root:root /etc/restic/password.txt # 授予执行权限 chmod +x /usr/local/bin/safe-backup.sh # 测试运行(手动) bash /usr/local/bin/safe-backup.sh
设置为定时任务 (推荐 systemd timer)
创建服务文件 /etc/systemd/system/backup-daily.service:
[Unit] Description=Daily Safe Backup After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/safe-backup.sh # 安全限制:禁止网络访问?根据需要调整 PrivateTmp=true ProtectSystem=full ReadWritePaths=/var/log
创建定时器文件 /etc/systemd/system/backup-daily.timer:
[Unit] Description=Daily Backup Timer Requires=backup-daily.service [Timer] OnCalendar=daily RandomizedDelaySec=1h # 随机延迟,避免所有任务同时启动 Persistent=true [Install] WantedBy=timers.target
激活定时器:
systemctl daemon-reload systemctl enable --now backup-daily.timer
如果必须使用 rsync(带加密的同步方案)
rsync 本身不加密,需要配合 SSH 或 GPG 使用,以下是一个安全+可靠的示例:
#!/bin/bash
set -euo pipefail
REMOTE_HOST="backup-server.example.com"
REMOTE_USER="backupuser"
LOCAL_SOURCE="/home/user/Documents"
REMOTE_DEST="/backup/incremental/"
SSH_PORT=2222 # 非默认端口
SNAPSHOT_DIR="/snapshots/backup_$(date +%Y%m%d_%H%M%S)"
LATEST_LINK="/snapshots/latest_backup"
# 1. 创建日期后缀的增量备份目录(硬链接方案,节省空间)
mkdir -p "$SNAPSHOT_DIR"
# 2. 使用 rsync 通过 SSH,启用压缩、校验、硬链接
rsync -avz \
--link-dest="$LATEST_LINK" \ # 与上次备份建立硬链接,节省空间但保持完整目录
--delete \ # 删除源中不再存在的文件
--chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r \
--log-file="/var/log/rsync_backup.log" \
-e "ssh -p ${SSH_PORT} -i /root/.ssh/backup_key" \
"$LOCAL_SOURCE" \
"${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DEST}${SNAPSHOT_DIR}/"
# 3. 更新最新链接
ssh -p "$SSH_PORT" -i /root/.ssh/backup_key "${REMOTE_USER}@${REMOTE_HOST}" \
"rm -f ${REMOTE_DEST}${LATEST_LINK}; ln -s ${SNAPSHOT_DIR} ${REMOTE_DEST}${LATEST_LINK}"
# 4. 验证:使用校验和的子集
echo "Verifying checksums..."
cd "$LOCAL_SOURCE"
find . -type f -name "*.txt" -exec sha256sum {} \; > /tmp/checksums_local.txt
ssh -p "$SSH_PORT" -i /root/.ssh/backup_key "${REMOTE_USER}@${REMOTE_HOST}" \
"cd ${REMOTE_DEST}${SNAPSHOT_DIR} && sha256sum -c /tmp/checksums_local.txt"
echo "✅ Checksum verification passed."
# 5. 清理:保留最近30天的快照
ssh -p "$SSH_PORT" -i /root/.ssh/backup_key "${REMOTE_USER}@${REMOTE_HOST}" \
"find ${REMOTE_DEST} -maxdepth 1 -type d -name 'backup_*' -mtime +30 -exec rm -rf {} \;"
注意:这种做法的安全性取决于 SSH 密钥的权限管理,如果远程服务器被入侵,所有数据都会暴露,因此强烈推荐使用 restic。
最佳实践总结
| 安全性措施 | 实现方式 |
|---|---|
| 加密 | 使用 restic 或 age/gpg 加密,密钥文件权限 600 |
| 传输加密 | SSH (SFTP)、Rsync over SSH、HTTPS |
| 防止篡改 | 定期对备份仓库执行 restic check 或 sha256sum |
| 防勒索软件 | 备份目标不能自动挂载且可写(使用 WORM 媒体或云对象存储不可变版本) |
| 防误删 | 配置 restic forget --keep-daily 7 自动清理,留有余地 |
| 记录审计 | 日志文件定期轮转,记录每次操作的退出码和时间 |
| 告警 | 失败后通过 Telegram/邮件/Webhook 通知,退出码用于监控系统(如 Prometheus) |
也是最重要的:定期进行恢复演练。 每季度至少一次从备份中恢复到一个临时环境并验证数据完整性,没有经过验证的备份,等于没有备份。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播