Коротко: rsync -av SOURCE/ DESTINATION/ копирует каталог, а каждый следующий запуск передаёт только изменившиеся файлы. Удалённая сторона записывается как USER@HOST:/path, и обмен с ней идёт по SSH, поэтому одна и та же команда выкладывает сайт на сервер, забирает бэкап или синхронизирует папку между двумя машинами.
rsync -av ./site/ USER@SERVER_IP:/var/www/site/
rsync -av USER@SERVER_IP:/var/www/site/ ./site-backup/Первая строка загружает содержимое site на сервер, вторая скачивает его обратно. rsync должен быть установлен на обеих машинах (sudo apt install rsync в Debian и Ubuntu, sudo dnf install rsync в Rocky Linux). Весь вывод ниже получен в rsync 3.2.7 — это версия из Debian 12 и Ubuntu 24.04 — на тестовых каталогах, а удалённая сторона там, где это отмечено, имитирована. Свои сообщения rsync не переводит: даже с русской локалью они выводятся по-английски.
Примеры rsync для типовых задач
| Задача | Команда | Примечание |
|---|---|---|
| Загрузить содержимое папки | rsync -av ./site/ USER@SERVER_IP:/var/www/site/ | Слеш у источника: копируется содержимое, а не сама папка |
| Скачать с сервера | rsync -av USER@SERVER_IP:/var/log/nginx/ ./logs/ | Удалённая сторона пишется первой |
| Другой порт SSH или ключ | rsync -av -e "ssh -p 2222 -i ~/.ssh/id_ed25519" ./site/ USER@SERVER_IP:/srv/site/ | Или используйте псевдоним из ~/.ssh/config |
| Посмотреть, ничего не меняя | rsync -avn --delete ./site/ USER@SERVER_IP:/srv/site/ | -n — это --dry-run |
| Точное зеркало | rsync -av --delete ./site/ USER@SERVER_IP:/srv/site/ | Удаляет лишние файлы на приёмнике |
| Исключить файлы | rsync -av --exclude='.git/' --exclude='*.log' ./app/ USER@SERVER_IP:/srv/app/ | Шаблоны разобраны ниже |
| Одна строка прогресса на всю задачу | rsync -a --info=progress2 /data/ USER@SERVER_IP:/data/ | rsync 3.1 и новее |
| Докачать большой файл | rsync -aP disk.img USER@SERVER_IP:/srv/ | -P — это --partial --progress |
| Переместить вместо копирования | rsync -av --remove-source-files ./uploads/ USER@SERVER_IP:/srv/uploads/ | Удаляет у источника каждый переданный файл; пустые папки остаются |
| Никогда не перезаписывать файлы приёмника | rsync -av --ignore-existing ./site/ USER@SERVER_IP:/srv/site/ | -u вместо этого пропускает только файлы, которые на приёмнике новее |
| Ограничить скорость | rsync -a --bwlimit=5M /data/ USER@SERVER_IP:/data/ | Без суффикса — КиБ/с |
| Сжимать при передаче | rsync -avz ./dump.sql USER@SERVER_IP:/root/ | Только текст и только на медленных каналах |
| Сравнивать по содержимому | rsync -avc ./site/ USER@SERVER_IP:/srv/site/ | Читает каждый файл одинакового размера на обеих сторонах |
| Создать недостающие каталоги на приёмнике | rsync -av --mkpath ./site/ USER@SERVER_IP:/srv/new/site/ | rsync 3.2.3 и новее |
| Сохранить жёсткие ссылки, ACL, xattrs | rsync -aHAX /srv/ /mnt/backup/srv/ | -a не включает ни одно из трёх |
| Писать в каталоги, принадлежащие root | rsync -av --rsync-path="sudo rsync" ./conf/ USER@SERVER_IP:/etc/myapp/ | Нужен sudo без пароля для rsync, а это равносильно root |
Слеш в конце: содержимое или сама папка
Что окажется на приёмнике, решает слеш у источника. Мы выполнили каждую строку с папкой site, в которой лежит index.html, один раз при отсутствующем приёмнике и один раз при существующем; результат оба раза совпал:
| Команда | Результат |
|---|---|
rsync -a site/ backup/ | backup/index.html: содержимое site |
rsync -a site/ backup | То же самое: для папки слеш у приёмника ничего не меняет |
rsync -a site backup/ | backup/site/index.html: сама папка, уровнем глубже |
rsync -a site backup | backup/site/index.html, даже если backup до этого не было |
Последняя строка — то место, где rsync расходится с cp -r site backup: cp кладёт файлы прямо в новую папку backup. Слеш у приёмника важен только в одном случае: когда один файл копируется по пути, которого ещё нет. rsync -a index.html save/dir создаст файл с именем dir, а save/dir/ создаст папку и положит в неё index.html. Кроме того, слеш сдвигает корень, от которого отсчитываются шаблоны исключений со слешем в начале.
Что значат ключи -a, -v и другие основные
-a(archive) — это-rlptgoD: рекурсивно, симлинки как симлинки, с сохранением прав, времени, группы, владельца, а также файлов устройств и специальных файлов. Он не включает жёсткие ссылки (-H), ACL (-A) и расширенные атрибуты (-X); для бэкапа системы добавьте их.- Владельцы сохраняются, только если rsync на принимающей стороне работает от root; иначе все файлы будут принадлежать пользователю, под которым вы вошли. Для бэкапов между машинами с разными списками пользователей добавьте
--numeric-ids. -vвыводит список файлов,-hпечатает размеры вида32.01M, а-iпоказывает, почему передаётся каждый файл (следующий раздел).- rsync пропускает файл, если размер и время изменения на обеих сторонах совпадают. Из-за этой «быстрой проверки» (quick check) второй запуск идёт быстро, и из-за неё же существует -c.
Сначала пробный запуск: -n и -i
-n (--dry-run) проходит всё сравнение и ничего не меняет. Мы добавили в источник contact.html, изменили index.html и удалили about.html, и пробный запуск на прежнюю копию вывел:
sending incremental file list
deleting about.html
./
contact.html
index.html
sent 300 bytes received 42 bytes 684.00 bytes/sec
total size is 37 speedup is 0.11 (DRY RUN)Замените -v на -i, и каждая строка скажет, что именно изменится:
*deleting about.html
.d..t...... ./
>f+++++++++ contact.html
>f.st...... index.html>f значит, что файл передаётся (<f — когда он уходит на удалённый хост), +++++++++ — что он новый, s и t — что отличаются размер и время, .d — каталог, у которого меняются атрибуты без передачи данных, а *deleting — файл, который удалил бы --delete.
--delete без потери данных
--delete удаляет на приёмнике файлы, которых больше нет в источнике, и именно это делает копию зеркалом. Он затрагивает только каталоги, которые участвуют в передаче: в нашем пробном запуске rsync -a --delete site mirror/ (без слеша) только создал бы mirror/site/ и ничего не удалил. Настоящая опасность — пустой или неверный источник. Опечатка в пути, несмонтированный диск для бэкапов или пустой checkout — и rsync послушно опустошит приёмник:
*deleting css/style.css
*deleting css/
*deleting index.html
*deleting about.html
.d..t...... ./- 1Запустите ровно эту команду вхолостую
Добавьте
-n(и-i) к команде, которую собираетесь выполнить, больше ничего в ней не меняя. - 2Прочитайте каждую строку *deleting
Если список длиннее, чем вы ожидали, остановитесь и проверьте оба пути и слеши.
- 3Запустите с ограничителем
Уберите
-n. В скриптах добавляйте--max-delete=50: после этого числа rsync пропускает оставшиеся удаления и завершается с кодом 25.
Исключённые файлы защищены от --delete, если не добавить --delete-excluded: так переживают зеркалирование node_modules или .env, которые есть только на сервере. Чтобы удалять только после того, как пришли все файлы, используйте --delete-after.
Как исключить файлы и папки
--exclude=PATTERN можно повторять; * совпадает в пределах одного уровня пути, слеш в конце — только с каталогами, а шаблон без слеша в начале совпадает на любой глубине. Слеш в начале привязывает шаблон к корню передачи, а этот корень зависит от слеша у источника: с источником site/ шаблон --exclude='/node_modules' пропускает только папку верхнего уровня, а с источником site тот же шаблон не совпадает ни с чем, и нужен /site/node_modules. Длинные списки удобнее держать в файле: по одному шаблону на строку, # для комментариев:
# исключения для деплоя
.git/
node_modules/
*.log
.envrsync -av --exclude-from=excludes.txt ./app/ USER@SERVER_IP:/srv/app/Чтобы скопировать только некоторые типы файлов, сначала перечислите включения, потому что срабатывает первое подходящее правило: --include='*/' --include='*.php' --exclude='*' копирует все файлы .php в дереве, а --prune-empty-dirs убирает оставшиеся пустыми папки. С --exclude='*' в начале наш тест не скопировал вообще ничего.
rsync по SSH: порт, ключ и sudo
rsync запускает ssh и выполняет на сервере второй rsync, поэтому он и должен быть там установлен. Мы подменили ssh скриптом, который только записывает свои аргументы; для rsync -a -e "ssh -p 2222" ./site/ deploy@203.0.113.10:/var/www/site/ он получил:
-p 2222 -l deploy 203.0.113.10 rsync --server -logDtpre.iLsfxCIvu . /var/www/site/- Порт, ключ и промежуточный хост проще всего задать в ~/.ssh/config (англ.): с псевдонимом
myvpsкомандеrsync -av ./site/ myvps:/var/www/site/ключ-eвообще не нужен. - Для каталога, в который может писать только root, нужен
--rsync-path="sudo rsync"и правило sudoers, которое разрешает этому пользователю запускать rsync без пароля, потому что ввести пароль некому. Такое правило — это root-доступ под другим названием: этот аккаунт может перезаписать любой файл, включая/etc/sudoers. Давайте его только отдельному пользователю для деплоя или загружайте файлы в домашний каталог и переносите их черезsudo. - Пути с пробелами заключайте в кавычки один раз, для своей оболочки. Начиная с 3.2.4 rsync сам экранирует удалённый путь; для
"deploy@203.0.113.10:/srv/My Files/"в логе было видно, что уходит/srv/My\ Files/.
Для ключа бэкапа, который должен уметь только rsync, в Debian 12 есть /usr/bin/rrsync (скрипт на Python). Поставьте command="rrsync -wo /srv/backups",restrict и пробел перед строкой этого ключа в ~/.ssh/authorized_keys на сервере, и ключ сможет только писать внутрь этого каталога, причём пути на приёмнике будут отсчитываться от него: ни оболочки, ни других путей.
Прогресс, недокачанные файлы, сжатие и ограничение скорости
-P объединяет --progress (строка на каждый файл) и --partial, который сохраняет наполовину переданный файл, чтобы следующий запуск продолжил, а не начал заново. Если файлов много, --info=progress2 показывает всю задачу одной строкой. Вот она с ограничением 5 МБ/с, чтобы цифры были как на реальном канале:
5,604,480 17% 5.00MB/s 0:00:05
16,745,600 52% 5.00MB/s 0:00:02
32,000,000 100% 5.04MB/s 0:00:06 (xfr#2, to-chk=0/3)--bwlimitбез суффикса считает в КиБ в секунду, так что--bwlimit=5000— это примерно 5 МБ/с, почти как--bwlimit=5M.-zсжимает данные файлов. Начиная с 3.2.0 обе стороны выбирают первый метод из спискаCompress listклиента (см.rsync --version), который есть и у сервера; для двух сборок Debian 12 это zstd. Сжатие окупается для SQL-дампов и логов на медленном канале и впустую тратит CPU на архивах, изображениях и видео, которые уже сжаты.--partial-dir=.rsync-partialпрячет недокачанные файлы в скрытую папку, а не держит их под настоящим именем.
Когда стоит включать -c (--checksum)
Быстрая проверка доверяет размеру и времени изменения. Мы дали файлу на приёмнике тот же размер и ту же метку времени, что у источника, но другое содержимое: обычный запуск его пропустил, а rsync -aic поймал:
>fc........ t.txtc отмечает расхождение контрольной суммы. Подвох в том, что rsync до начала передачи читает на обеих сторонах каждый файл с совпадающим размером, поэтому -c нужен для проверки миграции или бэкапа, а не для каждого деплоя.
Бэкапы: --backup-dir и снапшоты через --link-dest
--backup --backup-dir=DIR сначала переносит в DIR каждый файл, который был бы перезаписан или удалён. Относительный DIR отсчитывается от приёмника, поэтому используйте ../, чтобы держать его рядом с копией:
rsync -a --delete --backup --backup-dir="../changed-$(date +%F)" /srv/site/ /backup/current/В строке crontab пишите \%F вместо %F: голый % cron считает переводом строки.
Для ежедневных снапшотов, которые выглядят как полные копии, но хранят только изменения, укажите в --link-dest вчерашнюю папку. Неизменённые файлы станут жёсткими ссылками:
rsync -a --link-dest=../2026-11-06 /srv/site/ /backup/2026-11-07/В нашем тесте у каждого неизменённого файла было две ссылки, а du -sh 2026-11-06 2026-11-07 насчитал 24K для первого снапшота и 8K для второго: один новый файл и сама папка. du учитывает файл с жёсткими ссылками один раз за запуск, поэтому второй снапшот сам по себе показывает свои полные 28K. Старый снапшот удаляется обычным rm -r; файлы, на которые ещё ссылаются более новые, остаются. Чтобы запускать его каждую ночь, Cron Expression Generator (англ.) соберёт и объяснит строку расписания.
Копирование между двумя серверами
The source and destination cannot both be remote.
rsync error: syntax or usage error (code 1) at main.c(1437) [Receiver=3.2.7]rsync не умеет передавать данные между двумя удалёнными хостами через себя, как это делает scp -3. Войдите на один сервер и запустите rsync там: ssh USER@SERVER_A "rsync -a /srv/data/ USER@SERVER_B:/srv/data/". Для этого на сервере A нужен ключ, который примет сервер B. Можно и пробросить свой агент через ssh -A, но тогда любой, у кого есть root на сервере A, может пользоваться этим агентом, пока вы подключены. Данные при этом идут напрямую между серверами, а не через ваш домашний канал.
Демон rsync (rsync://, порт 873)
Помимо SSH, rsync умеет работать с rsync --daemon на TCP-порту 873, который настраивается в /etc/rsyncd.conf с именованными модулями: rsync -av rsync://HOST/MODULE/ ./ или HOST::MODULE в старой записи. Через него раздают файлы зеркала дистрибутивов Linux. Протокол не шифруется, поэтому свои данные передавайте по SSH или держите демон в частной сети. В rsync 3.4.0 (январь 2025 года) исправлены шесть уязвимостей: часть — в демоне, часть позволяла вредоносному серверу атаковать клиента. Debian 12 перенёс исправления в свой пакет 3.2.7, так что ориентируйтесь на обновления apt, а не на номер версии.
Частые ошибки rsync
rsync: command not found на сервере
bash: line 1: rsync: command not found
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: remote command not found (code 127) at io.c(232) [sender=3.2.7]Первая строка пришла от оболочки сервера: rsync там нет. Установите его на сервере или укажите через --rsync-path копию, которая лежит вне PATH. На большинстве серверов эта строка английская. Если на сервере сгенерирована русская локаль, а SSH передал LANG (в Debian это включено по умолчанию: SendEnv LANG LC_* у клиента и AcceptEnv LANG LC_* у сервера), bash напишет bash: строка 1: rsync: команда не найдена. Две строки самого rsync остаются английскими в любом случае.
mkdir failed: No such file or directory (2)
rsync: [Receiver] mkdir "/srv/deep/a/b" failed: No such file or directory (2)
rsync error: error in file IO (code 11) at main.c(800) [Receiver=3.2.7]rsync создаёт только последний каталог пути на приёмнике. Добавьте --mkpath (3.2.3 и новее) или создайте родительские каталоги командой ssh USER@SERVER_IP mkdir -p /srv/deep/a.
Permission denied (13) и код 23
Строки вроде rsync: [receiver] mkstemp "/var/www/site/.index.html.…" failed: Permission denied (13), за которыми следует some files/attrs were not transferred (see previous errors) (code 23), значат, что пользователь, под которым вы вошли, не может писать в этот путь или читать этот файл. Исправьте владельца на приёмнике или воспользуйтесь вариантом с sudo из раздела про SSH. Код 24 (файлы исчезли во время передачи) нормален для живых каталогов с логами или кешем.
Connection refused, таймауты и Permission denied (publickey)
Это сбои SSH, а не rsync. Сначала идёт строка от ssh, а rsync добавляет к ней две свои:
deploy@203.0.113.10: Permission denied (publickey).
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: unexplained error (code 255) at io.c(232) [sender=3.2.7]Выполните ssh -v USER@SERVER_IP с тем же портом и сначала почините SSH; со стороны ключа поможет статья про Permission denied (publickey). Port Checker (англ.) покажет, отвечает ли порт SSH из интернета вообще.
Нужно место для этих бэкапов? VPS с большим диском от VMHeaven — полноценный KVM-сервер, который выбирают по объёму диска. Он рассчитан на приём данных от rsync, restic или Borg по SSH и стоит отдельно от машины, которую защищает.
Частые вопросы
Что значит слеш в конце пути в rsync?
Слеш у источника копирует содержимое папки: rsync -a site/ backup/ положит index.html прямо в backup/. Без слеша rsync копирует саму папку, и получится backup/site/index.html, даже если backup раньше не было. Слеш у приёмника при копировании папки ничего не меняет.
Как запустить rsync по SSH на нестандартном порту?
Передайте команду ssh через ключ -e: rsync -av -e "ssh -p 2222" ./site/ user@host:/var/www/site/. В кавычки можно добавить -i ~/.ssh/id_ed25519 для конкретного ключа или прописать Port и IdentityFile в ~/.ssh/config и использовать псевдоним вместо user@host.
Есть ли rsync для Windows?
Встроенного нет. Удобнее всего установить WSL и пользоваться rsync из Linux-дистрибутива внутри него; rsync при этом должен быть установлен и на сервере. Для разовой передачи файлов хватит scp, который входит в Windows. На macOS начиная с 15.4 /usr/bin/rsync — это openrsync с урезанным набором ключей, а полноценный rsync ставится через brew install rsync.