一次搞懂 rsync:从入门到解决真实世界中的权限难题

在日常运维和开发中,我们经常需要在服务器之间同步文件,比如备份网站、分发代码、迁移数据等。rsync 就是为此而生的"神器"。它快速、灵活,并且极其高效,因为它只传输文件的变化部分。

rsync 的强大也伴随着它丰富的选项和复杂的权限逻辑。很多初学者在使用时,常常会陷入各种"权限不足"的报错中。

本文将从 rsync 的基础用法讲起,然后通过一个真实网站同步的排错案例 ,一步步深入理解 rsync 的工作原理,彻底攻克那些令人头疼的权限问题。

rsync 快速入门

1. rsync 是什么?

简单来说,rsync 是一个文件同步工具。它可以在本地不同目录间、或在本地与远程服务器间同步文件。它最大的特点是"增量同步",第一次会同步所有内容,之后就只同步修改过的部分,非常节省时间和带宽。

2. 两种核心工作模式

rsync 有两种主要的远程同步模式:

  1. SSH 模式: 这是最常用、最简单也推荐的模式。它通过 SSH 协议连接远程服务器,安全性和认证都由 SSH 负责。
  2. Daemon 模式 (守护进程模式) : 远程服务器上需要运行一个 rsync 守护进程(默认监听873端口),客户端通过专门的 rsync 协议连接。这种模式配置更复杂,但适合大规模、频繁的同步场景。

它们的语法有明显区别:

bash 复制代码
# SSH 模式 (使用单冒号 :)
rsync [选项] [源] user@host:/path/to/dest

# Daemon 模式 (使用双冒号 ::)
rsync [选项] [源] user@host::module

本文的案例将聚焦于配置更复杂的 Daemon 模式,因为它的权限问题最具代表性。

3. 最重要的"陷阱":结尾的斜杠 /

在学习具体命令前,必须先掌握 rsync 最容易出错的一个点:源地址末尾的斜杠 /

  • 没有斜杠 rsync ... /src ... /dest : 同步目录本身。会把 src 整个目录(包括 src 这个名字)复制到 dest 下,形成 /dest/src
  • 有斜杠 rsync ... /src/ ... /dest : 同步目录下的内容。会把 src 目录里的所有文件和子目录直接复制到 dest 下,不会在 dest 目录下创建 src 这个子目录。

简单记:有斜杠,同步"内容";没斜杠,同步"目录本身"。

常用选项详解

rsync 的选项非常多,但我们日常使用中最核心的是 -avzP 这个组合。

  • -a (archive): 归档模式,这是一个"全家桶"选项,相当于 -rlptgoD

    • -r: 递归同步目录。
    • -l: 保持符号链接。
    • -p: 保持文件权限 (permissions)
    • -t: 保持文件修改时间 (times)。
    • -g: 保持文件所属组 (group)
    • -o: 保持文件所有者 (owner)
    • -D: 保持设备文件等。 总之,-a 选项致力于让目标文件和源文件尽可能保持一模一样。
  • -v (verbose): 详细模式。会显示同步过程,方便我们观察。

  • -z (compress): 压缩模式。在传输时压缩数据,能节省带宽,但会增加 CPU 消耗。

  • -P: 这是 --partial--progress 的合体。

    • --partial: 保留因故中断传输的半成品文件,下次能断点续传。
    • --progress: 显示每个文件的传输进度条,对同步大文件非常友好。

还有几个在实战中非常有用的选项:

  • --delete: 删除目标目录中,源目录已经不存在的文件,让两边真正"一模一样"。(危险操作,使用前务必确认!)
  • --exclude=PATTERN: 排除掉符合某种模式的文件,例如 --exclude=*.log
  • --exclude-from=FILE: 从一个文件中读取排除规则列表。
  • --bwlimit=KBPS: 限制传输带宽,单位是 KB/s。避免 rsync 占满带宽。

实战排错:同步网站遇到的连环"坑"

理论说完了,我们来看一个真实的案例。

目标 : 将服务器 A (10.0.0.1) 的网站目录 /www/wwwroot/site.com/,通过 rsync 守护进程(Daemon)模式,同步到服务器 B (10.0.0.2)。

场景设定

  1. 服务器 B (目标端) : 已经配置好了 rsync 守护进程。其配置文件 /etc/rsyncd.conf 内容如下,定义了一个名为 website 的模块:

    ini 复制代码
    # 全局配置
    uid = root             # 全局默认使用 root 用户写入
    gid = root             # 全局默认使用 root 组
    use chroot = no
    max connections = 200
    timeout = 600
    log file = /var/log/rsyncd.log
    
    # "website" 模块配置
    [website]
        path = /www/wwwroot/site.com/
        comment = Website Backup
        read only = false
        ignore errors
        # 模块级配置会覆盖全局配置,这是关键!
        uid = www          # 强制写入文件的所有者为 www
        gid = www          # 强制写入文件的所属组为 www
        auth users = myuser
        secrets file = /etc/rsync.secrets
  2. 服务器 B (目标端) : 认证文件 /etc/rsync.secrets 内容为 用户名:密码 格式:

    makefile 复制代码
    myuser:YourStrongPassword123
  3. 服务器 A (源端): 我们将把密码存储在一个文件中,以便命令可以自动读取。

关键的安全细节:密码文件

在客户端(服务器A),我们需要创建一个文件来存放密码,并通过 --password-file 参数指定它。

这个密码文件有严格的要求:

  1. 文件中只包含密码,不包含用户名和冒号。
  2. 为了安全,该文件的权限必须 设置为 600 (只有所有者可读写)。否则 rsync 会拒绝使用它。
bash 复制代码
# 在服务器 A 上操作
echo "YourStrongPassword123" > /etc/rsync.pass
chmod 600 /etc/rsync.pass

初始命令

一切就绪,我们在服务器 A 上写出了第一版命令:

bash 复制代码
/usr/bin/rsync -avzP \
--port=873 \
--bwlimit=10240 \
--exclude-from=/etc/rsync_exclude.list \
--password-file=/etc/rsync.pass \
/www/wwwroot/site.com/ \
myuser@10.0.0.2::website

执行后,报错了。


坑 1: "文件或目录不存在"

text 复制代码
rsync: failed to open exclude file /etc/rsync_exclude.list: No such file or directory (2)
rsync error: error in file IO (code 11)
  • 问题分析 : 错误信息非常直白,failed to open exclude file,找不到排除规则文件。
  • 原因 : rsync 命令严格按照指令去找 /etc/rsync_exclude.list,但这个文件我们忘了创建。
  • 解决方案 :
    1. 创建文件 : 在服务器 A 上 touch /etc/rsync_exclude.list,然后把排除规则写进去。
    2. 规则解释 :
      • **/*.log: ** 代表任意深度的目录,所以这条规则会排除所有子目录下的 .log 文件。
      • upload/: 排除顶层的 upload 目录及其所有内容。
    3. 如果不需要排除任何文件,直接从命令中删除 --exclude-from 这部分即可。

我们选择创建文件并加入规则,问题解决,继续执行。又报错了!


坑 2: "chgrp: 操作不被允许"

text 复制代码
rsync: chgrp "some/file.html" (in website) failed: Operation not permitted (1)
...
rsync error: some files/attrs were not transferred (code 23)
  • 问题分析 : chgrp failedrsync 在目标服务器上尝试更改文件所属组 失败。Operation not permitted 表明这是个权限问题。
  • 原因 :
    1. 客户端要求 : 我们的命令里有 -a,其中包含了 -g (保持所属组)。
    2. 源文件状态 : 服务器 A 上的网站文件,所属组是 root
    3. 服务器端限制 : 服务器 B 的 rsyncd.conf 已指定 uid=wwwgid=www,所以写入文件时,进程是以普通用户 www 的身份运行的。
    4. 权限冲突 : rsync 在服务器 B 上以 www 用户的身份创建了文件,然后接到客户端的指令:"请把这个文件的所属组改成 root"。一个普通用户 www 当然没有权限把文件交给 root 组。于是,操作被系统拒绝。
  • 解决方案 : 既然目标服务器已经强制指定了所有权,客户端就不应该再提要求。我们修改命令,将 -a 拆开,去掉 -g (所属组) 和 -o (所有者)。

修改后的命令选项 : -rltpDvzP (从 -a 中去掉了 -g-o)

bash 复制代码
/usr/bin/rsync -rltpDvzP ... [其他部分不变]

我们修正命令,再次尝试,结果......又报错了!


坑 3: "设置权限: 操作不被允许"

text 复制代码
rsync: failed to set permissions on "some/file.html" (in website): Operation not permitted (1)
...
rsync error: some files/attrs were not transferred (code 23)
  • 问题分析 : failed to set permissions,这次是设置文件权限位失败了。
  • 原因 :
    1. 客户端要求 : 我们的新命令里还有 -p (保持权限)。
    2. 源文件状态 : 服务器 A 上的某些文件或目录,可能带有一些只有 root 才能设置的特殊权限位,比如 sticky bit (粘滞位 t)。
    3. 服务器端限制 : www 用户没有权限设置这些特殊的权限位。
    4. 权限冲突 : rsync 在服务器 B 上以 www 用户的身份,尝试复制一个只有 root 才能设置的特殊权限,再次被系统无情拒绝。
  • 解决方案: 我们需要再次"让步",不强求权限位完全一致,而是给所有同步过去的文件设置一个统一、安全、合理的权限。

最终的完美命令 : 去掉 -p,改用 --chmod

bash 复制代码
/usr/bin/rsync -rltDvzP \
--chmod=D755,F644 \
--port=873 \
--bwlimit=10240 \
--exclude-from=/etc/rsync_exclude.list \
--password-file=/etc/rsync.pass \
/www/wwwroot/site.com/ \
myuser@10.0.0.2::website
  • --chmod=D755,F644: 这个选项是解决问题的关键。它告诉 rsync
    • 所有目录 (D) 的权限都设置为 755 (rwxr-xr-x)。
    • 所有文件 (F) 的权限都设置为 644 (rw-r--r--)。 这正好是 Web 服务器最标准、最安全的权限配置。

再次执行这个最终版的命令,屏幕上终于滚动起正常的同步列表,所有报错都消失了。

rsync 权限问题的核心思想

通过这次排错之旅,我们可以总结出使用 rsync(特别是守护进程模式)时关于权限的核心思想:

  1. 明确责任划分:

    • 服务器端 (rsyncd.conf) :负责决定同步过来的文件**"属于谁"**。通过 uidgid 参数来强制指定所有者和所属组。
    • 客户端 (rsync 命令) :负责传输文件内容。应该放弃对所有权和特殊权限的控制,避免向服务器提出它无法完成的"权限要求"。
  2. 告别对 -a 的盲目依赖 : -a 选项虽然方便,但在复杂的权限场景下(比如以非 root 用户同步),它就是权限问题的根源。要学会将它拆解为 -rltpD 等,并根据实际情况去掉 -g, -o, -p

  3. 主动设置目标权限 : 使用 --chmod 是一个非常好的实践。它能确保目标文件的权限统一、正确且安全,而不是依赖于源文件那可能混乱或不适用的权限设置。

相关推荐
U盘失踪了5 分钟前
python JSONPath 表达式生成器
linux·windows·python
锦鲤飞上天2 小时前
CentOS卸载、安装MySQL8(yum操作)
linux·adb·centos
wb1893 小时前
服务器的Mysql 集群技术
linux·运维·服务器·数据库·笔记·mysql·云计算
天上掉下来个程小白4 小时前
Docker-07.Docker基础-数据卷挂载
运维·docker·微服务·容器
whabc1004 小时前
ssh连接VirtualBox中的Ubuntu24.04(win11、putty、NAT 模式)
运维·ssh
热爱生活的五柒5 小时前
服务器突然之间特别卡,什么原因?
运维·服务器
huangyuchi.5 小时前
【Linux系统】详解,进程控制
linux·进程控制·进程创建·进程等待·进程程序替换·退出码·进程终止
zly35005 小时前
Linux(centos)安全狗
linux·运维·服务器
星辰云-6 小时前
Nginx笔记
运维·笔记·nginx