
服务器数据无价,无论是网站、数据库还是 Docker 容器数据,一旦丢失后果不堪设想。本文介绍最经典的 Linux 服务器间数据备份方案——rsync + cron,实现增量自动备份到远程服务器。
rsync(remote synchronize)是 Linux 下最强大的数据同步工具,核心优势:
192.168.1.100 | ||
192.168.1.200 |
两台机器都需要安装 rsync,大多数 Linux 发行版已预装。
我们使用莱卡云VPS来演示需要vps的可以看以下信息,莱卡云官网https://www.lcayun.com/aff/PQCSKOCK
源服务器A ──── rsync over SSH ────→ 目标服务器B/data/app/ /backup/app/ │ │ └──── cron 定时触发 ────────────────┘💡 核心优势:rsync 增量传输只同步变化部分,对带宽和网络压力极小,适合长期稳定运行。
# Debian/Ubuntuapt update && apt install -y rsync# CentOS/RHEL/AlmaLinuxyum install -y rsync# Arch Linuxpacman -S rsyncrsync --version# rsync version 3.2.7 protocol version 31备份是自动化任务,不能每次都手动输密码,所以先配好 SSH 密钥认证。
# 如果已有密钥可跳过ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519# 默认22端口ssh-copy-id root@192.168.1.200# 自定义端口(如7722)ssh-copy-id -p 7722 root@192.168.1.200# 应该直接登录成功,不需要输入密码ssh root@192.168.1.200 "echo connected"# 自定义端口ssh -p 7722 root@192.168.1.200 "echo connected"⚠️ 如果使用了自定义端口,后续所有 rsync 命令都需要加
-e "ssh -p 端口"参数。
如果还是无法免密登录,可能是没有开启秘钥登录我们配置下即可
grep -i "PubkeyAuthentication" /etc/ssh/sshd_configPubkeyAuthentication noPubkeyAuthentication是no就代表没有开启秘钥登录
我们修改成yes即可
vim /etc/ssh/sshd_config........PubkeyAuthentication yes........然后重启ssh服务即可
systemctl restart ssh# 在服务器 B 上执行mkdir -p /backup/appmkdir -p /backup/mysqlmkdir -p /backup/dockerrsync [选项] 源路径 目标路径-a | |
-v | |
-z | |
-P | |
--delete | |
--exclude | |
-e |
# 把服务器A的 /data/app 目录同步到服务器B的 /backup/apprsync -avz --delete /data/app/ root@192.168.1.200:/backup/app/🔔 注意尾随斜杠:
• /data/app/(有斜杠)= 同步 app 目录里的内容• /data/app(无斜杠)= 同步 app 目录本身备份场景建议加尾随斜杠。
rsync -avz --delete -e "ssh -p 7722" /data/app/ root@192.168.1.200:/backup/app/# 排除日志和临时文件rsync -avz --delete \ --exclude='*.log' \ --exclude='tmp/' \ --exclude='.cache/' \ /data/app/ root@192.168.1.200:/backup/app/# 创建排除规则文件cat > /etc/rsync-exclude.txt << 'EOF'*.log*.tmptmp/.cache/node_modules/*.pidEOF# 使用 --exclude-from 引用rsync -avz --delete --exclude-from='/etc/rsync-exclude.txt' \ /data/app/ root@192.168.1.200:/backup/app/rsync -avz --delete \ --exclude='*.log' \ --exclude='.git/' \ /www/wwwroot/mysite/ \ root@192.168.1.200:/backup/mysite/rsync -avz --delete \ --exclude='*.log' \ /var/lib/docker/volumes/ \ root@192.168.1.200:/backup/docker-volumes/# 先导出MySQL数据库mysqldump -u root -p'你的密码' --all-databases > /tmp/all_db.sql# 再同步到远程rsync -avz /tmp/all_db.sql root@192.168.1.200:/backup/mysql/# 先用SQLite的.backup命令安全备份(比直接复制更安全)sqlite3 /data/app/onenav.db3 ".backup '/tmp/onenav_backup.db3'"# 同步到远程rsync -avz /tmp/onenav_backup.db3 root@192.168.1.200:/backup/db/cat > /root/backup.sh << 'BACKUP_EOF'#!/bin/bash# ===== 配置区域 =====REMOTE_IP="192.168.1.200"REMOTE_PORT="22"REMOTE_USER="root"BACKUP_DIR="/backup"# 备份任务列表(源路径:目标子目录名)TASKS=( "/www/wwwroot/mysite/:mysite" "/data/docker/:docker" "/root/scripts/:scripts")# 日志文件LOG_FILE="/var/log/backup.log"# ===== 执行区域 =====echo "========================================" >> $LOG_FILEecho "备份开始: $(date '+%Y-%m-%d %H:%M:%S')" >> $LOG_FILEfor TASK in "${TASKS[@]}"; do SRC="${TASK%%:*}" DST="${TASK##*:}" echo ">>> 同步 $SRC -> $REMOTE_IP:$BACKUP_DIR/$DST" >> $LOG_FILE rsync -avz --delete \ --exclude='*.log' \ --exclude='.git/' \ --exclude='*.tmp' \ --exclude='.cache/' \ -e "ssh -p $REMOTE_PORT" \ "$SRC" "$REMOTE_USER@$REMOTE_IP:$BACKUP_DIR/$DST/" >> $LOG_FILE 2>&1 if [ $? -eq 0 ]; then echo "✅ $DST 备份成功" >> $LOG_FILE else echo "❌ $DST 备份失败" >> $LOG_FILE fidoneecho "备份结束: $(date '+%Y-%m-%d %H:%M:%S')" >> $LOG_FILEecho "" >> $LOG_FILEBACKUP_EOFchmod +x /root/backup.shcrontab -e添加以下内容:
# 每天凌晨3点执行备份0 3 * * * /root/backup.sh# 如果想每12小时备份一次0 */12 * * * /root/backup.sh# 如果想每小时备份一次(高频场景)0 * * * * /root/backup.shcrontab -l┌──────── 分钟 (0-59)│ ┌────── 小时 (0-23)│ │ ┌──── 日 (1-31)│ │ │ ┌── 月 (1-12)│ │ │ │ ┌ 星期 (0-7, 0和7都是周日)│ │ │ │ │* * * * * 命令0 3 * * * | |
0 */6 * * * | |
0 3 * * 1 | |
0 0 1 * * | |
*/30 * * * * |
tail -50 /var/log/backup.logcat > /etc/logrotate.d/backup << 'EOF'/var/log/backup.log { weekly rotate 4 compress missingok notifempty create}EOF在 backup.sh 末尾加上通知,通过 Telegram Bot 推送:
# 在 backup.sh 的末尾添加SUCCESS_COUNT=$(grep "✅" $LOG_FILE | tail -${#TASKS[@]} | wc -l)FAIL_COUNT=$(grep "❌" $LOG_FILE | tail -${#TASKS[@]} | wc -l)MESSAGE="📋 备份报告时间: $(date '+%Y-%m-%d %H:%M:%S')成功: ${SUCCESS_COUNT} / ${#TASKS[@]}失败: ${FAIL_COUNT} / ${#TASKS[@]}"# Telegram推送(替换为你的Bot Token和Chat ID)curl -s -X POST "https://api.telegram.org/bot你的TOKEN/sendMessage" \ -d "chat_id=你的CHAT_ID" \ -d "text=$MESSAGE"如果只为 rsync 使用,可以在服务器 B 的 ~/.ssh/authorized_keys 中限制来源 IP 和命令:
# 编辑服务器B的 authorized_keysfrom="192.168.1.100",command="rsync --server" ssh-ed25519 AAAA...公钥内容...这样即使密钥泄露,也只能从指定 IP 执行 rsync 命令。
# 服务器B只允许服务器A的SSH连接iptables -A INPUT -p tcp --dport 22 -s 192.168.1.100 -j ACCEPTiptables -A INPUT -p tcp --dport 22 -j DROP备份的意义在于能恢复。从目标服务器 B 恢复数据到源服务器 A:
# 反向同步(从B拉取到A)rsync -avz root@192.168.1.200:/backup/app/ /data/app/# 或者在服务器B上推送(推送到A)rsync -avz /backup/app/ root@192.168.1.100:/data/app/⚠️ 恢复时不要加
--delete,除非你确定要完全覆盖。
定期验证备份是否能用:
# 在服务器B上检查备份文件ls -la /backup/app/du -sh /backup/app/find /backup/app/ -type f | wc -l# 对比文件数量find /data/app/ -type f | wc -l