两台 Ubuntu 服务器之间传文件夹,这活儿听起来简单,真要传好、传稳、传得不出幺蛾子,里面门道不少。我这些年帮客户迁移数据、同步备份,踩过的坑能绕机房一圈。今天不聊虚的,直接把这套“服务器互传文件夹”的完整实战经验拆开讲透,从最基本的命令到增量同步、断点续传、权限保留、安全加固,全部按真实操作环境和思路来。
1. 传文件夹这件事,先想清楚三个问题
动手敲命令之前,我建议你花两分钟想明白自己的实际场景。同样是两台 Ubuntu 服务器之间互传文件夹,一次性拷贝、定期增量备份、双向数据同步,这三者的技术选型完全不同。盲目套用一个命令,轻则效率低,重则数据错乱。
1.1 有多少数据、传多少次、谁来操作
先说数据量层面。如果你只是偶尔手动传个小目录,比如几百兆、一两个 GB,那么scp就够用了,简单直接,不需要额外装任何东西。但如果目录里有几十万个文件、几十 GB 甚至上 TB 的数据,那就必须上rsync,否则你会在终端前等到怀疑人生。
传输频率也很关键。如果是“每天凌晨自动把 A 服务器的日志同步到 B 服务器”,那就不能靠手动敲命令,得写脚本配合 cron 定时任务,同时还要考虑增量同步能力。如果只有一次性的搬迁任务,比如机房迁移、服务器换新,那重点就是完整性校验和权限保留,而不是同步效率。
最后说操作者。如果是你自己在终端里操作,交互式输入密码没问题。但如果你要写成自动化脚本,那必须配置 SSH 密钥免密登录,否则脚本一跑就卡在密码输入那里,挂机挂到天荒地老。
1.2 主流方案对照:scp、rsync、sftp、NFS 怎么选
我直接给一个对比表,这是我平时给团队内部做培训用的标准表:
| 方案 | 适合场景 | 增量传输 | 断点续传 | 权限保留 | 上手难度 |
|---|---|---|---|---|---|
| scp | 小规模一次性拷贝 | 不支持 | 不支持 | 基本保留(不保留属主/时间戳细节) | 极低 |
| rsync | 中大规模同步/备份 | 支持 | 支持(需配合参数或工具) | 完整保留 | 中等 |
| sftp | 交互式管理远程文件 | 不支持 | 支持(部分客户端) | 一般 | 低 |
| NFS/Samba | 常驻挂载、实时共享 | 本身就是实时访问 | 不适用 | 取决于配置 | 高 |
日常场景里,我 90% 以上的互传需求都用rsync搞定。scp偶尔用于应急或顺手传个小文件。sftp适合你不想开 SSH 完整权限、只想让对端用户管理特定目录的场景。NFS 属于“把远程目录当本地盘用”的思路,适合持续共享但不适合一次性搬数据。
1.3 一个容易被忽略的前提:SSH 配置
以上所有命令(scp、rsync、sftp)默认都走 SSH 通道,所以你得先确认两台服务器的 SSH 服务是正常的。说白了,Ubuntu 之间互传文件夹,本质上就是“通过 SSH 通道操作对方的文件系统”。
我遇到过不少新手,在阿里云或者腾讯云上开了服务器安全组端口,却忘了装 OpenSSH Server,结果客户端一通操作猛如虎,一看报错全是Connection refused。Ubuntu 桌面版默认没装 SSH 服务端,服务器版看安装选项。没装的话先执行:
sudo apt update sudo apt install openssh-server -y sudo systemctl enable --now ssh确认服务状态:
sudo systemctl status ssh看到active (running)就放心了。另外提醒一句,很多云厂商的安全组默认只放行 80/443/22 这类端口,22 端口一般没问题,但你的 SSH 如果改了端口,记得同步放行安全组。
2. scp 快速上手:适合一次性拷贝的轻量方案
scp是 Secure Copy 的缩写,利用 SSH 协议加密传输文件。它的语法和cp非常像,只是在源路径或目标路径前面加上了“用户名@主机地址:”的前缀。如果你只想完成一次简单的文件夹拷贝,这是最快的路径。
2.1 scp 基础命令与参数解析
最基本的命令长这样:
scp -r /home/user/data 用户名@目标IP:/home/user/这里的-r表示递归复制目录。如果你不加这个参数,直接复制目录会报错omitting directory,因为scp默认只处理文件。
几个我常用的参数:
-P 端口号:指定 SSH 端口,注意是大写 P。默认 22 端口可以省略。-C:开启压缩传输。如果你的网络带宽有限,这是个好东西,但也会增加 CPU 负载。文本类文件压缩率很高,压缩视频图片类文件反而浪费 CPU。-i 密钥文件路径:指定私钥文件登录,适合非默认密钥名的场景。-l 带宽限制:以 Kbit/s 为单位限制带宽。比如你不想让传输占满机房带宽,可以加-l 8192就是把传输带宽限制在 8Mbps 左右。
举个例子,把本机/data目录传到 IP 为192.168.1.10的服务器,SSH 端口为2222,同时启用压缩:
scp -r -C -P 2222 /data 用户名@192.168.1.10:/backup/注意目标路径末尾的斜杠:/backup/表示把/data目录整体放进/backup下面,形成/backup/data。如果目标路径写成/backup且这个目录已存在,效果是一样的。但如果/backup不存在,有些版本的 scp 行为可能不同,稳妥起见还是写清/backup/data这种完整路径更可控。
2.2 scp 的局限与替代场景
scp最大的问题有三个:
第一,它不支持增量同步。每次传的都是全量数据,哪怕你上次已经传了 99% 的内容,它还是会完整复刻一遍。第二,它不支持断点续传。传了一半网络断了,对不起,重新来。第三,它默认不保留原始文件的属主(owner)、时间戳等元数据。你传过去之后,文件的时间戳变成传输时刻的时间,对某些需要保留修改时间的场景很致命。
有人会问,那为什么还要用它?答案很简单:快、稳、简单。对于几百 MB 到几个 GB 的一次性传输,scp开箱即用,零学习成本。你要是为了传个小目录专门去学 rsync 的参数,那反而是在浪费精力。
还有一种场景我经常用scp,就是“临时从 A 服务器拉一个文件到本地,再推到 B 服务器”。虽然路径绕了一点,但在两台服务器之间没法直接连通(比如处在不同内网)的时候,本地中转是最快的解法。
2.3 一个实用技巧:用 tar 配合 scp 保留权限和时间戳
如果你既想用scp的简单,又想保留完整的权限和时间戳,可以在传之前先打个包。步子很简单,通过管道把tar和scp串起来:
tar czf - /data | ssh 用户名@目标IP "tar xzf - -C /backup"这条命令的意思是:把/data目录打包并通过 ssh 通道直接发送到目标服务器,然后在目标服务器上解包到/backup目录。它比scp -r好的地方在于tar保存了文件的权限、属主、时间戳等元数据,而且单个流传输在大目录场景下往往比逐个文件复制更高效,因为减少了文件系统调用的开销。
这种写法有一个前提:目标服务器上也要有tar命令,Ubuntu 系统默认都有,这个不用担心。如果想看你传输的过程中发生了什么,把czf改成czvf,也就是加一个v,就能看到每个文件的处理过程。
注意:如果两台服务器之间的网络不太稳定,建议先测一下再跑大数据量任务。tar 流式传输一旦中断,整个管道就断了,没有断点续传能力。
3. rsync 才是主力:增量同步与断点续传的完整实操
如果你需要经常在两台服务器之间同步目录,或者数据量大到scp实在扛不住,那rsync就是你的主力工具。这玩意儿诞生几十年了,至今仍是服务器间文件同步的事实标准,没有之一。
3.1 rsync 核心参数与增量原理
rsync的精髓在于“增量传输”。它先把源目录和目标目录做对比,找出有差异的部分,只传输变化的数据块。这个对比机制叫“滚动校验算法”,它在文件未被修改时直接跳过,文件只有局部改动时只传改动的那一块,效率非常惊人。
我日常几乎固定使用的参数组合是:
rsync -avz --progress 源目录 用户名@目标IP:目标路径逐个拆开说:
-a:归档模式,等价于-rlptgoD,意思是递归复制、保留软链接、保留权限、保留时间戳、保留属主和属组、保留设备文件等特殊文件。通俗讲就是“最大程度地还原源目录的本来面貌”。-v:verbose,输出详细信息。-z:传输时压缩,节省带宽,原理和 scp 的-C一致。--progress:显示传输进度,能实时看到文件列表和速度。
在增量计算上,还需要了解--itemize-changes这个参数,它用标志位告诉你每个文件为什么被同步。比如>f+++++++++表示新文件,>f.sT.......表示文件大小、时间戳发生了变化。这个参数是排查“为什么这个文件被重复传输”的神器。
3.2 走 SSH 通道的常规用法与端口处理
rsync默认不走 SSH,但在 Ubuntu 服务器场景下我们几乎总是让它走 SSH,因为 SSH 本身就是加密且安全的。默认命令:
rsync -avz --progress /data 用户名@192.168.1.10:/backup/和scp一样,它也支持指定端口:
rsync -avz --progress -e "ssh -p 2222" /data 用户名@192.168.1.10:/backup/-e参数是rsync指定远程 shell 的方式。你可以用引号里塞任意 ssh 选项,这就让rsync拥有了极强的扩展性。比如你想用特定的私钥:
rsync -avz --progress -e "ssh -p 2222 -i /home/user/.ssh/id_rsa_backup" /data 用户名@192.168.1.10:/backup/这个-e "ssh ..."的写法是 rsync 实操里最高频的用法之一,一定要记牢。
3.3 大目录同步的实战示例:排除文件、预演、权限保留
来一个我经常在实际业务中用到的大型目录同步示例。假设你要把 A 服务器上的/var/www/html这个站点目录同步到 B 服务器,同时排除掉缓存目录、日志目录和临时文件:
rsync -avz --progress \ -e "ssh -p 22" \ --exclude "cache/" \ --exclude "logs/*.log" \ --exclude "tmp/" \ /var/www/html/ 用户名@192.168.1.10:/var/www/几个解析点:
--exclude支持相对路径模式,cache/表示排除所有名为 cache 的目录,*.log表示排除所有 .log 文件。- 源路径末尾有没有斜杠,含义完全不同。
/var/www/html/带斜杠表示“把 html 目录下的内容复制过去”,目标路径/var/www/下直接出现的是 html 里的文件。如果写成/var/www/html不带斜杠,则会把html目录本身复制过去,目标是/var/www/html,这是一个非常容易踩的坑。
正式执行之前,强烈建议先跑一遍派演练算(dry-run),看看 rsync 会做什么操作,避免因为粗心导致目标目录被完全覆盖:
rsync -avzn --progress /var/www/html/ 用户名@192.168.1.10:/var/www/-n表示 dry-run,它只列出将要执行的传输操作,不实际执行。我每次做敏感的大规模同步前都会先跑一下-n,确认文件列表没有异常再正式执行。这个习惯救过我很多次。
还有一个参数值得专门说:--delete。它的作用是“让目标目录与源目录严格保持一致,删除目标目录中源目录没有的文件”。用了它就意味着目标目录里多出来的文件会被删掉。我在做镜像同步时非常依赖它,把--delete加入命令后,整个目录就是源目录的完美副本。但请你注意,这个参数很危险,加上它之前绝对要三思,配合--dry-run跑一次再执行:
rsync -avz --delete --dry-run /data/ 用户名@192.168.1.10:/backup/data/3.4 中断恢复与定时同步脚本实战
说个实际情况:我曾经在两个机房之间同步 1.2TB 的数据库备份文件,带宽只有 100Mbps,跑了一整晚,中途网络抖动断了。如果是scp,那屏一断就得重来,前功尽弃。但rsync的好处就在于,你再执行一次同样的命令,它会立刻识别出哪些文件已经完整传过去了,只传剩下的部分,相当于是“自然的断点续传”。
为了自动化,我写过一个非常简单但实用的同步脚本,放在/usr/local/bin/sync_backup.sh:
#!/bin/bash # 增量同步站点目录及数据库备份到备份服务器 SRC="/var/www/html" DEST="backupuser@192.168.1.10:backup/www" LOGFILE="/var/log/rsync_sync.log" rsync -avz --delete --log-file=$LOGFILE -e "ssh -p 22 -i /root/.ssh/backup_rsa" $SRC $DEST # 移除超过 30 天的本地备份日志 find /var/log/rsync*.log -mtime +30 -exec rm {} \;赋予执行权限后,放进 crontab:
chmod +x /usr/local/bin/sync_backup.sh crontab -e加入计划任务:
30 2 * * * /usr/local/bin/sync_backup.sh这个配置会在每天凌晨 2 点 30 分执行同步任务。--log-file参数把每次传输的操作记录到日志,方便排查“昨天到底同步了哪些文件”。
实战心得:
rsync退出状态码要看。0 表示成功,非 0 表示出错。常见的有 12(rsync 本身语法错误)、13(权限问题)、23(部分文件传输失败)。脚本里加上对退出码的判断,出错时直接发送告警到你的手机上,比事后查看日志高效得多。比如if [ $? -ne 0 ]; then 发送告警; fi。
4. 传输性能监测与安全加固的实操细节
效率和安全,是服务器互传文件夹逃不开的两个话题。很多教程只会告诉你命令怎么敲,不会告诉你实际跑大数据量时怎么保证传输不拖垮生产环境,也不会告诉你如何防止意外覆盖。这部分我来说点硬核的。
4.1 展示传输进度与速度监测的正确姿势
rsync --progress虽然能看到传输进度,但输出非常密集,尤其在大文件列表下刷屏刷到根本看不清。这时候我一般改用--info=progress2,这个参数只会显示一个总进度条和总速度,不会逐文件刷屏:
rsync -av --info=progress2 /data/ 用户名@192.168.1.10:/backup/输出大概长这样:
1.2G 3% 78.5MB/s 0:12:30传输百分比、瞬时速度、剩余时间一目了然。这个参数在跑大目录同步时体验非常舒服。
如果需要更精细的性能分析,rsync支持--stats参数,它会在传输结束后统计文件数、总字节数、匹配率等:
rsync -avz --stats /data/ 用户名@192.168.1.10:/backup/最值得关注的是Literal data: 1.2 GB和Matched data: 5.8 GB。匹配率高说明增量同步发挥了大作用,你这次实际传输的只有 1.2GB,如果全量传输就得跑 7GB。
4.2 SSH 密钥认证与免密配置
自动化和脚本化部署绕不开免密登录。SSH 密钥认证替代密码认证,步骤其实很简单:
A 服务器上执行:
ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa-t rsa指定算法,-b 4096指定密钥长度,-N ""表示不设置密码短语,-f指定保存路径。
然后把公钥传到 B 服务器:
ssh-copy-id 用户名@目标IPssh-copy-id会自动把~/.ssh/id_rsa.pub内容追加到目标服务器的~/.ssh/authorized_keys。之后你再执行ssh、scp、rsync就都不会问密码了。
为了安全,我强烈建议把 SSH 密码认证直接关掉,只保留密钥认证。修改/etc/ssh/sshd_config:
PasswordAuthentication no PubkeyAuthentication yes然后重启 SSH 服务:
sudo systemctl restart ssh但注意,这次操作前务必确认你的密钥能正常登录。有一次我在服务器上配好密钥后没有验证,手贱把密码认证关了,结果人在机房外,密码登录被拒,密钥又因为权限问题进不去,折腾了一下午。所以建议操作顺序是:先在终端测试密钥登录成功,再去关闭密码认证,并且不要关掉当前这个会话,另一个窗口测试通过后再退出会话。
4.3 传输过程中命令超时与断连的救急套路
我提一个很多人不知道的坑:你手动在终端里跑长时间同步,一旦本地网络闪断,任务就中断了。解决思路是让进程脱离终端运行。以前我会写nohup,现在更推荐直接用screen或tmux。
比如:
screen -S sync_session在新建的 screen 窗口里执行同步命令:
rsync -avz --progress /data/ 用户名@192.168.1.10:/backup/然后按Ctrl+A再按D让会话转入后台,也就是 detach。你可以安心关掉终端,任务照常跑。回来看时可以重新附加会话:
screen -r sync_session这个操作简单到不值得一提,但在生产环境中救过太多回命,我和团队现在跑传输任务时都默认先在 screen 里建一个会话,再执行命令。
另一个需要注意的是 SSH 长连接的稳定性。你可以通过 ssh 配置来减少长连接断开的情况,在~/.ssh/config里加:
Host * ServerAliveInterval 30 ServerAliveCountMax 10这个配置会让 SSH 每隔 30 秒发送一次心跳探测,避免长时间无通信被中间网络设备静默断开。实测下来,这种方法对跨运营商网络传输的稳定性提升非常明显。
5. 常见问题与排查技巧实录(青少年避坑篇)
这部分内容不是从文档里抄的,全是真实操作中遇到过的问题和处理经验。每一条后面我都附了当时的排查思路,照着做能帮你省不少时间。
5.1 连接超时与端口问题的快速定位
症状:执行ssh、scp、rsync命令后,长时间卡住不动,最后报Connection timed out。
排查步骤:
- 确认目标 IP 能通:
ping 目标IP。如果 ping 不通,大概率是网络路由或安全组问题。 - 确认端口是开的:
telnet 目标IP 22或nc -vz 目标IP 22。连不通就看是不是忘了装 openssh-server,或者防火墙拦截了。 - 确认 SSH 服务监听正常:目标服务器上执行
ss -tlnp | grep :22,能看到0.0.0.0:22就说明服务正常监听。 - 确认目标服务器防火墙:
sudo ufw status,Ubuntu 默认防火墙如果开启,需要sudo ufw allow ssh放行。
除了网络层面,还有一个我遇到过的冷门坑:如果两台服务器的系统时间偏差太大,SSH 的密钥交换可能失败。遇到诡异的连接问题,可以顺手对时一下:
sudo apt install -y chrony sudo systemctl enable --now chrony时间服务器的配置和这块的联动比较神奇,但确实曾解决过一次让我抓狂的 SSH 连接问题。
5.2 Permission denied 的三种典型原因及对应解法
报错Permission denied (publickey,password)分好几种情况。
第一种是验证方式问题:目标服务器不允许密码登录,而你还在输密码,或者你配置的账号没有 SSH 权限。解决办法是改用密钥登录,或者检查/etc/ssh/sshd_config里的PasswordAuthentication配置。
第二种是账号权限不够:你用的用户名没有对应目录的写权限。这很常见,比如你想把文件传到/var/www/下面,但/var/www/属主是root,你用的是普通用户。此时有两种思路:一是sudo chown -R 用户名 /var/www/调整属主(不推荐在生产环境直接改系统目录的属主),二是把目标路径改成普通用户有写权限的目录,比如/home/用户名/,再后用sudo mv移动到目标位置。
第三种是家目录或authorized_keys权限错误:这种情况报错很隐蔽,就是密钥文件存在、内容也没写错,但就是登不进去。原因是 SSH 很需要权限校验严格:
- 家目录权限不能超过
755 .ssh目录权限必须是700authorized_keys权限必须是600
如果不对,执行:
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chmod g-w ~这个坑十个人有八个会踩,第一次配置免密登录时一定要检查权限。
5.3 rsync 同步后源文件被误删除的风险与备份策略
--delete参数是双刃剑,我用它做镜像同步很顺手,但也见过同事因为误用了--delete,把目标服务器上存储了几年、源端已经清理掉的旧数据全删了,现场一度非常尴尬。
我的建议是:
- 如果目标是备份,不要用
--delete。直接跑增量同步,保留目标端多余文件,反而是一种额外的保护。 - 如果目标是镜像,需要严格保持一致,那用
--delete前先做一次-n预演,并确认你理解每个被标记删除的文件。 - 永远在目标服务器上留一个最近一次成功同步的快照。我常用的做法是同步完成后再软链一个
backup_$(date +%F)快照目录,配上--link-dest参数可以做“成本几乎为零”的增量快照。
快照方式的命令大概是:
rsync -avz --link-dest=/backup/latest /data/ 用户名@目标IP:/backup/current/--link-dest会对比目标目录和指定的目录,如果文件相同就创建硬链接而不是实质拷贝,占用的磁盘空间极小。这是实现“多版本快照”最划算的做法,属于 rsync 高阶玩法,值得实践一次。
5.4 中文文件名与硬链接等冷门问题
Ubuntu 服务器之间传文件夹,一般不用担心中文文件名。rsync和scp对 UTF-8 编码的中文文件名处理都很正常。但是有一个点要注意:如果目标服务器的locale设置有问题,某些特殊字符可能在文件系统层面显示异常。我的习惯是先在两边验证echo $LANG,如果输出是空的或者是C,最好改成en_US.UTF-8或zh_CN.UTF-8。
硬链接的问题更隐蔽。如果你在源目录里有很多硬链接文件(比如备份软件创建的 dedup 文件),普通 rsync 处理起来会非常慢,且如果不加参数,硬链接关系会丢失,文件的硬度变成 1,磁盘空间会比源端占用更多。解决办法是加-H参数:
rsync -avzH /data/ 用户名@目标IP:/backup/-H表示保留硬链接。如果遇到“明明文件没变,却每回都会全量传输”的诡异现象,优先检查是不是文件时间戳不一致。比如你用-t保留时间戳,但源目录里很多文件的时间戳本身就是错的,可以被-I参数忽略时间戳对比,但那会强制全量传输,慎用。
6. 结尾:最后一层实操经验
我个人在实际操作中的体会是,服务器互传文件夹这件事,真正考验人的不是命令本身,而是对场景的判断和对细节的把控。同样是rsync一条命令,加不加斜杠、加不加--delete、走不走screen,结果可能天差地别。每次做大规模同步之前,先想清楚三个问题:我的数据量多大,我的网络带宽多少,我的目标目录有没有可能被误操作。想清楚了再出手,基本不会翻车。
最后再分享一个小技巧:在两台服务器之间传超大文件(超过 10GB 的数据库备份或镜像),建议先用dd或iperf3测一下两台服务器之间的裸带宽,确认网络质量再做传输。我发现很多传输失败或者速度慢根本不是工具的问题,而是链路上某个中间节点丢包严重。这时候重新拨号换条链路,往往比加参数管用得多。工具只是手段,稳定传输才是目的,希望这篇实战笔记能帮你少走一些弯路。