服务器自动备份方案:用 rsync + cron 实现异地增量备份
服务器自动备份方案用 rsync cron 实现异地增量备份服务器数据丢失是小概率但高代价的事故。硬盘故障、误操作rm -rf、系统被黑客清空……这些情况听起来离你很远但真发生了就是几个月甚至几年的工作付之一炬。备份不是有了更好是没有迟早后悔。这篇文章介绍一套实用的自动备份方案用rsync做增量同步用cron定时触发把数据异地备份到另一台服务器。整个方案不依赖第三方服务成本低可控性强。备份策略设计先想清楚要备份什么、备份多久、保留多少份备份类型频率保留时长数据库每天一次保留 30 天应用配置每天一次保留 30 天用户上传文件每天一次保留 7 天完整系统快照每周一次保留 4 周最低成本的异地备份方案是再准备一台小服务器专门用来存备份。我在雨云服务器 rainyun.com开了一台 1 核 1G、50GB 硬盘的机器专门放备份数据按月付价格很低。雨云的性价比在这种场景下特别合适——备份机不需要高性能只需要存储空间大、网络稳定。新用户注册填优惠码2026off可以领 5 折优惠券一台备份机的月费低到可以忽略不计但能给你的主服务器数据提供有效保障。准备工作主服务器被备份的那台创建专用备份用户adduser backup --disabled-password--gecos备份服务器同样创建对应用户adduser backup --disabled-password--gecosmkdir-p/backup/server-mainchownbackup:backup /backup/server-main配置 SSH 免密登录在主服务器上以 backup 用户身份生成 SSH 密钥su- backup ssh-keygen-ted25519-Cbackupmain-server-N-f~/.ssh/id_backup把公钥复制到备份服务器ssh-copy-id-i~/.ssh/id_backup.pub backup备份服务器IP测试连接ssh-i~/.ssh/id_backup backup备份服务器IPecho连接成功编写备份脚本创建数据库备份脚本sudomkdir-p/opt/backup/scriptssudotee/opt/backup/scripts/backup-mysql.shEOF #!/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_DAYS30 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 StrictHostKeyCheckingno \ $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 EOFsudochmodx /opt/backup/scripts/backup-mysql.sh创建文件备份脚本sudotee/opt/backup/scripts/backup-files.shEOF #!/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 \ --excludenode_modules \ --exclude.git \ -e ssh -i /home/backup/.ssh/id_backup -o StrictHostKeyCheckingno \ $DIR \ backup${REMOTE_HOST}:${REMOTE_DIR}/ \ $LOG_FILE 21 fi done echo 备份结束: $(date) $LOG_FILE EOFsudochmodx /opt/backup/scripts/backup-files.sh配置 cron 定时任务以 root 身份编辑 crontabsudocrontab-e添加以下任务# 每天凌晨 2 点备份数据库02* * *MYSQL_PASS你的MySQL密码/opt/backup/scripts/backup-mysql.sh/var/log/backup-mysql.log21# 每天凌晨 3 点备份文件03* * * /opt/backup/scripts/backup-files.sh# 每周日凌晨 4 点做一次完整打包可选04* *0/opt/backup/scripts/backup-weekly.sh验证备份效果手动运行一次脚本测试sudoMYSQL_PASS你的密码/opt/backup/scripts/backup-mysql.shsudo/opt/backup/scripts/backup-files.sh登录备份服务器确认文件是否到位sshbackup备份服务器IPls-lh/backup/server-main/databases/检查日志tail-50/var/log/backup-mysql.logtail-50/var/log/backup-files.log进阶带保留策略的增量备份rsync加上--link-dest参数可以实现快照式备份——每次都是完整备份的样子但实际上用硬链接节省空间没变化的文件不占额外存储。#!/bin/bashDATE$(date%Y%m%d)REMOTE_HOST备份服务器IPSNAPSHOT_DIR/backup/server-main/snapshotsLATEST_LINK${SNAPSHOT_DIR}/latestssh-i/home/backup/.ssh/id_backup backup${REMOTE_HOST}\mkdir -p${SNAPSHOT_DIR}/${DATE}rsync-avz\--delete\--link-dest${LATEST_LINK}\-essh -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 {} \;这样每天的快照独立存在可以回滚到任意一天的状态实际占用空间只比单次备份多一点点。备份监控可选建议加一个简单的备份成功通知。最简单的方式是在脚本末尾发送邮件# 安装发件工具sudoaptinstall-ymsmtp msmtp-mta# 在脚本末尾加echo备份完成$(date)|mail-s服务器备份报告你的邮箱example.com或者用 curl 发 webhook 到你的通知渠道Bark、钉钉、企业微信等curl-shttps://api.day.app/你的Key/备份成功/$(date%Y%m%d)异地备份搭起来之后基本是无感运行的。定期检查一下日志和备份服务器的文件大小确认备份在正常进行。真正到需要用的那天有备份和没备份的差别就是能不能快速恢复。