Когда нужно переехать на другой сервер, обычно хочется двух вещей: чтобы данные доехали целыми и чтобы пользователи почти не заметили простоя. rsync — один из самых надёжных и предсказуемых инструментов для такой миграции: он копирует только изменения, сохраняет права и хорошо подходит для «длинного» первичного прогона плюс «короткого» финального.
Ниже — рабочая схема переезда «почти без простоя» для типового LEMP/LAMP-сайта: статика, загрузки, конфиги приложения и (отдельно) база данных. Мы используем rsync как транспорт для файлов; для БД выделяем отдельный этап, потому что rsync не заменяет корректный дамп или репликацию.
Что переносить rsync, а что переносить нельзя
rsync отлично подходит для:
- каталога проекта (код приложения), если это не «живой» build-артефакт;
- статических файлов и загрузок (uploads/media);
- конфигов (Nginx/Apache, systemd unit-файлы, env-файлы), если аккуратно исключить секреты или перенести их отдельно;
- кэшей, но часто их проще пересоздать, чем копировать.
Плохая идея копировать rsync «как есть»:
- активную БД как набор файлов (MySQL/MariaDB/PostgreSQL) — почти всегда получите неконсистентное состояние;
- каталоги с постоянно меняющимися lock-файлами/сокетами и runtime-данными;
- временные каталоги, которые на новой машине имеют другой смысл (например,
/tmp).
Надёжная миграция — это разделение на «файлы приложения» и «данные», у которых есть своя модель консистентности. rsync закрывает первую часть, а для БД и очередей нужен отдельный шаг.
Подготовка: инвентаризация и план окна переключения
До того как запускать rsync, определите состав переносимых данных и как именно вы «заморозите запись» на время финального переключения. Это напрямую влияет на downtime.
Базовый список, который стоит выписать:
- пути: корень проекта, uploads/media, приватные файлы, cron-скрипты;
- веб-сервер: конфиги виртуальных хостов, версии PHP/Node/Java;
- процессы: systemd services/таймеры, воркеры очередей, планировщики;
- БД: тип (MySQL/PostgreSQL), объём, способ переноса (dump/репликация);
- доступы: SSH-ключи, пользователи, права на каталоги.
Окно переключения (когда запись будет остановлена) — обычно 1–5 минут для средних сайтов, если первичная синхронизация выполнена заранее и остаётся только финальный прогон.
Если вы переезжаете на новый сервер, имеет смысл заранее подготовить целевую площадку (ОС, диски, бэкапы, сеть). В таких задачах удобнее всего использовать VDS, чтобы воспроизвести окружение максимально близко к текущему продакшену и спокойно прогнать тесты до переключения.

Сетап доступа: безопасный rsync по SSH
Самый частый и безопасный вариант — rsync поверх SSH. На практике это означает: с нового сервера вы подключаетесь к старому и «тянете» данные к себе, чтобы не открывать лишние входящие порты на новом хосте.
На новом сервере создайте отдельного пользователя для миграции и подготовьте ключ (Debian/Ubuntu):
adduser migrator
su - migrator
ssh-keygen -t ed25519 -a 64
Добавьте публичный ключ на старом сервере в ~/.ssh/authorized_keys пользователя, имеющего доступ к данным. Если копируете системные каталоги, удобнее работать от root по ключу, но тогда обязательно ограничивайте доступ и хранение приватного ключа.
Проверка соединения:
ssh -o StrictHostKeyChecking=accept-new user@old-host 'uname -a'
Если вы не уверены в безопасной схеме переноса (ключи, права, исключения, прогон «в два этапа»), полезно заранее свериться с отдельной памяткой по подходу «копирование/деплой через SSH и rsync»: rsync для деплоя и бэкапов по SSH.
Первичная синхронизация: копируем «толстый» объём заранее
Идея проста: основной объём данных перегоняем заранее, пока сайт работает. Это может занять часы — и это нормально. Главное — сделать повторяемую команду rsync с понятными исключениями.
Практичный базовый шаблон для сайта:
rsync -aHAX --numeric-ids --delete --info=progress2 --human-readable -e 'ssh' user@old-host:/var/www/site/ /var/www/site/
Что здесь важно:
-aсохраняет права, время, симлинки (как правило, must-have);-HAXполезны, если у вас есть hardlink/ACL/xattr (не всегда нужно, но часто безопаснее включить);--numeric-idsпереносит владельцев по числовым ID, чтобы не зависеть от совпадения имён пользователей;--deleteсинхронизирует удаление (осторожно: сначала убедитесь в корректности source/destination);--info=progress2показывает общий прогресс по задаче.
Исключения лучше задавать явно. Обычно исключают кэши и временные каталоги. Чтобы не городить переносы строк в команде, используйте файл исключений:
cat > /root/rsync-exclude.txt << 'EOF'
cache/
tmp/
*.log
EOF
rsync -aHAX --numeric-ids --delete --info=progress2 --human-readable -e 'ssh' --exclude-from=/root/rsync-exclude.txt user@old-host:/var/www/site/ /var/www/site/
Совет из практики: зафиксируйте команду (и файл исключений) в заметке/репозитории миграции. Тогда финальный прогон вы сделаете тем же способом, без импровизаций.
Снижение downtime: финальный rsync после остановки записи
Самый короткий простой достигается так: вы «замораживаете запись» на старом сервере, делаете финальный rsync (он переносит только дельту) и сразу переключаете трафик.
Как заморозить запись — зависит от приложения:
- перевести сайт в режим обслуживания на 1–3 минуты (возвращать 503 и не принимать POST/загрузки);
- остановить воркеры очередей и cron, чтобы они не писали в uploads/кэш;
- если есть фоновые загрузки — временно их отключить.
После этого запускается финальный rsync тем же шаблоном:
rsync -aHAX --numeric-ids --delete --info=progress2 --human-readable -e 'ssh' --exclude-from=/root/rsync-exclude.txt user@old-host:/var/www/site/ /var/www/site/
Почему именно так: rsync сравнит дерево файлов и докачает только изменившееся. Если первичная синхронизация была недавно, финальный прогон часто укладывается в десятки секунд или пару минут — это и есть ваше окно простоя для файловой части.
База данных: варианты, чтобы не получить «битую» консистентность
Файлы сайта — половина дела. Если у вас динамика, база данных критична. Два базовых подхода для миграции с минимальным downtime:
- Dump + restore в окно переключения (простое решение для небольших БД).
- Репликация (MySQL/PostgreSQL) с догоняющей репликой и переключением ролей (лучше для крупных БД).
Dump + restore (общая идея): заранее подготовить новый сервер (пользователи, права, параметры), перед переключением остановить запись, снять дамп, перенести на новый сервер, развернуть, проверить, переключить приложение.
Пример дампа для MySQL:
mysqldump --single-transaction --routines --triggers --events --databases appdb > /root/appdb.sql
Восстановление на новом сервере:
mysql < /root/appdb.sql
Если БД большая, dump/restore может стать главным источником downtime. Тогда лучше репликация: вы заранее поднимаете реплику на новом сервере, даёте ей догнаться, а в окно переключения лишь «переключаете запись» на новый мастер.
Если вы не уверены, что успеете сделать dump/restore за минуты, не гадайте: оцените скорость на тестовой копии или выбирайте репликацию. Иначе downtime почти гарантированно вырастет.
Проверки до переключения: что можно валидировать заранее
Пока DNS и трафик ещё смотрят на старый сервер, вы можете проверить на новом почти всё, кроме публичного доступа по домену (если не используете временные способы). Минимальный чек-лист:
- наличие файлов и ожидаемых прав (особенно uploads и каталоги для записи);
- запуск сервисов: Nginx/Apache, PHP-FPM/приложение, воркеры, cron;
- доступ приложения к БД и миграции схемы;
- логика фоновых задач (но не запускайте то, что отправляет письма/уведомления без ограничений);
- лимиты загрузки (Nginx
client_max_body_size, PHPupload_max_filesizeиpost_max_size).
Полезно заранее прогнать грубую sanity-проверку: количество файлов и общий размер (ожидайте небольшую разницу из-за кэшей/логов, если вы их не переносите):
ssh user@old-host 'cd /var/www/site && find . -type f | wc -l'
cd /var/www/site && find . -type f | wc -l
ssh user@old-host 'du -sh /var/www/site'
du -sh /var/www/site

Переключение: последовательность действий, которая обычно не подводит
Ниже — практичная последовательность, где простой контролируемый и короткий:
- Заранее понизить TTL DNS (если планируете менять A/AAAA). Если TTL не под вашим контролем или используете иной способ переключения — учтите это отдельно.
- Сделать первичную синхронизацию rsync (пока сайт работает).
- Подготовить новый сервер: конфиги, сервисы, права, доступы, тестовый запуск.
- В назначенное окно: включить maintenance и остановить запись (cron, воркеры, загрузки).
- Сделать финальный rsync (короткий).
- Перенести БД: финальный дамп или промоут реплики (в зависимости от выбранного варианта).
- Переключить трафик на новый сервер.
- Снять maintenance, включить фоновые задачи уже на новом сервере.
- Наблюдать логи и метрики, держать план быстрого отката.
Если хотите дополнительно «приземлить» план миграции и свериться с вариантами переключения (DNS, балансировщик, временные схемы тестирования), пригодится отдельный разбор подходов: как организовать миграцию сайта с нулевым или минимальным downtime.
План отката: как вернуть всё назад, если что-то пошло не так
План отката нужен всегда, даже если вы уверены в миграции. Он должен быть простым и быстрым, иначе в стресс-момент вы его не выполните.
Для типового переезда откат обычно такой:
- вернуть трафик на старый сервер;
- оставить сайт в maintenance ещё на пару минут;
- если на новом сервере уже была запись — определить «источник истины» (поэтому старайтесь минимизировать время, когда два сервера принимают запись параллельно).
Практическое правило: избегайте ситуации, когда старый и новый сервер одновременно принимают изменения в одну и ту же БД или файловое хранилище. Если такое произошло — откат превращается в разбор конфликтов.
Частые проблемы rsync при миграции и как их лечить
Права и владельцы «поехали»
Если после переноса веб-сервер не может писать в uploads или приложение ругается на доступ, причина часто в UID/GID или маске прав. Помогают --numeric-ids и предварительное приведение пользователей/групп к одинаковым ID, либо последующая корректировка прав на новом сервере.
rsync «удалил лишнее»
--delete опасен, если перепутать source/destination или забыть завершающий слэш. Перед боевым прогоном полезно сделать dry-run:
rsync -aHAX --numeric-ids --delete --dry-run --info=progress2 -e 'ssh' user@old-host:/var/www/site/ /var/www/site/
Скорость низкая, окно переключения растёт
Чаще всего виноваты: огромное количество мелких файлов, слабый диск, или вы запускаете первичную синхронизацию слишком поздно. Решение — делать первичный прогон заранее, а в окно переключения оставлять только финальную дельту.
Несогласованность из-за постоянных изменений
Если приложение постоянно пишет файлы (генерирует превью, пишет кэш, логирует в файл внутри каталога проекта), то финальный rsync может «гоняться» за изменениями. Для этого и нужен шаг «остановить запись» перед финальным прогоном.
Итог: рабочий шаблон миграции с минимальным downtime
Схема «первичный rsync заранее плюс финальный rsync в короткое окно плюс корректный перенос БД» даёт предсказуемый результат и почти всегда минимизирует downtime. Самое важное — не пытаться копировать rsync-ом то, что требует транзакционной консистентности (БД), и заранее продумать, как вы остановите запись на старой площадке.
Чтобы миграция прошла спокойнее, добавьте два улучшения: тестовый прогон на копии проекта и формальный план отката (буквально 5–7 пунктов). Это занимает час, но экономит ночь.


