在异地机房之间保障业务连续性,核心难点不在于“能不能传文件”,而在于如何让两个物理位置相隔很远的服务器的数据保持准实时一致。宝塔面板本身没有直接叫“异地实时同步”的按钮,但我们可以利用它提供的软件管理、计划任务以及终端能力,把 rsync 与文件变更监听组合起来,搭出一套低延迟、可监控的同步机制。

一、同步方案的技术选型
做异地数据同步,常见思路有三种:第一是定时跑全量或增量备份,比如每天凌晨用 tar 打包再传;第二是用共享存储或分布式文件系统,例如 NFS 跨机房挂载;第三是基于变更事件的近实时同步,典型组合是 rsync + inotify。前两种要么延迟高,要么对网络质量和带宽要求苛刻,而第三种在普通云服务器之间最实用。
rsync 本身只解决“差量传输”,它比对源和目标文件的差异,只传改动块,带宽占用小。但它默认是被动触发,需要有人或脚本叫它跑。inotify 是 Linux 内核提供的文件系统事件监控接口,能在文件被修改、创建、删除时立刻发出通知。把两者结合,就能做到“文件一变,马上同步”。宝塔面板自带终端和计划任务,正好用来部署这套逻辑。
1.1 为什么不用纯计划任务
很多人习惯在宝塔里建一个每分钟执行一次的 rsync 计划任务。这种做法实现简单,但有两个问题:一是最小粒度是一分钟,期间丢失的写入可能来不及传;二是无变化时也空跑,浪费 CPU 和连接数。近实时场景更推荐事件驱动。
另外,异地机房往往有公网 IP 或弹性 IP,直接暴露 rsync 端口有安全风险。我们通过 SSH 隧道承载 rsync,既加密又省去开额外端口,宝塔终端配置一次即可长期使用。
二、前置准备与免密通道
假设源机房服务器 A(装了宝塔)IP 为 192.168.0.1,目标机房服务器 B IP 为 192.168.0.2。我们要让 A 把 /www/wwwroot 下的站点数据同步给 B 的 /backup/sync。首先在 A 上生成 SSH 密钥,并把公钥拷到 B,实现免交互登录。
这一步非常关键,因为后续的 inotify 脚本会在后台自动跑 rsync,如果每次都要输密码,同步会卡死。宝塔的“安全”和“SSH 管理”里可以限制 B 仅允许 A 的 IP 连入,降低风险。
2.1 生成并部署密钥
在 A 的宝塔终端执行以下命令,一路回车即可:
# 在源服务器 A 生成密钥,若已存在可跳过 ssh-keygen -t ed25519 -N '' -f /root/.ssh/id_ed25519 # 将公钥复制到目标服务器 B,按提示输入 B 的 root 密码 ssh-copy-id -i /root/.ssh/id_ed25519.pub root@192.168.0.2 # 测试免密登录是否成功 ssh root@192.168.0.2 'echo connected_ok'
如果最后一行输出 connected_ok,说明 A 到 B 的免密通道已经通了。注意目标 B 也要装好 rsync,大多数 Linux 发行版自带,若没有可用 yum 或 apt 装。
2.2 目录与权限对齐
在 B 上创建接收目录,并保证属主和权限不会让同步后的文件无法被 Web 服务读取:
# 在目标服务器 B 执行 mkdir -p /backup/sync chown -R www:www /backup/sync
这里把属主设成和宝塔一致的 www 用户,避免同步完之后 Nginx 或 PHP 没有权限访问。如果 A 上源目录属主也是 www,rsync 加 -a 参数就能保留。
三、编写 inotify 实时同步脚本
核心脚本放在 A 上,它用 inotifywait 监听目录,一旦有事件就调用 rsync 通过 SSH 推数据。inotify-tools 一般需手动装,宝塔终端里执行安装命令即可。
脚本要处理几个细节:避免重复触发导致堆积、忽略临时文件、记录日志便于排查。下面给出一个生产可用的例子。
3.1 安装依赖与脚本内容
先装 inotify 工具,再写脚本 /root/sync_realtime.sh:
# 安装 inotify-tools(CentOS 示例)
yum install -y inotify-tools rsync
# 编辑脚本
cat > /root/sync_realtime.sh <<'EOF'
#!/bin/bash
SRC=/www/wwwroot/
DST=root@192.168.0.2:/backup/sync/
LOG=/var/log/sync_realtime.log
# 基础 rsync 参数:归档、压缩、删除源端已删文件、通过 ssh
RSYNC_OPT="-az --delete -e ssh"
inotifywait -mrq --format '%w%f' -e modify,create,delete,move $SRC | while read file
do
# 忽略编辑器临时文件
if echo "$file" | grep -qE '.(swp|swx|tmp)$'; then
continue
fi
echo "$(date '+%F %T') sync trigger: $file" >> $LOG
rsync $RSYNC_OPT $SRC $DST >> $LOG 2>&1
done
EOF
chmod +x /root/sync_realtime.sh
脚本里 inotifywait 的 -m 表示持续监听,-r 递归子目录,-q 减少冗余输出。每次事件读到文件路径后,我们跑一次整体 rsync。虽然可以按文件增量传,但目录级 rsync 更简单稳健,几百兆站点压力不大。
如果你源目录特别大、变更极频繁,可以把 rsync 改成只传具体 $file 的相对路径,减少比对范围。但对于一般企业站和接口服务,上述写法够用且不易出错。
3.2 后台运行与开机自启
直接执行脚本会占住终端,我们用 nohup 丢到后台,同时借助宝塔“计划任务”里的 Shell 脚本类型,添加重启后自动拉起的逻辑。
# 手动启动
nohup /root/sync_realtime.sh > /dev/null 2>&1 &
# 在宝塔计划任务中添加“重启服务器后”或每分钟保活检查
cat > /root/check_sync.sh <<'EOF'
#!/bin/bash
if ! pgrep -f sync_realtime.sh > /dev/null; then
nohup /root/sync_realtime.sh > /dev/null 2>&1 &
fi
EOF
chmod +x /root/check_sync.sh
在宝塔面板“计划任务”新建一个 Shell 脚本任务,内容为 /root/check_sync.sh,频率选“每分钟”,就能保证脚本意外退出时被拉起。比起写 systemd 服务,这种办法对不熟悉底层的同学更友好。
四、宝塔面板里的可视化监控
虽然同步脚本是命令行的,但宝塔可以帮我们看状态。一方面用“文件”功能远程挂载或定时对比 B 的 /backup/sync 看是否最新;另一方面在“计划任务”日志里能看到 check_sync 的执行记录。
更直观的做法是在 A 上装宝塔的“监控”或第三方探针,观察 /var/log/sync_realtime.log 的增长。一旦发现某次 rsync 报错,比如 SSH 断开,日志里会有明确提示,这时检查网络或重做免密即可。
4.1 带宽与冲突处理
异地同步最怕两台机房同时写同一个文件,造成版本互相覆盖。因此源端 A 建议设为可写,目标端 B 同步目录只做接收,业务流量也走 A,B 作为热备。若需双活,要引入分布式锁或对象存储,超出本文范围。
rsync 的 -z 参数会压缩数据,跨公网能省流量,但吃 CPU。如果机房间是专线或内网互通,可去掉 -z 提速。这些参数在脚本里调整很方便。
五、常见问题与排查
实际配置中容易卡在几个地方:一是 B 的 SSH 端口不是默认 22,要在 rsync 的 -e 里指定,例如 -e 'ssh -p 2222';二是 SELinux 或防火墙拦了 SSH,需放通;三是 inotify 监听数超限,改 /proc/sys/fs/inotify/max_user_watches 即可。
还有人发现同步延迟高,多是 A 到 B 的公网抖动。可在脚本加简单的失败重试,或者把 rsync 换成支持断点续传的参数。宝塔本身不限制你写多复杂的 Shell,灵活度足够。
5.1 简单验证同步效果
在 A 的 /www/wwwroot 下新建一个文件,几秒内登录 B 查看是否出现:
# A 上执行 echo "hello_sync" > /www/wwwroot/test_sync.txt # B 上执行 ls -l /backup/sync/test_sync.txt && cat /backup/sync/test_sync.txt
若 B 能马上看到内容,说明整套宝塔加 rsync 加 inotify 的异地实时同步已经跑通。后续只要源目录有变动,目标机房就会自动保持一致,无需人工干预。