MHOSTMHOST

Резервное копирование с rsync

rsync копирует каталоги быстро и экономно, передавая только изменившиеся данные, — локально на другой диск или на удалённый сервер по SSH. В этой статье: ключевые флаги -a, -v, -z, --delete, бэкап каталога на другой сервер mHost и скрипт-обёртка, которую можно поставить на расписание через cron.

Что понадобится

  • VPS mHost на Ubuntu 22.04/24.04, Debian 11/12 или AlmaLinux/Rocky Linux 8/9 — сервер-источник, который нужно бэкапить.
  • Второй сервер (например, ещё один VPS mHost) или отдельный диск/раздел на этом же сервере — куда складывать копии.
  • Доступ по SSH под root либо пользователем с правами sudo: к серверу-источнику, а для удалённого варианта — и к серверу назначения.
  • Пакет rsync — обычно уже есть в системе, но стоит проверить (шаг 1).
Совет: команды ниже даны с sudo. Если вы уже подключены как root и sudo в системе нет — выполняйте те же команды без префикса sudo.

Ключевые флаги: -a, -v, -z, --delete

Флаг -a (--archive) — самый важный: это сокращение для -rlptgoD. rsync рекурсивно обходит каталоги (-r), сохраняет символические ссылки как ссылки (-l), права доступа (-p), время модификации (-t), группу (-g) и владельца (-o), а также файлы устройств и спецфайлы (-D). При этом -a не сохраняет ACL (-A), расширенные атрибуты (-X), время последнего доступа (-U), время создания (-N) и жёсткие ссылки (-H) — при необходимости их нужно добавлять отдельно.

  • -v (--verbose) — выводит список передаваемых файлов и краткую сводку в конце. Для большей детализации используйте -vv.
  • -z (--compress) — сжимает данные на лету перед передачей по сети. Заметно помогает на медленных или ограниченных по трафику каналах; на быстрой сети между серверами в одном дата-центре выигрыш обычно небольшой, а для уже сжатых файлов (архивы, видео, изображения) — почти нулевой.
  • --delete — удаляет на приёмнике файлы, которых уже нет в источнике, чтобы копия оставалась точным зеркалом, а не просто накапливала файлы годами.
Важно: --delete — потенциально опасный флаг: неверный путь в команде — и можно удалить не то и не там. Перед первым запуском команды с --delete обязательно проверьте её с флагом -n (--dry-run) — rsync покажет, что должно произойти, но ничего не изменит на диске.
Совет: обращайте внимание на слэш в конце пути источника. rsync -avz /var/www/ /mnt/backup/ скопирует содержимое каталога /var/www внутрь /mnt/backup. А rsync -avz /var/www /mnt/backup (без слэша у источника) создаст внутри /mnt/backup ещё один вложенный каталог www. Ставьте слэш в конце пути источника — и для единообразия так же у приёмника — одинаково во всех командах и в скрипте: это самая частая ошибка при первом знакомстве с rsync.

Шаг 1. Убедитесь, что rsync установлен

rsync нужен на обеих сторонах — и на сервере-источнике, и на сервере, куда складываются копии.

Проверьте, установлен ли он:

bash
rsync --version

Если команда не найдена — установите пакет.

Ubuntu / Debian:

bash
sudo apt update
sudo apt install -y rsync

AlmaLinux / Rocky Linux:

bash
sudo dnf install -y rsync

Повторите проверку (и, если нужно, установку) на обоих серверах.

Шаг 2. Настройте вход по SSH-ключу на сервер назначения

Скрипт-обёртка (шаг 5) и cron (шаг 6) будут запускать rsync без вашего участия — вход по паролю здесь не подойдёт, нужна аутентификация по SSH-ключу без passphrase. Выполните команды ниже на сервере-источнике, под тем пользователем, от имени которого будет работать бэкап (обычно root).

  1. Сгенерируйте отдельный ключ для бэкапов:
bash
ssh-keygen -t ed25519 -f /root/.ssh/id_rsync_backup -N ""

-N "" — пустая passphrase: без неё скрипт, запущенный из cron, не сможет ввести пароль от ключа.

Важно: ключ без passphrase — осознанный компромисс ради автоматизации. Используйте его только для этой задачи; на сервере назначения по возможности заведите отдельного пользователя, у которого есть доступ только к каталогу с бэкапами.
  1. Скопируйте публичный ключ на сервер назначения — backup в примере ниже может быть любым существующим на сервере назначения пользователем (в том числе root), у которого есть доступ на запись в целевой каталог:
bash
ssh-copy-id -i /root/.ssh/id_rsync_backup.pub backup@203.0.113.10

При первом запуске ssh-copy-id спросит пароль (или воспользуется вашим текущим ключом) для входа на backup@203.0.113.10 — это нормально, дальше новый ключ будет пускать без пароля.

Замените backup@203.0.113.10 на пользователя и адрес вашего сервера назначения.

  1. Проверьте, что подключение проходит без пароля:
bash
ssh -i /root/.ssh/id_rsync_backup backup@203.0.113.10 "echo OK"

Если в ответ пришло OK без запроса пароля — можно переходить к самому rsync.

Шаг 3. Локальная синхронизация каталога

Локальный вариант полезен, если нужно зеркалировать каталог на другой диск, раздел или примонтированное сетевое хранилище на этом же сервере — без SSH и второго сервера.

Сначала — пробный прогон с -n (--dry-run), ничего не меняющий на диске:

bash
rsync -avzn --delete /var/www/ /mnt/backup/www/

Проверьте вывод и, если всё выглядит верно, запустите по-настоящему (без -n):

bash
rsync -avz --delete /var/www/ /mnt/backup/www/
Совет: если каталог /mnt/backup/www/ ещё не существует, создайте его заранее: mkdir -p /mnt/backup/www. Более новые версии rsync умеют создавать недостающие каталоги на лету через флаг --mkpath, но заранее созданный каталог работает одинаково надёжно в любой версии.

Шаг 4. Бэкап каталога на другой сервер по SSH

Отличие от локального варианта — приёмник указывается как пользователь@хост:путь, через двоеточие. Сначала — тот же пробный прогон:

bash
rsync -avzn --delete -e "ssh -i /root/.ssh/id_rsync_backup" /var/www/ backup@203.0.113.10:/backup/myserver/www/

Проверьте вывод и запустите по-настоящему:

bash
rsync -avz --delete -e "ssh -i /root/.ssh/id_rsync_backup" /var/www/ backup@203.0.113.10:/backup/myserver/www/

Что добавилось по сравнению с локальным вариантом:

  • backup@203.0.113.10:/backup/myserver/www/ — пользователь, IP (или домен) сервера назначения и путь на нём.
  • -e "ssh -i /root/.ssh/id_rsync_backup" — явно указывает rsync использовать SSH с конкретным файлом ключа из шага 2. Если бы ключ лежал под стандартным именем (~/.ssh/id_ed25519 или id_rsa) на стандартном 22-м порту, -e можно было бы вообще не указывать — современный rsync и так использует SSH по умолчанию. -e нужен, когда SSH требуются нестандартные параметры: свой файл ключа или нестандартный порт (-e "ssh -p 2222 -i /root/.ssh/id_rsync_backup").

Как и в локальном варианте, заранее создайте каталог на сервере назначения:

bash
ssh -i /root/.ssh/id_rsync_backup backup@203.0.113.10 "mkdir -p /backup/myserver/www"
Совет: это переиспользует тот же SSH-порт, через который вы уже администрируете сервер назначения, — открывать в файрволе что-то новое не требуется. Если вы настраиваете ufw на сервере назначения с нуля, не забудьте сначала разрешить сам SSH — см. статью «Файрвол ufw».

Шаг 5. Скрипт-обёртка для регулярных бэкапов

Чтобы не набирать команду вручную, оформите её в скрипт: с логом, обработкой ошибок и защитой от повторного запуска, если предыдущий бэкап ещё не завершился.

Создайте файл:

bash
sudo nano /usr/local/sbin/rsync-backup.sh

Содержимое:

bash
#!/usr/bin/env bash
set -euo pipefail

# Source directory and backup destination
SRC="/var/www/"
DEST_USER="backup"
DEST_HOST="203.0.113.10"
DEST_PATH="/backup/myserver/www/"
SSH_KEY="/root/.ssh/id_rsync_backup"

LOG_FILE="/var/log/rsync-backup.log"
LOCK_FILE="/var/lock/rsync-backup.lock"

# Prevent overlapping runs if the previous backup is still going
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
  echo "$(date '+%Y-%m-%d %H:%M:%S') Previous backup is still running, exiting" >> "$LOG_FILE"
  exit 1
fi

echo "$(date '+%Y-%m-%d %H:%M:%S') Backup started" >> "$LOG_FILE"

if rsync -avz --delete -e "ssh -i ${SSH_KEY}" "$SRC" "${DEST_USER}@${DEST_HOST}:${DEST_PATH}" >> "$LOG_FILE" 2>&1; then
  echo "$(date '+%Y-%m-%d %H:%M:%S') Backup finished OK" >> "$LOG_FILE"
else
  echo "$(date '+%Y-%m-%d %H:%M:%S') Backup FAILED" >> "$LOG_FILE"
  exit 1
fi

Сделайте скрипт исполняемым и доступным только root:

bash
sudo chmod 700 /usr/local/sbin/rsync-backup.sh

Запустите вручную и проверьте лог:

bash
sudo /usr/local/sbin/rsync-backup.sh
tail -n 20 /var/log/rsync-backup.log
Готово: если в логе — «Backup finished OK» и файлы появились на сервере назначения, скрипт готов к постановке в расписание.
Совет: замените SRC, DEST_USER, DEST_HOST, DEST_PATH и SSH_KEY в начале скрипта на свои значения — остальную логику (лог, блокировку от повторного запуска, обработку ошибок) менять не нужно.

Шаг 6. Поставьте скрипт на расписание в cron

Откройте crontab пользователя root (того же, под кем настроен SSH-ключ в шаге 2):

bash
sudo crontab -e

Добавьте строку — например, ежедневный запуск в 02:30:

30 2 * * * /usr/local/sbin/rsync-backup.sh

Скрипт сам ведёт лог в /var/log/rsync-backup.log, поэтому дополнительно перенаправлять вывод в crontab не обязательно.

Подробный разбор синтаксиса cron, других вариантов расписания (по часам, по дням недели) и типичных ошибок — в статье «Автоматизация бэкапов через cron».

Что дальше

rsync с --delete хранит только последнее состояние каталога, а не версии и историю: если файл случайно испортился давно, старой копии уже не будет — её удалит тот же --delete. Для версионных и зашифрованных бэкапов с дедупликацией посмотрите статью про restic: «Резервное копирование с restic».