本页内容

  • 1 安装 rsync
  • 2 在 server1.example.com 上创建非特权用户
  • 3 测试 rsync
  • 4 在 mirror.example.com 上创建密钥
  • 5 配置 server1.example.com
  • 6 在 mirror.example.com 上测试 rsync
  • 7 创建 Cron 任务
  • 8 相关链接

本教程将向你展示如何把你的网站从主 Web 服务器镜像到一台备份服务器,当主服务器发生故障时,备份服务器可以接管。我们使用 rsync 这个工具来完成,并通过一个 cron 任务来运行它——该任务每隔 x 分钟检查镜像上是否有需要更新的内容。因此,当备份服务器需要接管时,它通常都是最新的。

rsync 只更新发生变化的文件,因此你不必在每次运行 rsync 时都传输 5 GB 的数据。它只镜像新增/变化的文件,并且还能删除镜像上那些已在主服务器上被删除的文件。此外,它还能保留被镜像的文件和目录的权限与所有者信息;为了保留所有者信息,我们需要以 root 身份运行 rsync,这正是我们在本教程中所做的。如果主服务器上的权限和/或所有者发生变化,rsync 也会在备份服务器上相应地进行更改。

在本教程中,我们将通过 SSH 来隧道传输 rsync,这样更安全;这也意味着你无需为 rsync 在防火墙中开放另一个端口——只要 22 端口(SSH)是开放的即可。问题在于,SSH 登录需要密码,而如果你想把 rsync 作为 cron 任务来运行,这就不太合适了。需要密码就意味着需要人工交互,而这并不是我们想要的效果。

但幸运的是,有一个解决方案:使用公钥。我们在备份服务器 mirror.example.com 上创建一对密钥,其中一把保存在远程系统 server1.example.com 的一个文件中。之后,我们在运行 rsync 时就不会再被要求输入密码了。这也包括 cron 任务,而这正是我们想要的。

正如你从前面的内容中可能已经猜到的那样,我们的思路是:直接从 mirror.example.com 发起对 server1.example.com 的镜像;server1.example.com 不需要做任何事情就能被镜像。

这里我将使用如下配置:

  • 主服务器:server1.example.com(server1)——IP 地址:192.168.0.100
  • 镜像/备份服务器:mirror.example.com(mirror)——IP 地址:192.168.0.175
  • 待镜像的网站位于 server1.example.com 的 /var/www 目录下。

rsync 仅用于镜像文件和目录;如果你想要镜像你的 MySQL 数据库,请改用 MySQL 镜像/复制(replication)。

我想先说明,这不是搭建此类系统的唯一方式。实现这一目标有很多方法,但这将是我所采用的方式。

第一步是登录你的系统或成为 root 用户。在 Debian 和 CentOS 上,使用:

su -

如果你登录的不是 root 用户。在 Ubuntu 上,使用:

sudo -s

代替。

1 安装 rsync

首先,我们必须在 server1.example.com 和 mirror.example.com 上都安装 rsync。对于 Debian 和 Ubuntu 系统,操作如下:

server1/mirror:

(我们以 root 身份执行此操作!)

apt install rsync

在其他 Linux 发行版上,你会使用 yum / dnf(Fedora/CentOS)或 yast(SuSE)来安装 rsync。

在 CentOS / Rocky Linux 或 AlmaLinux 上,使用:

dnf install rsync

2 在 server1.example.com 上创建非特权用户

现在我们在 server1.example.com 上创建一个名为 someuser 的非特权用户,mirror.example.com 上的 rsync 将使用该用户来镜像 /var/www 目录(当然,someuser 必须对 server1.example.com 上的 /var/www 拥有读取权限)。

server1:

(我们以 root 身份执行此操作!)

sudo useradd -d /home/someuser -m -s /bin/bash someuser

这将创建用户 someuser,其主目录为 /home/someuser,登录 shell 为 /bin/bash(someuser 必须拥有一个有效的登录 shell,这一点很重要——类似 /bin/false 的 shell 是无法工作的!)。现在为 someuser 设置一个密码:

passwd someuser

3 测试 rsync

接下来,我们在 mirror.example.com 上测试 rsync。我们以 root 身份执行如下操作:

mirror:

rsync -avz -e ssh 
[email protected]
:/var/www/ /var/www/

你应该会看到类似如下的内容。输入 yes 进行确认:

The authenticity of host 'server1.example.com (192.168.0.100)' can't be established.
RSA key fingerprint is 32:e5:79:8e:5f:5a:25:a9:f1:0d:ef:be:5b:a6:a6:23.
Are you sure you want to continue connecting (yes/no)?
<-- yes

然后输入 someuser 的密码,你应该会看到 server1.example.com 上的 /var/www 目录已被镜像到 mirror.example.com 的 /var/www。

你可以在两台服务器上这样验证:

server1/mirror:

ls -la /var/www

你应该会看到所有文件和目录都已镜像到 mirror.example.com,并且这些文件和目录的权限/所有者应与 server1.example.com 上保持一致。

4 在 mirror.example.com 上创建密钥

现在我们在 mirror.example.com 上创建私钥/公钥对:

mirror:

(我们以 root 身份执行此操作!)

mkdir /root/rsync
ssh-keygen -t dsa -b 1024 -f /root/rsync/mirror-rsync-key

你会看到类似如下的内容:

Generating public/private dsa key pair.
Enter passphrase (empty for no passphrase): [press enter here]
Enter same passphrase again: [press enter here]
Your identification has been saved in /root/cron/mirror-rsync-key.
Your public key has been saved in /root/cron/mirror-rsync-key.pub.
The key fingerprint is:
68:95:35:44:91:f1:45:a4:af:3f:69:2a:ea:c5:4e:d7 root@mirror

重要的是不要输入任何密码短语(passphrase),否则镜像在没有人工交互的情况下将无法工作,所以直接按回车即可!

接下来,我们将公钥复制到 server1.example.com:

mirror:

(同样,我们以 root 身份执行此操作。)

scp /root/rsync/mirror-rsync-key.pub 
[email protected]
:/home/someuser/

现在,公钥 mirror-rsync-key.pub 应该已经存在于 server1.example.com 的 /home/someuser 中。

5 配置 server1.example.com

现在通过 SSH 以 someuser(不是 root!)身份登录 server1.example.com,并执行如下操作:

server1:

(请以 someuser 身份执行此操作!)

mkdir ~/.ssh
chmod 700 ~/.ssh
mv ~/mirror-rsync-key.pub ~/.ssh/
cd ~/.ssh
touch authorized_keys
chmod 600 authorized_keys
cat mirror-rsync-key.pub >> authorized_keys

通过这一步,我们已经将 mirror-rsync-key.pub 的内容追加到了 /home/someuser/.ssh/authorized_keys 文件中。/home/someuser/.ssh/authorized_keys 的内容应该类似于这样:

server1:

(仍然是 someuser 身份!)

vi /home/someuser/.ssh/authorized_keys
ssh-dss AAAAB3NzaC1kc3MAAA[...]lSUom root@
mirror

现在我们希望只允许来自 mirror.example.com 的连接,并且连接的用户只能使用 rsync,因此我们添加

command="/home/someuser/rsync/checkrsync",from="mirror.example.com",no-port-forwarding,no-X11-forwarding,no-pty

到 /home/someuser/.ssh/authorized_keys 文件的最开头:

server1:

(仍然是 someuser 身份!)

vi /home/someuser/.ssh/authorized_keys
command="/home/someuser/rsync/checkrsync",from="mirror.example.com",no-port-forwarding,no-X11-forwarding,no-pty ssh-dss AAAAB3NzaC1kc3MAAA[...]lSUom root@
mirror

在 from= 之后,你必须使用像 mirror.example.com 这样的 FQDN(完全限定域名)而不是 IP 地址,否则自动镜像将无法工作!

现在我们创建脚本 /home/someuser/rsync/checkrsync,该脚本会拒绝除 rsync 之外的所有命令。

server1:

(我们仍以 someuser 身份执行此操作!)

mkdir ~/rsync
vi ~/rsync/checkrsync
#!/bin/sh
case "$SSH_ORIGINAL_COMMAND" in
        *\&*)
                echo "Rejected"
                ;;
        *\(*)
                echo "Rejected"
                ;;
        *\{*)
                echo "Rejected"
                ;;
        *\;*)
                echo "Rejected"
                ;;
        *\<*)
                echo "Rejected"
                ;;
        *\`*)
                echo "Rejected"
                ;;
        rsync\ --server*)
                $SSH_ORIGINAL_COMMAND
                ;;
        *)
                echo "Rejected"
                ;;
esac
chmod 700 ~/rsync/checkrsync

6 在 mirror.example.com 上测试 rsync

现在我们必须要在 mirror.example.com 上测试,看是否能够在不被提示输入 someuser 密码的情况下镜像 server1.example.com。我们执行如下操作:

mirror:

(我们以 root 身份执行此操作!)

rsync -avz --delete --exclude=**/stats --exclude=**/error --exclude=**/files/pictures -e "ssh -i /root/rsync/mirror-rsync-key" 
[email protected]
:/var/www/ /var/www/

(--delete 选项表示,在 server1.example.com 上已被删除的文件,也应在 mirror.example.com 上被删除。--exclude 选项表示这些文件/目录不应被镜像;例如 --exclude=**/error 表示"不要镜像 /var/www/error"。你可以使用多个 --exclude 选项。我列出这些选项作为示例;你可以根据实际需求调整该命令。请参阅

man rsync

以获取更多信息。)

你现在应该会看到镜像正在进行:

receiving file list ... done
sent 71 bytes  received 643 bytes  476.00 bytes/sec
total size is 64657  speedup is 90.56

而不会被提示输入密码!这正是我们想要的效果。

7 创建 Cron 任务

我们希望将镜像自动化,因此我们在 mirror.example.com 上为其创建一个 cron 任务。以 root 身份运行 crontab -e:

mirror:

(我们以 root 身份执行此操作!)

crontab -e

并创建如下这样的 cron 任务:

*/5 * * * * /usr/bin/rsync -azq --delete --exclude=**/stats --exclude=**/error --exclude=**/files/pictures -e "ssh -i /root/rsync/mirror-rsync-key" 
[email protected]
:/var/www/ /var/www/ 

这会让 rsync 每 5 分钟运行一次;请根据你的需求进行调整(参见

man 5 crontab

)。我在这里使用了 rsync 的完整路径(/usr/bin/rsync),只是为了确保 cron 知道去哪里找 rsync。你的 rsync 位置可能有所不同。运行

mirror:

(我们以 root 身份执行此操作!)

which rsync

来查明你系统中 rsync 的位置。

8 相关链接

  • rsync:https://rsync.samba.org/