rsync на Linux: рабочие команды для бэкапа, деплоя и переноса
rsync — стандартный инструмент Linux для синхронизации файлов между каталогами и серверами по SSH. Делает инкрементальную копию (только изменения), сохраняет атрибуты, переживает обрывы. Разбираем главные флаги, инкрементальные бэкапы через `--link-dest`, типовые сценарии и грабли — наклонную черту в конце пути и `--delete`.
rsync: бэкапы, деплой и перенос файлов между серверами
rsync — стандартный инструмент Linux для синхронизации файлов между каталогами и серверами по SSH. Делает инкрементальную копию (только изменения), сохраняет атрибуты, переживает обрывы. Разбираем главные флаги, инкрементальные бэкапы через --link-dest, типовые сценарии и грабли — наклонную черту в конце пути и --delete.
Зачем rsync, а не cp или scp
Все три копируют файлы, но решают разные задачи:
cp— локальная копия. Не умеет в сеть, не различает «уже скопировано» и «новое».scp— копия по SSH. Тупо копирует всё каждый раз: 10 ГБ запросили — 10 ГБ перекачается.rsync— копия с дельта-протоколом. Сравнивает источник и приёмник, передаёт только изменившиеся блоки. На повторных синхронизациях экономит трафик в десятки раз.
Плюс к этому rsync:
- Сохраняет права, владельцев, времена модификации (
-a). - Переживает обрыв соединения —
--partialоставит частично скачанные файлы для дозакачки. - Поддерживает исключения через шаблоны.
- Работает локально, через SSH, через свой протокол на 873 порту, через демона
rsyncd.
На современных серверах вместо scp всё чаще берут sftp или rsync — scp объявлен устаревшим в OpenSSH с 2020 года.
Базовый синтаксис
rsync [опции] <откуда> <куда>
Источник и приёмник — локальные пути или user@host:путь. Минимальный пример — копирование локально:
rsync -av /opt/myapp/ /backup/myapp/
-a (--archive) — самый частый флаг. Объединяет:
-r— рекурсивно;-l— копировать симлинки как симлинки;-p— сохранять права (chmod);-t— сохранять времена модификации (важно для повторных синхронизаций!);-g/-o— сохранять группу и владельца;-D— копировать device и special-файлы.
-v (--verbose) — показывать что копируется. Для прода в скриптах — наоборот, лучше -q, чтобы не засорять логи.
Сухой прогон (показать что бы сделалось, не делая):
rsync -av --dry-run /opt/myapp/ /backup/myapp/
--dry-run (или -n) — обязательная привычка перед командами с --delete. Один раз увидите «о, я тут хотел не это», и поймёте, зачем.
Топ-флаги для типовых задач
| Флаг | Что делает |
|---|---|
-a |
архивный режим (см. выше) — стандарт для бэкапов |
-v / -q |
verbose / quiet |
-h |
человекочитаемые размеры (1.2K вместо 1234) |
-z |
сжатие в пути (полезно через медленную сеть) |
-P |
--partial --progress — прогресс-бар + дозакачка |
--delete |
удалять в приёмнике то, чего нет в источнике |
--exclude='pattern' |
исключение по шаблону |
--exclude-from=file |
исключения из файла |
--link-dest=DIR |
hardlink-снапшоты (инкрементальные бэкапы) |
--bwlimit=2M |
лимит скорости (KB/s) — чтобы не положить канал |
-e ssh |
использовать SSH (по умолчанию для удалённых) |
--rsync-path='sudo rsync' |
запустить rsync на удалённой стороне через sudo |
Универсальная команда для бэкапа, которую держу в голове:
rsync -avhP --delete --exclude='.git' --exclude='node_modules' \
/opt/myapp/ user@backup.example.com:/backup/myapp/
Синхронизация между серверами по SSH
Удалённый источник или приёмник пишется как user@host:путь:
# Локальное → удалённое (push)
rsync -avhP /opt/myapp/ deploy@web-01:/var/www/myapp/
# Удалённое → локальное (pull)
rsync -avhP deploy@web-01:/var/log/nginx/ ./nginx-logs/
# Между двумя удалёнными — НЕ работает без --remote!
# rsync через локальный хост:
rsync -avhP src.example.com:/path/ dst.example.com:/path/
Если на удалённом сервере SSH на нестандартном порту — пробрасываем через -e:
rsync -avhP -e "ssh -p 22022" /opt/myapp/ user@host:/path/
Для скриптовой автоматизации — настройте SSH-ключ без пароля, чтобы rsync не запрашивал пароль каждый раз.
Грабли с trailing slash
Это самая частая ошибка в rsync. Слэш в конце источника меняет поведение:
# Без слеша в конце — копирует ПАПКУ src внутрь dst
rsync -av /opt/src /backup/
# Результат: /backup/src/...
# Со слешем в конце — копирует СОДЕРЖИМОЕ src внутрь dst
rsync -av /opt/src/ /backup/
# Результат: /backup/...
Запомните мнемоникой: «слеш = содержимое». Хотите перенести папку целиком — без слеша. Хотите вылить её содержимое в существующий каталог — со слешем.
В приёмнике (dst) слеш игнорируется — там разницы нет.
--delete: опасный, но нужный
По умолчанию rsync не удаляет в приёмнике файлы, которых нет в источнике. Они просто остаются. Для зеркальной синхронизации (приёмник = точная копия источника) добавляют --delete:
rsync -av --delete /opt/myapp/ /backup/myapp/
После такой команды /backup/myapp/ будет точно соответствовать /opt/myapp/ — старые файлы из бэкапа удалятся, если они отсутствуют в источнике.
Грабли:
- Если перепутать источник и приёмник, удалите свои данные. Поэтому всегда
--dry-runперед--delete. - Если в источнике что-то пропадёт по ошибке (случайно вы запустили
rm -rf node_modulesи потом синхронизировались), это унесёт за собой версию в бэкапе.--deleteне подходит для долгосрочных бэкапов как единственный механизм — нужны снапшоты.
Безопасные альтернативы для бэкапов:
--backup --backup-dir=archive-YYYYMMDD— переносит удаляемые файлы в архивный каталог.--link-dest— инкрементальные снапшоты (см. ниже).
Инкрементальные бэкапы через --link-dest
Самый полезный паттерн rsync для бэкапов — серия снапшотов с hardlink-ами на неизменённые файлы. Размер каждого снапшота приближается к размеру изменений, а не к размеру всего исходника.
Идея: каждый день делаем бэкап в новый каталог, но передаём rsync ссылку на предыдущий каталог через --link-dest. Если файл не изменился — rsync не копирует его, а делает hardlink на старый. На диске файл лежит один раз, но виден в обоих каталогах.
#!/bin/bash
set -euo pipefail
SRC=/opt/myapp/
DEST_BASE=/backup/myapp
DATE=$(date +%Y%m%d-%H%M)
DEST=$DEST_BASE/$DATE
LATEST=$DEST_BASE/latest
mkdir -p "$DEST_BASE"
if [[ -d "$LATEST" ]]; then
rsync -aH --delete --link-dest="$LATEST" "$SRC" "$DEST/"
else
rsync -aH --delete "$SRC" "$DEST/"
fi
# Обновляем симлинк latest на свежий бэкап
ln -snf "$DEST" "$LATEST"
# Удаляем бэкапы старше 30 дней
find "$DEST_BASE" -maxdepth 1 -type d -mtime +30 -exec rm -rf {} +
Что важно:
-H— сохранять hardlink-структуру (по умолчанию rsync не отслеживает hardlink-и между файлами).--link-destработает только если каталог существует и доступен на чтение.- При просмотре
du -hкаждый снапшот показывает полный размер, ноdfподтвердит, что физически они занимают мало. - Восстановление любого дня — это просто копия из соответствующего каталога.
Запуск раз в час/сутки — через cron или systemd-таймер. Для деления нагрузки добавьте ionice -c 3 или --bwlimit.
Исключения
Чаще всего нужно исключить временные/мусорные каталоги:
rsync -av \
--exclude='.git' \
--exclude='node_modules' \
--exclude='__pycache__' \
--exclude='*.pyc' \
/opt/myapp/ /backup/myapp/
Шаблоны как у gitignore: * — любая последовательность кроме /, ** — включая /, ? — один символ.
При большом списке выносим в файл:
# /etc/myapp/rsync-exclude.txt
.git
node_modules
__pycache__
*.pyc
.cache/
*.tmp
И:
rsync -av --exclude-from=/etc/myapp/rsync-exclude.txt /opt/myapp/ /backup/myapp/
Обратные правила: --include='pattern' плюс --exclude='*' — для узких whitelist'ов.
Прогресс и продолжение
Большой перенос (десятки ГБ) хочется видеть и переживать обрывы:
rsync -avhP /opt/data/ user@backup:/data/
-P объединяет:
--progress— прогресс-бар на каждый файл.--partial— оставлять частично скачанный файл, чтобы при следующем запуске rsync смог его дозакачать с того же места.
Без -P обрыв на 9 ГБ файле начнёт с 0. С -P — продолжит. Для длинных переносов держите команду в tmux или screen, чтобы пережить отпадание SSH.
Боевые сценарии
1. Бэкап /etc перед изменениями.
sudo rsync -avh --delete /etc/ /backup/etc-$(date +%Y%m%d)/
Простой снапшот конфигов. На btrfs можно использовать btrfs-снапшот — он мгновенный.
2. Деплой кода на удалённый сервер.
rsync -avh --delete \
--exclude='.git' \
--exclude='.env' \
--exclude='node_modules' \
./ deploy@web-01:/var/www/myapp/
--delete обеспечивает, что приёмник = источник один к одному. --exclude='.env' — критично, чтобы локальный development-конфиг не попал в прод.
3. Перенос пользовательских данных при миграции сервера.
sudo rsync -avhP --delete \
-e "ssh -p 22022 -i ~/.ssh/migration_key" \
--rsync-path='sudo rsync' \
/home/ root@new-server:/home/
--rsync-path='sudo rsync' запустит rsync под sudo на удалённой стороне — нужно для копирования с сохранением владельцев. Альтернатива — sudo-без-пароля для пользователя на новом сервере, см. sudo.
4. Зеркало логов nginx с web-серверов на лог-сервер.
# /etc/cron.d/nginx-log-mirror
0 * * * * deploy /usr/bin/rsync -aq --append /var/log/nginx/ \
log-server:/logs/web-01/ 2>&1 | logger -t nginx-log-mirror
--append дозаписывает файлы, не пересоздавая — оптимально для растущих логов.
5. Синхронизация двух директорий локально с удалением мусора.
rsync -av --delete --exclude='*.tmp' /var/cache/myapp/ /var/cache/myapp-backup/
Грабли rsync
--deleteбез--dry-run— рискованно. Один лишний слеш или перепутанный источник/приёмник — и удалили данные.- Trailing slash меняет поведение источника. Запомните: «слеш = содержимое, без слеша = папка».
-aне сохраняет hardlink-и. Если структура с hardlink-ами важна, добавляйте-H.- Атрибуты ACL и xattr не сохраняются дефолтно. Для них — флаги
-Aи-X. - Sparse-файлы (с дырами): без
-Srsync развернёт их в обычные большие. Для VM-образов и баз данных — обязательно-S. - Большие файлы по медленной сети. Дельта-алгоритм rsync чексуммит файлы блоками по 700 байт — на больших файлах это медленно. Для огромных архивов и образов VM лучше пересдать через
scpилиdd+pv. --rsync-path='sudo rsync'требует, чтобы пользователь на удалённом мог выполнятьsudo rsync— иногда нужно настроитьNOPASSWDчерез sudoers, см. sudo.
Частые вопросы
Что такое rsync в Linux
Утилита для синхронизации файлов между каталогами и серверами с дельта-протоколом: при повторных запусках копирует только изменения. Стандартный инструмент бэкапов и деплоя в Linux/UNIX-мире. Работает локально и удалённо по SSH или собственному протоколу на 873 порту.
Чем rsync отличается от scp
scp всегда копирует все указанные файлы целиком. rsync сравнивает источник и приёмник и передаёт только изменения — на повторных синхронизациях это в десятки раз быстрее. Плюс rsync переживает обрывы (--partial), сохраняет атрибуты, поддерживает исключения и инкрементальные бэкапы. С 2020 года scp объявлен устаревшим в OpenSSH.
Как сделать инкрементальный бэкап через rsync
Через флаг --link-dest=PREVIOUS_DIR. rsync будет создавать hardlink-и на неизменённые файлы из предыдущего бэкапа, физически копируя только изменения. Каждый снапшот выглядит как полный, но на диске занимает только размер дельты. Стандартный паттерн — каталог-снапшот в имени с датой и симлинк latest на последний.
Что значит trailing slash в rsync
Слеш в конце пути источника. С трейлинг-слешем — копируется содержимое каталога. Без него — копируется сам каталог как поддиректория. Запомните: «src/ — содержимое внутрь, src — папку целиком». В приёмнике слеш не имеет значения.
Безопасно ли использовать --delete в rsync
Только с --dry-run сначала. --delete удаляет в приёмнике файлы, которых нет в источнике. Перепутаете источник и приёмник или передадите пустой источник — потеряете данные. На критичных бэкапах добавляйте --backup --backup-dir= для архива удалённых файлов или используйте --link-dest-снапшоты вместо --delete-зеркала.
Как ограничить скорость rsync чтобы не положить канал
Флаг --bwlimit=KBPS. Например, --bwlimit=10M — не больше 10 МБ/с. На медленных каналах или при синхронизации в рабочее время это спасает от перегрузки. Альтернатива — обернуть в trickle или ограничить через tc на уровне ОС.
Как rsync работает через SSH
По умолчанию rsync для удалённых путей user@host:path запускает ssh user@host rsync ... — то есть на той стороне тоже должен стоять rsync. Передача шифруется как в обычной SSH-сессии. Нестандартный порт — через -e "ssh -p N". Для пассивного выполнения настраивайте SSH-ключ без пароля.
Что запомнить
-avh— стандартное сочетание для бэкапов: архивный режим, verbose, человекочитаемые размеры. ДобавляйтеPдля длинных переносов.- Перед
--delete— всегда--dry-run. Эта привычка спасёт ваши данные. src/(со слешем) — копировать содержимое.src(без слеша) — папку целиком.- Для инкрементальных бэкапов используйте
--link-dest— серия снапшотов с hardlink-ами занимает только размер изменений. - Для удалённого копирования настройте SSH-ключ. Это критично для скриптов в cron или systemd-таймерах.
- Не забывайте
--exclude='.git','.env','node_modules'при деплое и бэкапе кода — они почти всегда лишние и тяжёлые.
Обложка: фото Vincent Botta с Unsplash, лицензия Unsplash.