Полная копия Linux сервера через rsync выглядит простым делом: одна команда, пара часов ожидания, готовый каталог. Неожиданности приходят при восстановлении: утилиты требуют прав суперпользователя, базы не стартуют из-за несогласованных файлов. Причины почти всегда одни: потерянные расширенные атрибуты, перепутанные владельцы, разъехавшееся состояние баз. Ниже - механика ключей rsync, рабочая команда с исключениями, ловушки с правами и план проверки копии до первого сбоя.

Архивный флаг rsync и его настоящие границы при копировании системы

Флаг -a в вызовах rsync называют архивным, он разворачивается в набор -rlptgoD. За буквами стоят гарантии: -r обходит каталоги рекурсивно, -l переносит символические ссылки как ссылки, -p сохраняет права доступа, -t хранит время модификации, -g и -o отвечают за группу и владельца, -D переносит файлы устройств и специальные объекты. Для системной копии этого мало.

Жёсткие ссылки архивный набор не трогает: без ключа -H два имени одного inode превратятся в два независимых файла. Ключ -H объединяет дубли по номерам inode, но заметно увеличивает расход памяти, поэтому по умолчанию выключен. Расширенные атрибуты и списки контроля доступа в набор не входят, для них есть ключи -X и -A, ставить их принято всегда, когда копия предназначена для восстановления. Время изменения метаданных ctime не переносит никто: его назначает само ядро.

Ключ --numeric-ids заслуживает отдельного упоминания: по умолчанию rsync сопоставляет числовые идентификаторы именам пользователей и ищет их на приёмной стороне. Если на сервере под номером 105 числится аккаунт базы данных, а на приёмной машине под ним сидит другой пользователь, копия получит чужие права. Ключ переносит числа как есть, для системной копии он обязателен.

Расширенные атрибуты и списки контроля доступа в реальной работе сервера

Расширенные атрибуты - это пары "имя - значение", живущие в inode рядом с правами. Пространства имён строго разделены: user. доступно владельцу, trusted. выставляет только суперпользователь, в security. читает и пишет ядро, там лежат метки SELinux и capabilities, дающие программе ограниченные привилегии без бита setuid. В system. хранятся списки контроля доступа POSIX, потому у rsync для них отдельный ключ -A, надёжнее ставить оба ключа сразу.

Что ломается от потери, видно по месту применения. Утилита проверки сети на многих современных системах создаёт сокеты через capabilities, а не через setuid: сотрите атрибут - и она перестаёт работать от обычного пользователя. На серверах с SELinux пропажа меток security.selinux означает, что службы не пройдут проверку политики и систему придётся перемаркировать. Списки контроля доступа задают тонкие права для отдельных пользователей, их пропажу замечают позже всего.

Утилиты пакета attr показывают картину: без маски getfattr выводит только user., ключ -m - раскрывает все пространства, чтение security. требует прав суперпользователя.

getfattr -d /srv/report.xlsx
getfattr -d -m - /usr/bin/ping

Тонкость: флаги lsattr вроде immutable живут во внутренних полях inode, к расширенным атрибутам не относятся, rsync их не переносит. Файлы, защищённые chattr, собирают списком через lsattr -Ra и воспроизводят вручную после восстановления.

Готовая команда копирования Linux сервера с продуманными исключениями

Команда запускается от имени суперпользователя и складывает корень в /mnt/backup, куда смонтирован отдельный диск:

rsync -aHAXSx --numeric-ids --delete --info=progress2 \
  --exclude=/proc/* --exclude=/sys/* --exclude=/dev/* \
  --exclude=/run/* --exclude=/tmp/* --exclude=/var/tmp/* \
  --exclude=/var/lib/docker/* --exclude=/var/lib/libvirt/images/* \
  --log-file=/root/rsync-full.log \
  / /mnt/backup/

За исключениями логика. Каталог /proc ядро генерирует на лету: файлы внутри - окна в состояние процессов, копировать их бессмысленно. Дерево /sys описывает объекты ядра, /dev строит при загрузке udev, /run живёт в tmpfs и хранит состояние служб. Хранилище контейнеров /var/lib/docker меняется на лету и копируется родными инструментами платформы, образы виртуальных машин заслуживают отдельной политики.

Тонкая деталь в записи масок. Исключение /proc/* со звёздочкой убирает содержимое каталога, но оставляет сам каталог пустым, и это принципиально: при загрузке ядро смонтирует в /proc, /sys, /dev и /run виртуальные файловые системы. Без звёздочки исчез бы сам каталог, и точек монтирования в системе не будет.

Ключ -x запрещает rsync переходить границы смонтированных файловых систем, это страховка от забытой строки; плата - отдельные разделы вроде /boot прогон не увидит. Ключ -S сохраняет разрежённые файлы без раскатывания нулей в реальные блоки, --info=progress2 показывает общий прогресс вместо мельтешения процентов.

Осторожнее с --delete: ключ приводит приёмный каталог к точному зеркалу и убирает лишнее, а при опечатке в пути источника вычищает зеркало подчистую. Правило одно: сначала прогон с --dry-run, по списку, потом настоящая команда.

Код возврата смотрите через echo $?. Ноль - полное перенесение, 23 - часть файлов или атрибутов не перенеслась, 24 встречается на живой системе: файлы исчезали во время работы. Лог пишется штатным ключом --log-file, а не через конвейер с tee, конвейер подменяет код возврата.

Живой сервер меняется во время копирования и пути к консистентной копии

Копирование нагруженного сервера длится десятки минут и часы: журналы дописываются, базы держат часть данных в памяти и сбрасывают страницы на диск вразнобой. Копия фиксирует полосу состояний, файлы данных и журнал предзаписи относятся к разным моментам, и исход восстановления базы не гарантирован.

Первый путь к честному состоянию - окно обслуживания: службы останавливаются, rsync снимает единственно верное состояние, службы запускаются обратно. Имена служб у каждой системы свои, суть одна - записи должны прекратиться.

systemctl stop mariadb postgresql
rsync -aHAXSx --numeric-ids --exclude=/proc/* --exclude=/sys/* \
  --exclude=/dev/* --exclude=/run/* --exclude=/tmp/* \
  / /mnt/backup/
systemctl start mariadb postgresql

Второй путь - снапшот LVM: том переводится в режим копирования при записи, снапшот фиксирует состояние на одну секунду, изменения уходят в отдельную область. Снапшот монтируется только для чтения и служит стабильным источником, псевдофайловые системы в снимок корневого тома не входят, длинные исключения не нужны.

lvcreate -s -n root_snap -L 20G vg0/root
mount -o ro,nouuid /dev/vg0/root_snap /mnt/snap
rsync -aHAXS --numeric-ids /mnt/snap/ /mnt/backup/
umount /mnt/snap
lvremove -f /dev/vg0/root_snap

Опция nouuid нужна томам XFS: у снапшота идентификатор файловой системы совпадает с оригиналом, и монтирование рядом без неё запрещено. От группы томов нужен запас места под область изменений, иначе снапшот переполнится. Состояние баз внутри равносильно резкой остановке: движок достроит данные по журналу, но согласованный дамп надёжнее. Третий путь - снапшоты Btrfs и ZFS, они создаются мгновенно. Четвёртый закрывает данные отдельно: дампы утилитами вроде pg_dump и mysqldump дают согласованный снимок без остановки службы; файловая копия хранит конфигурацию, дамп - данные.

Суперпользователь на обеих сторонах и числовые идентификаторы владельцев

Назначить владельца, перенести файл устройства и записать атрибуты из security и trusted способен только суперпользователь, причём на обеих сторонах: источник обязан прочитать всё, включая файлы с правами 600 чужих учётных записей, приёмник обязан расставить владельцев заново. Если приёмник работает под обычным пользователем, лог заполнят отказы chown, копия выйдет промаркированной одним пользователем, и восстановленная система неработоспособна: passwd, shadow и конфигурации баз принадлежат случайному аккаунту.

Прямой вход root по ssh часто закрыт настройкой PermitRootLogin, и схемы расходятся на три: rsync-служба (daemon) на приёмнике с модулем от имени root, права через sudo на исходнике с ключом --rsync-path="sudo rsync" и записью в sudoers без пароля, либо разовый честный сеанс с root на обеих сторонах; он проще, а схема с sudo передаёт права сервисной команде.

Отдельная история - приёмник без root: сетевое хранилище, облако с обычной учётной записью. Тут выручает --fake-super: приёмный rsync записывает владельца, группу, права и времена в расширенные атрибуты семейства user.rsync.*, а их владелец файла ставить вправе. Видимый владелец в ls остаётся учётной записью приёмника, а при обратном переносе rsync назначает настоящих владельцев, если принимающая машина работает под root. Плата: приёмная система обязана поддерживать расширенные атрибуты, метки видны посторонним утилитам. Это страховка для жёстких ограничений, а не замена копии под root.

rsync -aHAXS --numeric-ids --fake-super --info=progress2 \
  root@server:/ /mnt/nas/backup/server/

Поддержка атрибутов приёмной файловой системой и тихие потери метаданных

Приёмная файловая система решает, какие метаданные сохранятся. Локальные ext4, XFS и btrfs держат атрибуты и списки контроля доступа без дополнительных флагов монтирования. Разделы vfat и exFAT не знают ни прав POSIX, ни xattr: rsync сведёт права к маске монтирования, атрибуты отбросит. У NTFS своя модель доступа, драйвер Linux сопоставляет её с POSIX частично. Поведение NFS зависит от версии протокола и настроек сервера: user. может сохраниться, security. - нет. Готовые сетевые хранилища часто отдают наружу протоколы без метаданных, и копия теряет владельцев незаметно.

Проверка приёмника стоит копейки: положите в тестовый каталог файлы с разными атрибутами, прогоните рабочую команду и сравните вывод. Пустой getfattr - приговор носителю, меняйте диск или протокол, а не ключи команды. Заодно взгляните на df -i: исчерпание inode на миллионах мелких файлов обрывает копию на полпути.

rsync -aHAXS --numeric-ids /srv/probe/ /mnt/backup/probe/
getfattr -d -m - /mnt/backup/probe/capable.bin
getfacl /mnt/backup/probe/shared.txt

Проверка копии от chroot теста до загрузки в виртуальной машине

Непроверенная копия остаётся предположением. Рабочая лестница проверки выглядит так:

  1. контрольный прогон rsync с ключами --dry-run и --itemize-changes: для остановленного источника список расхождений обязан быть пустым, для живого покажет накопившиеся отличия;
  2. сверка атрибутов на образцовых файлах: getfattr -d -m - под root показывает security.* у источника и копии, вывод сравнивают через diff;
  3. выборочная сверка контрольных сумм: вывод sha256sum для нескольких системных файлов обязан совпасть символ в символ;
  4. chroot проверка каталога копии: система должна выполнять команды, читать конфигурации и хранить capabilities на системных утилитах;
  5. полная репетиция восстановления: копия переносится на виртуальный диск, получает загрузчик и грузится в виртуальной машине до приглашения входа.

Каталоги /proc, /sys и /dev в копии уже существуют, спасибо маскам со звёздочкой. Осталось подмонтировать их, войти и после выхода отмонтировать в обратном порядке:

mount --bind /proc /mnt/backup/proc
mount --bind /sys /mnt/backup/sys
mount --bind /dev /mnt/backup/dev
chroot /mnt/backup /bin/bash
exit
umount /mnt/backup/dev /mnt/backup/sys /mnt/backup/proc

В виртуальной машине создаётся новый диск, копия переносится на него тем же rsync, затем чинятся две вещи. В /etc/fstab корень и подкачка указаны UUID старого диска, у нового значения другие: blkid покажет фактические, fstab правят под них. Загрузчик в файловую копию не входит, его ставят grub-install и пересобирают конфигурацию, команды в Debian и Red Hat различаются написанием. Копии, которой предстоит жить рядом с оригиналом, полагается собственный идентификатор в /etc/machine-id и отдельные сетевые настройки.

После загрузки проверка короткая:

systemctl --failed
journalctl -b -p err --no-pager

Пустой список сбойных служб и короткий журнал ошибок - лучший финал репетиции.

Копия, которая загрузилась в виртуальной машине, сохранила capabilities утилит, запустила базы и показала согласованные права, имеет право называться резервной, всё остальное - черновик. Ни владелец, ни атрибут, ни маска исключения не спрячутся внутри монолитного образа, за упущение система спросит при восстановлении. Полный цикл проверки закрывает вопрос, а первый успешный перенос превращает процедуру в рабочий инструмент.