服务器自动备份方案:用 rsync + cron 实现异地增量备份

服务器自动备份方案:用 rsync + cron 实现异地增量备份

服务器数据丢失是小概率但高代价的事故。硬盘故障、误操作 rm -rf、系统被黑客清空......这些情况听起来离你很远,但真发生了就是几个月甚至几年的工作付之一炬。备份不是"有了更好",是"没有迟早后悔"。

这篇文章介绍一套实用的自动备份方案:用 rsync 做增量同步,用 cron 定时触发,把数据异地备份到另一台服务器。整个方案不依赖第三方服务,成本低,可控性强。

备份策略设计

先想清楚要备份什么、备份多久、保留多少份:

备份类型 频率 保留时长
数据库 每天一次 保留 30 天
应用配置 每天一次 保留 30 天
用户上传文件 每天一次 保留 7 天
完整系统快照 每周一次 保留 4 周

最低成本的异地备份方案是再准备一台小服务器专门用来存备份。我在 雨云服务器 rainyun.com 开了一台 1 核 1G、50GB 硬盘的机器专门放备份数据,按月付,价格很低。雨云的性价比在这种场景下特别合适------备份机不需要高性能,只需要存储空间大、网络稳定。新用户注册填优惠码 2026off 可以领 5 折优惠券,一台备份机的月费低到可以忽略不计,但能给你的主服务器数据提供有效保障。

准备工作

主服务器(被备份的那台)

创建专用备份用户:

bash 复制代码
adduser backup --disabled-password --gecos ""

备份服务器

同样创建对应用户:

bash 复制代码
adduser backup --disabled-password --gecos ""
mkdir -p /backup/server-main
chown backup:backup /backup/server-main

配置 SSH 免密登录

在主服务器上,以 backup 用户身份生成 SSH 密钥:

bash 复制代码
su - backup
ssh-keygen -t ed25519 -C "backup@main-server" -N "" -f ~/.ssh/id_backup

把公钥复制到备份服务器:

bash 复制代码
ssh-copy-id -i ~/.ssh/id_backup.pub backup@备份服务器IP

测试连接:

bash 复制代码
ssh -i ~/.ssh/id_backup backup@备份服务器IP echo "连接成功"

编写备份脚本

创建数据库备份脚本:

bash 复制代码
sudo mkdir -p /opt/backup/scripts
sudo tee /opt/backup/scripts/backup-mysql.sh << 'EOF'
#!/bin/bash

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/tmp/db_backup"
REMOTE_HOST="备份服务器IP"
REMOTE_DIR="/backup/server-main/databases"
KEEP_DAYS=30

mkdir -p $BACKUP_DIR

# 备份所有数据库(排除系统库)
DATABASES=$(mysql -u root -p"$MYSQL_PASS" -e "SHOW DATABASES;" 2>/dev/null | grep -Ev "(Database|information_schema|performance_schema|sys|mysql)")

for DB in $DATABASES; do
    echo "备份数据库: $DB"
    mysqldump -u root -p"$MYSQL_PASS" \
        --single-transaction \
        --routines \
        --triggers \
        "$DB" 2>/dev/null | gzip > "$BACKUP_DIR/${DB}_${DATE}.sql.gz"
done

# rsync 到备份服务器
rsync -avz \
    -e "ssh -i /home/backup/.ssh/id_backup -o StrictHostKeyChecking=no" \
    "$BACKUP_DIR/" \
    "backup@${REMOTE_HOST}:${REMOTE_DIR}/"

# 清理本地临时文件
rm -rf $BACKUP_DIR

# 删除备份服务器上 30 天前的文件
ssh -i /home/backup/.ssh/id_backup backup@${REMOTE_HOST} \
    "find ${REMOTE_DIR}/ -name '*.sql.gz' -mtime +${KEEP_DAYS} -delete"

echo "数据库备份完成: $DATE"
EOF

sudo chmod +x /opt/backup/scripts/backup-mysql.sh

创建文件备份脚本:

bash 复制代码
sudo tee /opt/backup/scripts/backup-files.sh << 'EOF'
#!/bin/bash

REMOTE_HOST="备份服务器IP"
REMOTE_DIR="/backup/server-main/files"
LOG_FILE="/var/log/backup-files.log"

echo "=== 备份开始: $(date) ===" >> $LOG_FILE

# 需要备份的目录列表
BACKUP_DIRS=(
    "/etc"
    "/opt/myapp"
    "/var/www"
    "/home"
)

for DIR in "${BACKUP_DIRS[@]}"; do
    if [ -d "$DIR" ]; then
        echo "同步目录: $DIR" >> $LOG_FILE
        rsync -avz \
            --delete \
            --exclude="*.log" \
            --exclude="*.tmp" \
            --exclude="node_modules" \
            --exclude=".git" \
            -e "ssh -i /home/backup/.ssh/id_backup -o StrictHostKeyChecking=no" \
            "$DIR" \
            "backup@${REMOTE_HOST}:${REMOTE_DIR}/" \
            >> $LOG_FILE 2>&1
    fi
done

echo "=== 备份结束: $(date) ===" >> $LOG_FILE
EOF

sudo chmod +x /opt/backup/scripts/backup-files.sh

配置 cron 定时任务

以 root 身份编辑 crontab:

bash 复制代码
sudo crontab -e

添加以下任务:

bash 复制代码
# 每天凌晨 2 点备份数据库
0 2 * * * MYSQL_PASS="你的MySQL密码" /opt/backup/scripts/backup-mysql.sh >> /var/log/backup-mysql.log 2>&1

# 每天凌晨 3 点备份文件
0 3 * * * /opt/backup/scripts/backup-files.sh

# 每周日凌晨 4 点做一次完整打包(可选)
0 4 * * 0 /opt/backup/scripts/backup-weekly.sh

验证备份效果

手动运行一次脚本测试:

bash 复制代码
sudo MYSQL_PASS="你的密码" /opt/backup/scripts/backup-mysql.sh
sudo /opt/backup/scripts/backup-files.sh

登录备份服务器确认文件是否到位:

bash 复制代码
ssh backup@备份服务器IP ls -lh /backup/server-main/databases/

检查日志:

bash 复制代码
tail -50 /var/log/backup-mysql.log
tail -50 /var/log/backup-files.log

进阶:带保留策略的增量备份

rsync 加上 --link-dest 参数可以实现"快照式"备份------每次都是完整备份的样子,但实际上用硬链接节省空间,没变化的文件不占额外存储。

bash 复制代码
#!/bin/bash

DATE=$(date +%Y%m%d)
REMOTE_HOST="备份服务器IP"
SNAPSHOT_DIR="/backup/server-main/snapshots"
LATEST_LINK="${SNAPSHOT_DIR}/latest"

ssh -i /home/backup/.ssh/id_backup backup@${REMOTE_HOST} \
    "mkdir -p ${SNAPSHOT_DIR}/${DATE}"

rsync -avz \
    --delete \
    --link-dest="${LATEST_LINK}" \
    -e "ssh -i /home/backup/.ssh/id_backup" \
    /opt/myapp/ \
    "backup@${REMOTE_HOST}:${SNAPSHOT_DIR}/${DATE}/"

# 更新 latest 软链接
ssh -i /home/backup/.ssh/id_backup backup@${REMOTE_HOST} \
    "ln -sfn ${SNAPSHOT_DIR}/${DATE} ${LATEST_LINK}"

# 删除 7 天前的快照
ssh -i /home/backup/.ssh/id_backup backup@${REMOTE_HOST} \
    "find ${SNAPSHOT_DIR} -maxdepth 1 -name '20*' -mtime +7 -exec rm -rf {} \;"

这样每天的快照独立存在,可以回滚到任意一天的状态,实际占用空间只比单次备份多一点点。

备份监控(可选)

建议加一个简单的备份成功通知。最简单的方式是在脚本末尾发送邮件:

bash 复制代码
# 安装发件工具
sudo apt install -y msmtp msmtp-mta

# 在脚本末尾加
echo "备份完成 $(date)" | mail -s "服务器备份报告" 你的邮箱@example.com

或者用 curl 发 webhook 到你的通知渠道(Bark、钉钉、企业微信等):

bash 复制代码
curl -s "https://api.day.app/你的Key/备份成功/$(date +%Y%m%d)"

异地备份搭起来之后基本是"无感"运行的。定期检查一下日志和备份服务器的文件大小,确认备份在正常进行。真正到需要用的那天,有备份和没备份的差别就是能不能快速恢复。

相关推荐
HABuo10 小时前
【linux(四)】套接字编程--基于UDP协议的客户端服务端
linux·服务器·c++·网络协议·ubuntu·udp·centos
艾莉丝努力练剑10 小时前
【Linux网络】Linux 网络编程入门:UDP Socket 编程(下)
linux·运维·服务器·网络·计算机网络·安全·udp
qq_4523962317 小时前
第十五篇:《UI自动化中的稳定性优化:解决flaky tests的七种武器》
运维·ui·自动化
j_xxx404_17 小时前
Linux:静态链接与动态链接深度解析
linux·运维·服务器·c++·人工智能
墨风如雪18 小时前
别被“高价建站”劝退了!我跑了多年的 WordPress 架构,一年只花 $25.7
服务器
Elastic 中国社区官方博客18 小时前
Elastic-caveman : 在不损失 Elastic 最佳效果的情况下,将 AI 响应 tokens 减少64%
大数据·运维·数据库·人工智能·elasticsearch·搜索引擎·全文检索
云飞云共享云桌面18 小时前
东莞智能装备工厂数字化实践—研发部门10名SolidWorks设计共享一台云主机流畅设计
服务器·自动化·汽车·负载均衡·制造
专注API从业者19 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
xingyuzhisuan19 小时前
稳定性考验:连续跑7天,哪家云主机不重启、不掉线?
服务器·人工智能·gpu算力