ServerAID
Найти гайд, команду, тег… ⌘ K
Сервер

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 или rsyncscp объявлен устаревшим в 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 — инкрементальные снапшоты (см. ниже).

Самый полезный паттерн 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-файлы (с дырами): без -S rsync развернёт их в обычные большие. Для 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.

Похожие материалы

Сервер

Установка Ubuntu Server 24.04 LTS: пошаговый гайд от ISO до первого SSH

Ставим Ubuntu Server 24.04 LTS с нуля: загрузочная флешка, разметка диска под LVM, статический IP, OpenSSH с ключами и базовая защита перед первым `apt update`. Гайд работает и для свежих установок 22.04 / 26.04 — отличия минимальные, отметили по тексту.

Редакция
Сервер

systemd unit и systemctl enable: что делают, чем отличаются от start

Команда `systemctl enable` создаёт симлинки, чтобы сервис стартовал при загрузке системы. Разбираем разницу с `start`, шорткат `--now`, свой unit-файл с `Restart=always`, пользовательские сервисы и частые ошибки на Ubuntu 24.04 LTS.

Редакция
Безопасность

Let's Encrypt и certbot на Ubuntu: бесплатный SSL для nginx

Let's Encrypt — бесплатные SSL/TLS-сертификаты для любого домена. На Ubuntu выпускаются через утилиту certbot одной командой; автообновление работает само через systemd-таймер. Разбираем установку, выпуск для nginx, DNS-challenge для wildcard-сертификатов и грабли с rate-limit.

Редакция
Shell и скрипты

sed на Linux: замена строк, правка in-place и регулярки

sed (stream editor) — стандартная команда Linux для построчной обработки текста: замена, удаление, печать строк по шаблону. Работает с потоком (pipe) или файлами, поддерживает in-place редактирование. Базовый инструмент шелл-скриптов после `grep` и `awk`.

Редакция