- Опубликовано: 2 авг 2026
- 20
Переезд на другой хостинг без потери сайта, писем и заказов
Часть 13 из 14 · Серия «Хостинг без магии»
Владелец интернет-магазина решил сменить хостинг.
На новом тарифе больше ресурсов, есть SSH и Composer, а поддержка обещает помочь с переносом. Разработчик скачивает файлы старого сайта, импортирует базу на новый сервер и меняет A-запись домена.
Через несколько часов сайт открывается с нового хостинга.
Кажется, что переезд завершён успешно.
На следующий день обнаруживаются проблемы:
- пропали три заказа;
- часть новых фотографий товаров отсутствует;
- несколько клиентов не могут войти в аккаунт;
- письма продолжают поступать на старый сервер;
- форма обратной связи отправляет уведомления через прежний SMTP;
- один cron всё ещё запускается на старом хостинге;
- часть пользователей видит старую версию сайта;
- платёжная система отправляет уведомления то на старый, то на новый сервер.
Причина проста: сайт продолжал изменяться во время переноса.
Пока копировались файлы и база:
- пользователи создавали заказы;
- менеджеры редактировали товары;
- приложение загружало изображения;
- очередь отправляла письма;
- cron обновлял остатки;
- почтовые серверы принимали новые сообщения.
Разработчик перенёс не сайт, а его состояние на случайный момент времени.
Переезд динамического проекта — это не команда копирования. Это управляемое переключение между двумя работающими средами, в котором нужно определить:
- где находится актуальная версия данных;
- когда запрещаются новые изменения;
- как выполняется финальная синхронизация;
- что произойдёт с пользователями, которые ещё попадают на старый IP;
- как сохранить входящую почту;
- как остановить дублирующиеся фоновые задачи;
- как проверить новый сервер до изменения DNS;
- как действовать, если после переключения обнаружится проблема.
Главный принцип:
В каждый момент времени должен существовать один понятный источник актуальных данных.
Если старый и новый сервер одновременно принимают заказы, загружают файлы и выполняют фоновые задания, проект распадается на две расходящиеся версии.
Статический и динамический сайт переезжают по-разному
Статический сайт
Он состоит из файлов:
index.html
styles.css
app.js
images/
Посетители читают данные, но не изменяют их.
Такой сайт можно:
- скопировать;
- проверить;
- переключить DNS.
Даже если часть пользователей временно открывает старый сервер, обе версии могут быть идентичны.
Динамический сайт
Он изменяется постоянно:
база данных
пользовательские загрузки
заказы
сессии
очереди
почта
cron
внешние интеграции
Один предварительный архив быстро устаревает.
Пока копируется база, в ней появляются новые записи. Пока переносятся изображения, пользователи загружают новые файлы.
Поэтому динамический проект обычно переносится в несколько этапов:
подготовка новой среды
↓
предварительное копирование
↓
тестирование
↓
остановка изменений
↓
финальная синхронизация
↓
проверка
↓
переключение трафика
Сначала составьте карту проекта
До переноса нужно выяснить, из каких компонентов состоит сайт.
Фраза:
Нужно перенести папку
public_html
почти всегда описывает проект неполно.
Минимальный инвентарный список:
Домены и поддомены
DNS-зона
Файлы приложения
База данных
Пользовательские загрузки
.env и секреты
Версия PHP
PHP-расширения
Composer
Node.js и frontend-сборка
Document Root
Cron
Очереди
Постоянные процессы
Почтовые ящики
SMTP сайта
SSL-сертификаты
CDN
Webhooks
Внешние API
Объектное хранилище
Резервные копии
Для каждого компонента укажите:
- где он находится сейчас;
- куда должен переехать;
- кто его использует;
- можно ли остановить изменения;
- как проверить перенос;
- как вернуть предыдущую версию.
Определите источник истины
До переключения источником истины обычно является старый сервер:
Старый сервер
├── актуальная база
├── актуальные uploads
├── работающие очереди
└── активные cron-задачи
Новый сервер пока является копией:
Новый сервер
├── тестовая база
├── предварительные файлы
├── выключенные очереди
└── выключенные cron-задачи
После финального переключения роли меняются:
Новый сервер
├── актуальная база
├── актуальные uploads
├── активные очереди
└── активные cron-задачи
Старый сервер
└── только резервная или техническая копия
Опасная ситуация:
Старый сервер принимает заказы
Новый сервер принимает заказы
Через несколько минут базы уже различаются.
Это называют split-brain — две среды считают себя основной системой и независимо изменяют состояние.
Назначьте ответственного за переключение
Во время миграции не должно быть пяти человек, которые независимо:
- меняют DNS;
- импортируют базу;
- запускают очередь;
- обновляют код;
- отключают старый сервер.
Назначьте одного координатора.
Он должен знать:
- текущий этап;
- актуальный сервер;
- разрешены ли записи;
- выполнена ли финальная синхронизация;
- можно ли запускать cron;
- принято ли решение о переключении;
- начался ли откат.
Полезен простой журнал:
19:00 — включён режим обслуживания
19:03 — остановлены очереди
19:05 — завершён финальный rsync
19:09 — создан дамп базы
19:14 — импорт завершён
19:18 — smoke tests успешны
19:22 — изменены A и AAAA
19:25 — включён новый сайт
В случае проблемы такой журнал помогает понять, какие данные могли измениться на каждом этапе.
Создайте резервную копию перед переездом
До любых изменений сохраните:
- файлы;
- базу;
- пользовательские загрузки;
- конфигурацию;
- DNS-зону;
- список cron-задач;
- почтовые параметры;
- секреты;
- текущие версии программного окружения.
Копия должна храниться отдельно от старого и нового рабочего сайта.
Недостаточно рассчитывать на то, что старый хостинг останется доступен.
Во время переноса можно:
- случайно удалить каталог;
- импортировать базу не туда;
- изменить DNS-зону;
- перезаписать
.env; - удалить почту;
- выполнить
rsync --deleteв неправильном направлении.
Проверка бэкапа подробно разобрана в предыдущей статье серии.
Не меняйте код одновременно с хостингом
Переезд и обновление приложения — две разные операции.
Плохой план:
сменить хостинг
обновить PHP
обновить Laravel
заменить базу
пересобрать frontend
обновить плагины
изменить DNS
Если сайт перестанет работать, причин будет слишком много.
Безопаснее разделить изменения:
1. Перенести существующую рабочую версию
2. Проверить её на новом сервере
3. Завершить миграцию
4. Отдельно обновлять приложение
Иногда переход на новую версию PHP неизбежен, потому что новый хостинг не поддерживает старую. В таком случае совместимость нужно проверить на тестовой копии заранее, а не в ночь переключения.
Снизьте TTL заранее
DNS-ответы кэшируются рекурсивными резолверами на срок, указанный в TTL. Чем больше TTL, тем дольше часть пользователей может продолжать использовать старый IP после изменения записи.
Предположим, сейчас:
A example.com
TTL 86400
Это сутки.
Если одновременно изменить TTL на 300 секунд и поменять IP, резолверы, уже сохранившие старый ответ с TTL 86400, могут продолжать использовать его до окончания прежнего срока.
Поэтому TTL уменьшают заранее:
За 24–48 часов до переезда:
TTL → 300 или 600 секунд
Точный срок зависит от прежнего TTL.
После того как старые длинные кэши успели истечь, можно менять IP.
После стабилизации:
TTL → 3600 секунд
или другое обычное значение.
Низкий TTL ускоряет переключение, но не гарантирует мгновенного обновления каждого устройства: локальные кэши и некоторые резолверы могут вести себя иначе.
Не меняйте DNS-провайдера без необходимости
Есть два разных действия:
Изменение A и AAAA
Авторитетные DNS-серверы остаются прежними, меняется только адрес сайта.
Смена NS
Вся DNS-зона передаётся другому провайдеру.
При смене NS нужно перенести не только сайт, но и:
- MX;
- SPF;
- DKIM;
- DMARC;
- поддомены;
- CNAME;
- SRV;
- CAA;
- записи подтверждения сервисов;
- DNSSEC.
По возможности не совмещайте в один вечер:
смену хостинга
смену DNS-провайдера
смену почты
Чем меньше независимых изменений, тем проще диагностика.
Если NS всё же меняются, сначала создайте полную зону у нового DNS-провайдера, сравните записи и только затем меняйте делегирование. Современные DNS-платформы поддерживают экспорт и импорт зоны именно для миграций и массовой проверки записей.
Подготовьте новый хостинг до копирования данных
Создайте на новом сервере:
- сайт;
- базу;
- пользователя базы;
- каталоги;
- SSH-доступ;
- cron;
- переменные окружения;
- необходимые версии PHP;
- расширения;
- Composer;
- Node.js;
- почтовые параметры.
Проверьте:
php -v
php -m
composer --version
node --version
npm --version
Для PHP-проекта:
composer check-platform-reqs --no-dev
Сравните старую и новую среду:
Версия PHP
memory_limit
upload_max_filesize
post_max_size
max_execution_time
timezone
расширения
MySQL/PostgreSQL
кодировка
Document Root
cron
Новый сервер должен быть готов принять данные до начала финального окна.
Скопируйте код заранее
Если проект хранится в Git, код лучше развернуть из репозитория:
git clone \
[email protected]:company/project.git \
project
Затем выбрать нужную версию:
cd project
git checkout production-tag
Установить зависимости:
composer install \
--no-dev \
--prefer-dist \
--optimize-autoloader \
--no-interaction
Frontend:
npm ci
npm run build
Так новый сервер получает воспроизводимую версию кода.
Но Git не заменяет перенос:
- базы;
.env;- uploads;
- документов;
- почты;
- локальных данных.
Копирование файлов через rsync
Если между серверами доступен SSH, удобно выполнить предварительную синхронизацию через rsync.
Пример запуска на новом сервере:
rsync \
--archive \
--no-owner \
--no-group \
--info=progress2 \
--exclude='.env' \
--exclude='node_modules/' \
--exclude='storage/logs/' \
old-user@old-server:/home/old-user/project/ \
/home/new-user/project/
Режим --archive рекурсивно копирует структуру и сохраняет большинство основных атрибутов, включая времена, права и символические ссылки. При этом он не включает автоматически ACL, extended attributes и hard links — для них существуют отдельные параметры.
На виртуальном хостинге владельцы файлов на двух серверах обычно различаются, поэтому параметры:
--no-owner
--no-group
часто необходимы.
Важен завершающий слеш
Команды:
rsync -a source/ destination/
и:
rsync -a source destination/
могут создать разную структуру.
В первом случае переносится содержимое source.
Во втором в destination может появиться отдельный каталог source.
Всегда проверяйте результат на тестовом пути.
Сначала используйте --dry-run
Перед финальной синхронизацией:
rsync \
--archive \
--dry-run \
--itemize-changes \
source/ \
destination/
Команда покажет планируемые изменения без их применения.
Особенно это важно перед использованием:
--delete
--delete-delay
--remove-source-files
Параметры удаления способны уничтожить данные в целевом каталоге, если перепутаны:
- направление;
- каталог;
- завершающий слеш;
- список исключений.
После проверки можно применить:
rsync \
--archive \
--delete-delay \
--itemize-changes \
source/ \
destination/
--delete-delay удаляет лишние файлы на принимающей стороне после расчёта изменений. Официальная документация rsync отдельно предупреждает, что параметры удаления изменяют содержимое назначения и должны использоваться с пониманием выбранного дерева.
Для первого копирования удаление обычно не требуется.
Что переносить отдельным потоком
Пользовательские файлы изменяются чаще кода.
Например:
storage/app/public/
public/uploads/
wp-content/uploads/
media/
documents/
Их полезно синхронизировать отдельно:
rsync \
--archive \
--no-owner \
--no-group \
old-user@old-server:/home/old-user/project/storage/app/public/ \
/home/new-user/project/storage/app/public/
Это позволяет:
- заранее перенести основной объём;
- во время финального окна скопировать только изменения.
Если uploads занимают 200 ГБ, копировать их с нуля после включения maintenance mode слишком долго.
Не копируйте живую базу как обычные файлы
Нельзя надёжно перенести MySQL или PostgreSQL командой:
cp -R /var/lib/mysql ...
пока сервер базы продолжает работать.
Используйте:
- логический дамп;
- физический backup-инструмент;
- репликацию;
- согласованный snapshot.
Для большинства сайтов на виртуальном хостинге подходит логический дамп.
Предварительный перенос MySQL
Создаём дамп:
mysqldump \
--single-transaction \
--routines \
--triggers \
--events \
--default-character-set=utf8mb4 \
old_database |
gzip \
> old_database-initial.sql.gz
Импортируем на новый сервер:
gzip -dc old_database-initial.sql.gz |
mysql new_database
Для транзакционных таблиц InnoDB параметр --single-transaction создаёт согласованное состояние на момент начала транзакции, не блокируя обычную работу приложения. Он не даёт тех же гарантий для нетранзакционных таблиц и требует осторожности при параллельных изменениях структуры.
Предварительный дамп нужен для тестирования.
Он ещё не является окончательной production-базой, потому что старый сайт продолжает принимать изменения.
Предварительный перенос PostgreSQL
Создаём архив:
pg_dump \
--format=custom \
--file=old_database-initial.dump \
old_database
Импортируем в пустую тестовую базу:
pg_restore \
--dbname=new_database \
--no-owner \
old_database-initial.dump
pg_dump создаёт согласованный экспорт даже при параллельной работе пользователей и не блокирует обычное чтение и запись.
Но после завершения дампа старый сайт продолжает меняться, поэтому перед финальным запуском потребуется ещё одна актуальная копия или другой механизм синхронизации.
Настройте новую конфигурацию отдельно
Не копируйте .env вслепую.
На новом сервере могут отличаться:
APP_URL=
DB_HOST=
DB_PORT=
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
MAIL_HOST=
MAIL_PORT=
CACHE_STORE=
SESSION_DRIVER=
QUEUE_CONNECTION=
FILESYSTEM_DISK=
Создайте новый production-файл и перенесите только значения, которые должны сохраниться:
APP_KEY
ключи шифрования
API-токены
секреты webhook
Особенно осторожно с:
APP_ENV=production
APP_DEBUG=false
Новый сервер не должен случайно использовать тестовые:
- платежи;
- SMTP;
- CRM;
- очереди;
- storage;
- аналитику.
И наоборот: тестирование до переключения не должно отправлять реальные письма и изменять внешние системы.
Отключите опасные интеграции на тестовой копии
До перехода новый сервер не должен самостоятельно:
- отправлять письма клиентам;
- списывать оплату;
- менять остатки;
- отправлять SMS;
- запускать импорт;
- обрабатывать очередь;
- посылать webhooks;
- создавать документы;
- запускать маркетинговые кампании.
В тестовой конфигурации можно использовать:
MAIL_MAILER=log
QUEUE_CONNECTION=sync
PAYMENT_MODE=sandbox
Конкретные значения зависят от проекта.
Главная цель:
Новый сервер можно тестировать, не создавая production-эффектов.
Проверьте сайт до переключения DNS
DNS пока ведёт на старый сервер, но новый сайт уже можно открыть.
Через файл hosts
Добавьте на рабочем компьютере:
203.0.113.25 example.com
203.0.113.25 www.example.com
Теперь только этот компьютер будет открывать домен с нового IP.
После теста строки нужно удалить.
Через curl --resolve
curl \
--resolve example.com:80:203.0.113.25 \
http://example.com/
Для HTTPS:
curl \
--resolve example.com:443:203.0.113.25 \
-Iv \
https://example.com/
Опция --resolve позволяет временно сопоставить доменное имя с выбранным IP, сохраняя правильный HTTP Host и TLS SNI. Это делает проверку точнее, чем открытие сайта непосредственно по IP.
Что проверить на новом сервере
Главные страницы
Главная
Каталог
Карточка товара
Поиск
Статья
Контакты
Авторизация
Вход
Выход
Регистрация
Восстановление пароля
Права администратора
База
Количество пользователей
Количество товаров
Количество заказов
Последний заказ
Последнее обновление
Файлы
Изображения
Документы
Миниатюры
Uploads
Символические ссылки
Интеграции
В безопасном режиме:
SMTP
CRM
платёжная система
доставка
webhooks
API
Сервер
PHP
расширения
права
кэш
cron
логи
Document Root
HTTPS
Производительность
Сравните:
curl \
--silent \
--output /dev/null \
--write-out \
'TTFB: %{time_starttransfer}s Total: %{time_total}s\n' \
--resolve example.com:443:203.0.113.25 \
https://example.com/
Переезд считается подготовленным не тогда, когда открылась главная страница, а когда проверены критические бизнес-сценарии.
Подготовьте SSL до переключения
Для HTTPS новый сервер должен показывать сертификат, покрывающий:
example.com
www.example.com
HTTP-01-проверка Let’s Encrypt требует, чтобы специальный файл был доступен через домен на порту 80. Если DNS ещё указывает только на старый сервер, новый сервер такую проверку обычно не пройдёт. DNS-01 подтверждает домен через TXT-запись _acme-challenge и позволяет выпустить сертификат до смены IP.
Варианты:
- выпустить сертификат через DNS-01;
- использовать механизм хостинг-панели;
- подготовить переключение и выпустить сертификат сразу после него;
- безопасно перенести существующий сертификат и ключ, если это допускает инфраструктура.
Копирование закрытого ключа увеличивает число мест, где он хранится. Не отправляйте его через почту или открытый тикет.
Если до переключения HTTPS на новом сервере ещё не готов, тестируйте HTTP и заранее подготовьте процедуру выпуска. Но учитывайте, что после смены DNS первые посетители уже могут прийти по HTTPS.
Выберите стратегию финального переключения
Есть три основных варианта.
Вариант №1. Maintenance window
Самый понятный и безопасный вариант для большинства сайтов.
остановить изменения
↓
финально скопировать файлы
↓
финально перенести базу
↓
проверить
↓
переключить DNS
Пользователи некоторое время видят страницу обслуживания.
Преимущества:
- один источник данных;
- простой контроль;
- минимальный риск потерянных заказов;
- понятный откат.
Недостаток — короткий простой.
Вариант №2. Режим только для чтения
Сайт продолжает показывать страницы, но запрещает:
- заказы;
- регистрацию;
- загрузку файлов;
- изменение профиля;
- административные правки.
Преимущества:
- публичная часть остаётся доступной;
- база перестаёт изменяться.
Недостаток:
- приложение должно корректно поддерживать read-only;
- не все фоновые процессы прекращаются автоматически;
- часть функций недоступна.
Вариант №3. Репликация и переключение без остановки
Используется для крупных проектов.
Возможная схема:
старая база
↓ репликация
новая база
↓ переключение приложения
Дополнительно могут потребоваться:
- синхронизация object storage;
- общий Redis;
- балансировщик;
- единый session store;
- CDC;
- binary log или WAL;
- контроль replication lag;
- план обратного переключения.
Это не универсальная команда, а отдельный инфраструктурный проект.
Для большинства обычных сайтов несколько минут планового maintenance mode надёжнее плохо настроенной «миграции без простоя».
Финальный план переноса
Ниже — базовая последовательность для динамического PHP-сайта.
Шаг 1. Объявите окно работ
Сообщите:
Дата:
Начало:
Ожидаемая длительность:
Какие функции недоступны:
Кто отвечает:
Для магазина выберите период с низкой нагрузкой.
Но не планируйте работы на время, когда:
- банк выполняет регламент;
- идёт рекламная кампания;
- запускается распродажа;
- недоступен разработчик;
- поддержка нового хостинга не работает.
Шаг 2. Зафиксируйте контрольные значения
Например:
Последний заказ:
ID 51903
Время:
19:02:11
Пользователей:
128 420
Товаров:
18 442
Последний загруженный файл:
invoice-51903.pdf
После переноса эти данные помогут проверить точку синхронизации.
Шаг 3. Включите maintenance или read-only
Laravel:
php artisan down \
--render="errors::503" \
--retry=60
Современный Laravel позволяет включить maintenance mode командой php artisan down; режим возвращает посетителям 503, может использовать заранее отрисованную страницу и отключается командой php artisan up.
Выход:
php artisan up
Для WordPress, Symfony и других систем используйте подходящий механизм приложения или веб-сервера.
Страница обслуживания должна быть простой и не зависеть от:
- базы;
- Composer;
- кэша;
- внешнего API.
Шаг 4. Остановите источники изменений
На старом сервере отключите:
- cron;
- scheduler;
- queue workers;
- импорты;
- генераторы;
- рассылки;
- внешние обработчики;
- административные правки.
Проверьте, что процесс действительно остановлен:
ps aux
Недостаточно удалить cron-запись, если ранее запущенный процесс продолжает работать.
Шаг 5. Выполните финальную синхронизацию файлов
Сначала проверка:
rsync \
--archive \
--dry-run \
--itemize-changes \
old-user@old-server:/home/old-user/project/storage/app/public/ \
/home/new-user/project/storage/app/public/
Затем применение:
rsync \
--archive \
--itemize-changes \
old-user@old-server:/home/old-user/project/storage/app/public/ \
/home/new-user/project/storage/app/public/
Если требуется удаление файлов, исчезнувших на старом сервере, добавляйте --delete-delay только после внимательной проверки.
Шаг 6. Создайте финальный дамп базы
MySQL:
mysqldump \
--single-transaction \
--routines \
--triggers \
--events \
--default-character-set=utf8mb4 \
old_database |
gzip \
> old_database-final.sql.gz
Проверяем:
gzip --test old_database-final.sql.gz
test -s old_database-final.sql.gz
PostgreSQL:
pg_dump \
--format=custom \
--file=old_database-final.dump \
old_database
Проверяем список:
pg_restore \
--list \
old_database-final.dump \
> /dev/null
Шаг 7. Импортируйте базу на новый сервер
Лучше импортировать в пустую базу, а не поверх тестовой версии.
MySQL:
gzip -dc old_database-final.sql.gz |
mysql new_database
PostgreSQL:
pg_restore \
--dbname=new_database \
--no-owner \
old_database-final.dump
Если тестовая база уже существует:
- удалите её;
- создайте заново;
- убедитесь, что приложение пока не подключается к ней с записью.
Смешивание предварительного и финального дампа может оставить лишние данные.
Шаг 8. Примените production-конфигурацию
Проверьте:
APP_ENV=production
APP_DEBUG=false
DB_HOST=
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
APP_URL=https://example.com
Для Laravel:
php artisan optimize:clear
php artisan storage:link
php artisan optimize
Для Symfony:
APP_ENV=prod APP_DEBUG=0 \
php bin/console cache:clear
Не запускайте миграции автоматически, если финальная база уже имеет рабочую production-схему.
Миграции нужны только тогда, когда новый код действительно ожидает другую структуру.
Шаг 9. Проверьте новую среду через --resolve
curl \
--resolve example.com:443:203.0.113.25 \
-I \
https://example.com/
Затем выполните smoke tests:
Главная
Вход
Каталог
Поиск
Корзина
Тестовый заказ
Uploads
API
Административная панель
Не включайте публичную запись, пока не проверены:
- база;
- файлы;
- права;
- сертификат;
- конфигурация;
- критические функции.
Шаг 10. Сравните данные
Например:
SELECT
COUNT(*) AS orders_count,
MAX(id) AS last_order_id,
MAX(created_at) AS last_order_at
FROM orders;
На старой и новой базе должны совпадать:
Количество заказов
Последний ID
Время последней записи
Проверяйте также:
- пользователей;
- товары;
- платежи;
- пользовательские файлы;
- важные документы.
Шаг 11. Переключите DNS
Измените:
A
AAAA
Проверьте отдельно:
dig +short example.com A
dig +short example.com AAAA
dig +short www.example.com A
dig +short www.example.com AAAA
dig +short www.example.com CNAME
Не оставляйте старую AAAA-запись, если IPv6 нового сервера не настроен.
Проверьте авторитетные серверы:
dig +short NS example.com
Затем каждый из них:
dig +short \
@ns1.dns-provider.example \
example.com A
Шаг 12. Запустите новый сайт
После проверки DNS и сервера:
php artisan up
Затем запустите на новом сервере:
- cron;
- scheduler;
- очередь;
- импорт;
- необходимые фоновые процессы.
Не включайте их на старом сервере.
Шаг 13. Оставьте старый сервер работающим
Не удаляйте старый аккаунт сразу.
Часть резолверов может ещё использовать кэшированный IP. Старый сервер должен:
- показывать maintenance page;
- не принимать новые изменения;
- не выполнять cron;
- не запускать очереди;
- сохранять логи обращений.
Длительность зависит от прежнего TTL и реального поведения пользователей.
Часто старый сервер оставляют доступным несколько суток как страховку, но не используют его как вторую production-систему.
Что увидят пользователи со старым DNS-кэшем
После переключения возникают две группы.
Пользователи с новым ответом
example.com → новый сервер
Они видят рабочий сайт.
Пользователи со старым ответом
example.com → старый сервер
Они могут увидеть:
- старый сайт;
- maintenance page;
- ошибку;
- прокси на новый сервер.
Самый опасный вариант — оставить старый сайт полностью рабочим.
Тогда часть заказов попадёт в старую базу.
Безопаснее:
- показывать maintenance;
- перевести старый сайт в read-only;
- настроить reverse proxy на новый сервер, если инфраструктура позволяет;
- использовать CDN для централизованного переключения origin.
Обычный HTTP-редирект на тот же домен не поможет: браузер снова разрешит имя в тот же старый IP.
Reverse proxy со старого сервера
Если есть доступ к конфигурации веб-сервера, старый сервер можно временно превратить в прокси:
пользователь со старым DNS
↓
старый сервер
↓
новый сервер
Преимущества:
- пользователи не видят простой;
- все записи создаются на новом сервере;
- старый IP безопасно обслуживает кэшированный трафик.
Но нужно правильно передавать:
- Host;
- исходный протокол;
- IP пользователя;
- cookies;
- заголовки;
- WebSocket, если используется.
На обычном виртуальном хостинге reverse proxy может быть недоступен.
В таком случае короткий maintenance для пользователей со старым кэшем безопаснее двух активных баз.
Особое внимание к сессиям
После перехода пользователи могут выйти из аккаунтов.
Причины:
- другой
APP_KEY; - другое хранилище сессий;
- файловые сессии остались на старом сервере;
- изменился cookie domain;
- сменился протокол;
- старые cookies невозможно расшифровать;
- Redis не перенесён.
Если допустимо, пользователей можно попросить войти повторно.
Если это критично, переносите:
- ключ шифрования;
- session store;
- настройки cookie;
- Redis или таблицу сессий.
Не копируйте старые сессии вслепую после взлома: они могут содержать активные авторизационные токены.
Очереди могут выполнить задание дважды
Представим:
- Старый worker взял задание.
- Начал создавать счёт.
- Во время миграции процесс остановился.
- Задание вернулось в очередь.
- Новый worker выполнил его ещё раз.
Результат:
- два письма;
- два документа;
- два webhook;
- повторное изменение внешней системы.
Фоновые действия должны быть идемпотентными: повторный запуск не должен создавать второй результат.
Перед переносом очереди определите:
- какие задания сейчас выполняются;
- какие можно повторить;
- какие нужно завершить;
- где хранится очередь;
- переносится ли её состояние;
- нужно ли очищать устаревшие задания.
Для критических операций полезны уникальные внешние идентификаторы и проверки:
Этот платёж уже обработан?
Этот счёт уже создан?
Это письмо уже отправлено?
Cron должен работать только в одном месте
После переезда часто забывают старые задания:
* * * * * php artisan schedule:run
В результате scheduler работает одновременно на двух серверах.
Возможные последствия:
- двойной импорт;
- двойная рассылка;
- дубли отчётов;
- повторное списание;
- конкурирующая очистка;
- блокировки базы;
- разные изменения на двух серверах.
Создайте список cron до переезда:
crontab -l
После переключения:
старый сервер — cron выключен
новый сервер — cron включён
Webhooks могут попасть на старый сервер
Платёжные системы, CRM и службы доставки обращаются к домену:
https://example.com/webhooks/payment
Они тоже используют DNS-кэш.
После переключения часть уведомлений может прийти на старый IP.
Если старый сервер показывает только maintenance page, webhook получит ошибку и, возможно, повторит запрос позже.
Проверьте политику каждого сервиса:
- сколько раз он повторяет;
- какие коды считает успешными;
- можно ли временно изменить callback URL;
- есть ли журнал недоставленных событий;
- можно ли повторно отправить webhook.
Для критических callback полезны:
- отдельный стабильный поддомен;
- CDN;
- reverse proxy;
- очередь входящих событий;
- идемпотентная обработка.
После переезда сравните статусы оплат с панелью платёжного провайдера.
CDN и WAF
Если сайт работает через CDN, публичный DNS может указывать не на хостинг, а на сеть CDN.
В этом случае переключается origin:
CDN
↓
старый сервер
на:
CDN
↓
новый сервер
Это может уменьшить влияние DNS-кэша пользователей: они продолжают подключаться к тому же CDN, а CDN начинает использовать новый origin.
Но перед переключением нужно настроить:
- сертификат origin;
- firewall;
- Host;
- доверенные прокси;
- real client IP;
- кэш;
- health checks;
- redirect rules.
После перехода очистите только действительно устаревшие ресурсы. Полная очистка крупного CDN может создать резкий холодный трафик на новый сервер.
Переезд почты — отдельный проект
Копирование сайта не переносит автоматически:
- почтовые ящики;
- письма;
- пароли;
- фильтры;
- пересылки;
- автоответчики;
- MX;
- SPF;
- DKIM;
- DMARC.
Сначала решите:
Почта вообще должна переезжать?
Можно перенести сайт, оставив корпоративную почту у прежнего почтового провайдера.
Тогда MX менять не нужно.
Это часто снижает риск.
Входящая и исходящая почта
Входящая почта
Определяется MX-записями:
example.com MX 10 mail.provider.example
Исходящие письма сайта
Определяются SMTP-конфигурацией приложения:
MAIL_HOST=
MAIL_PORT=
MAIL_USERNAME=
MAIL_PASSWORD=
Можно оставить MX без изменений и настроить новый сайт на прежний или внешний SMTP.
Не меняйте MX только потому, что переезжает веб-сайт.
Перенос почтовых ящиков
Для каждого ящика нужно перенести:
- папки;
- сообщения;
- даты;
- флаги прочтения;
- структуру;
- при возможности UID;
- подписки на папки.
Для серверов Dovecot существует dsync, который может использовать IMAP в сценариях миграции почтовых ящиков. Официальная документация рекомендует отдельную конфигурацию миграции, чтобы production-настройки, push-уведомления и другие механизмы не создавали нежелательных эффектов.
Общий принцип почтового переноса похож на перенос файлов:
1. Создать ящики на новом сервере
2. Выполнить предварительную IMAP-синхронизацию
3. Проверить папки и сообщения
4. Переключить MX
5. Оставить старый сервер принимать почту
6. Выполнить финальную синхронизацию
7. Повторить её после истечения DNS-кэшей
Почему нужна финальная синхронизация:
- часть отправителей продолжит использовать старый MX из кэша;
- новые письма некоторое время могут приходить на прежний сервер.
Не удаляйте старые ящики сразу после изменения MX.
Перенесите почтовые DNS-записи
При смене почтового сервиса проверяйте:
MX
SPF
DKIM
DMARC
autodiscover
autoconfig
SRV
mail.example.com
SPF может разрешать старый IP:
v=spf1 ip4:192.0.2.10 -all
После переезда отправка с нового адреса провалит проверку.
DKIM нового сервиса обычно использует новый selector:
newmail._domainkey.example.com
Старую DKIM-запись не обязательно удалять мгновенно. Она может потребоваться для проверки сообщений, отправленных ранее или продолжающих выходить через старую систему во время перехода.
DMARC лучше не ужесточать одновременно с миграцией почты.
Проверьте отправку сайта после переезда
Отправьте тесты:
на Gmail
на корпоративный ящик
на другой публичный сервис
на адрес своего домена
Проверьте:
- SMTP-лог;
- доставку;
- папку «Спам»;
Authentication-Results;- SPF;
- DKIM;
- DMARC;
- Return-Path;
- Reply-To.
Если письма отправляются через внешний SMTP, смена веб-хостинга может не потребовать изменения SPF.
Если сайт начинает отправлять напрямую с IP нового сервера, потребуется пересмотреть:
- SPF;
- PTR;
- DKIM;
- репутацию;
- лимиты.
Не забудьте служебные поддомены
Кроме основного сайта могут существовать:
api.example.com
admin.example.com
cdn.example.com
files.example.com
webhook.example.com
status.example.com
mail.example.com
Проверьте каждый:
dig +short api.example.com A
dig +short api.example.com AAAA
И каждый сертификат:
curl -Iv https://api.example.com/
Особенно опасны забытые AAAA-записи, которые продолжают вести на старую инфраструктуру.
План отката
Откат нужно подготовить до переключения.
Запишите:
При каких ошибках откатываемся?
Кто принимает решение?
До какого момента откат прост?
Как возвращаются новые данные?
Как меняется DNS?
Какая копия используется?
До открытия нового сайта откат прост
Если пользователи ещё не создавали данные на новом сервере:
новый сайт выключить
старый сайт включить
DNS вернуть
Хотя DNS-кэш всё равно создаст переходный период.
После появления новых заказов откат сложен
Представим:
На новом сервере:
заказы 51904–51918
На старом сервере:
последний заказ 51903
Просто вернуть DNS на старый IP означает потерять пятнадцать заказов.
Перед откатом нужно:
- остановить запись на новом сервере;
- выгрузить новые данные;
- синхронизировать uploads;
- перенести изменения обратно;
- проверить согласованность;
- только затем возвращать трафик.
Поэтому после успешного открытия нового сайта предпочтительнее исправлять проблему вперёд, если это безопасно, а не сразу откатывать DNS.
Определите точку невозврата
Например:
До включения нового сайта:
быстрый откат
После первого нового заказа:
откат только с обратной синхронизацией
Координатор должен зафиксировать момент:
19:31 — новый сайт открыт для записи
После него нельзя считать старую базу актуальной.
Контроль после переключения
Первые часы проверяйте:
HTTP
curl -I https://example.com/
curl -I https://www.example.com/
DNS
dig +short example.com A
dig +short example.com AAAA
Логи
tail -f storage/logs/laravel.log
или:
tail -f var/log/prod.log
Ошибки
500
502
503
404
ошибки базы
ошибки SMTP
ошибки permission denied
Ресурсы
CPU
RAM
PHP workers
I/O
соединения базы
диск
Бизнес-метрики
Заказы создаются?
Оплаты подтверждаются?
Письма уходят?
Uploads сохраняются?
CRM получает данные?
Webhooks обрабатываются?
Технический статус HTTP 200 не доказывает, что магазин работает.
Проверьте, не продолжают ли обращаться к старому серверу
Изучите access log старого хостинга.
Если через сутки там остаются запросы, выясните:
- это пользователи с кэшем;
- боты;
- прямой IP;
- внешний webhook;
- старый поддомен;
- cron другого сервиса;
- приложение с зашитым адресом.
Старый сервер помогает обнаружить забытые зависимости.
Не удаляйте его, пока не поняли источник критических обращений.
Сверка через несколько часов
Повторно сравните:
Последний заказ
Количество пользователей
Uploads
Очередь
Письма
Платежи
Проверьте старую базу.
После включения maintenance она не должна получать новые записи.
Если в ней появился новый заказ, значит:
- старый сайт всё ещё принимает запись;
- maintenance не работает для части URL;
- webhook обходит обычный маршрут;
- cron остался включён;
- кто-то использует прямой адрес сервера.
Когда можно отключать старый хостинг
Перед удалением проверьте:
DNS-кэши обновились
Старый сервер не получает важные запросы
Почта финально синхронизирована
Webhooks направлены на новый сервер
Cron выключен
Очереди пусты
Все данные скопированы
Бэкап старой среды сохранён
Новый сайт стабилен
Скачайте финальную архивную копию:
- файлов;
- базы;
- почты;
- DNS;
- конфигурации.
Только затем отменяйте услугу.
Уточните у старого провайдера, сколько времени данные хранятся после отключения. Не рассчитывайте на возможность восстановить аккаунт через месяц.
Миграция с минимальным простоем
Для обычного магазина практический сценарий может выглядеть так:
За 2 дня:
снизить TTL
развернуть новую среду
За 1 день:
предварительно перенести файлы
предварительно импортировать базу
провести тесты
В окно работ:
включить maintenance
остановить cron и очереди
финально синхронизировать uploads
создать финальный дамп
импортировать
проверить
изменить DNS
запустить новый сайт
После:
контролировать старый сервер
проверить почту и webhooks
повторить сверку
Простой будет равен в основном времени:
финальной синхронизации
+
финального дампа
+
импорта
+
проверки
Чем больше данных перенесено заранее, тем короче окно.
Как это устроено на Siteko. Всё описанное выше — карту проекта, предварительный перенос, финальную синхронизацию, проверку и переключение DNS — при переезде на Siteko поддержка может выполнить за вас под ключ: файлы, базу, DNS-записи, SSL и, при необходимости, почту, с проверкой, что сайт открывается и формы работают. Если сайт был на панельном хостинге (ispmanager, cPanel, Plesk), панель забирает файлы и базы через раздел «Импорт данных» — часто это самый быстрый путь. Тем, кто переносит сам, на тарифах Master и Expert доступны все инструменты из этой статьи: SSH,
rsync,mysqldump, доступ к обеим средам. SSL закрывается бесплатным Let's Encrypt из панели, а домен направляется на DNS-серверыns1.siteko.net/ns2.siteko.netлибо A-записью на IP сервера — смотря какую схему из пятой статьи вы выбрали.
Когда нужен более сложный план
Простого maintenance window может быть недостаточно, если:
- сайт принимает сотни заказов в минуту;
- недопустим даже минутный простой;
- база занимает сотни гигабайт;
- uploads изменяются постоянно;
- система работает в нескольких регионах;
- существует множество внешних webhook;
- используется несколько баз;
- есть Kafka, Redis, search cluster;
- приложение уже работает на нескольких серверах.
Тогда применяются:
- репликация базы;
- change data capture;
- dual write с контролем;
- object storage replication;
- балансировщик;
- blue-green deployment;
- временный reverse proxy;
- переключение origin у CDN;
- постепенный перевод трафика.
Такая миграция требует отдельного проектирования и репетиции.
Фраза «без простоя» не должна означать «без плана».
Репетиция переезда
Лучший способ сократить риск — выполнить миграцию заранее на копии.
Репетиция показывает:
- сколько копируются файлы;
- сколько создаётся дамп;
- сколько длится импорт;
- какие права ломаются;
- какие расширения отсутствуют;
- какой каталог забыли;
- какие команды нужны;
- сколько занимает smoke test;
- какой фактический RTO.
После репетиции составьте точный runbook с ожидаемым временем:
| Этап | План |
|---|---|
| Maintenance | 2 минуты |
| Финальный rsync | 4 минуты |
| Дамп базы | 3 минуты |
| Импорт | 6 минут |
| Кэш и конфигурация | 2 минуты |
| Smoke tests | 8 минут |
| Итого | 25 минут |
Добавьте резерв на непредвиденные действия.
Таблица: симптом, причина и действие
| Симптом | Вероятная причина | Следующее действие |
|---|---|---|
| После переезда пропали заказы | Перенесён не финальный дамп | Сравнить обе базы |
| На старой базе появились новые записи | Старый сервер принимает трафик | Включить maintenance |
| Не хватает новых изображений | Не выполнен финальный rsync | Синхронизировать uploads |
| Часть пользователей видит старый сайт | DNS-кэш | Держать старый сервер безопасным |
| Одни пользователи видят старый сайт, другие новый | A/AAAA или разные NS | Проверить DNS |
| По IPv4 новый сайт, по IPv6 старый | Не изменена AAAA | Исправить IPv6 |
| После переключения ошибка 500 | Окружение или .env |
Проверить логи |
| Не работают авторизованные сессии | Сменился ключ или session store | Проверить конфигурацию |
| Письма перестали приходить сотрудникам | Потеряны MX | Восстановить DNS-записи |
| Сайт не отправляет письма | Старый SMTP или SPF | Проверить mail config |
| Письма дублируются | Два worker или cron | Остановить старые процессы |
| Дважды создаются отчёты | Scheduler работает на двух серверах | Оставить один |
| Платёж подтверждён, заказ нет | Webhook пришёл на старый сервер | Проверить журналы провайдера |
| SSL показывает чужой сертификат | DNS или virtual host | Проверить SNI |
| Новый сервер работает по IP, но не по домену | Домен не добавлен | Настроить Host |
| После отката пропали новые данные | DNS возвращён без обратной синхронизации | Перенести изменения |
| Почта приходит на оба сервера | MX-кэш | Выполнить финальный IMAP sync |
| CDN показывает старый контент | Кэш или старый origin | Проверить CDN |
| На новом сервере высокая нагрузка | Холодный кэш или боты | Прогреть и анализировать |
| Старый сервер всё ещё получает API-запросы | Внешний сервис кэширует адрес | Найти и обновить интеграцию |
Грабли при переезде
| Грабля | Результат | Как избежать |
|---|---|---|
| Копировать сайт один раз | Теряются изменения после копии | Предварительная и финальная синхронизация |
Переносить только public_html |
Нет базы и конфигурации | Составить карту проекта |
| Менять хостинг и код одновременно | Непонятна причина ошибки | Разделить работы |
| Снижать TTL в момент переключения | Старые кэши живут долго | Снизить заранее |
| Забыть AAAA | Часть клиентов идёт на старый сервер | Проверять IPv4 и IPv6 |
| Оставить оба сайта рабочими | Расходятся базы | Один источник истины |
Использовать rsync --delete без dry-run |
Удаляются нужные данные | Сначала проверить |
| Копировать файлы рабочей базы | Несогласованный перенос | Использовать дамп |
| Запустить cron на новом, не выключив старый | Дублируются операции | Чёткий cutover |
| Тестировать с production SMTP | Клиенты получают тестовые письма | Sandbox |
| Открывать новый сайт до финального импорта | Новые записи смешиваются с тестом | Держать запись закрытой |
| Проверять только главную страницу | Критические функции сломаны | Smoke tests |
| Сразу удалить старый аккаунт | Нельзя проверить обращения и откат | Оставить переходный период |
| Менять MX вместе с сайтом без необходимости | Пропадает почта | Разделить миграции |
| Перенести ящики одним проходом | Письма продолжают приходить на старый сервер | Финальный IMAP sync |
| Откатить DNS после новых заказов | Теряются новые данные | Обратная синхронизация |
| Забыть webhooks | Платежи приходят на старую систему | Проверить callback |
| Не вести журнал работ | Непонятно, где произошла потеря | Фиксировать этапы |
| Не репетировать перенос | Окно работ неожиданно растёт | Тестовая миграция |
Что приложить к обращению в поддержку
Плохое сообщение:
Перенесите сайт без потерь.
Полезное:
Домен:
example.com
Тип проекта:
Laravel, PHP 8.4, MySQL
Объём:
файлы — 18 ГБ
uploads — 12 ГБ
база — 4,6 ГБ
Текущий Document Root:
project/public
Нужно перенести:
файлы
базу
.env
cron
SSL
Почту переносить не нужно:
MX остаются у текущего почтового провайдера.
Критические данные:
заказы
платежи
uploads
Допустимое окно обслуживания:
30 минут
с 01:00 до 01:30
Предварительный перенос уже выполнен.
План:
01:00 — maintenance
01:02 — остановка cron
01:05 — финальный rsync uploads
01:10 — финальный dump
01:15 — import
01:22 — smoke tests
01:27 — изменение A и AAAA
Прошу уточнить:
— можно ли выпустить SSL до изменения DNS;
— где находятся PHP-логи;
— как настроить cron раз в минуту;
— какой IP использовать в A и AAAA;
— можно ли временно сохранить старый аккаунт.
После проблемы:
Переключение выполнено в 01:27.
На новом сервере последний заказ:
ID 51918, 01:42.
На старом сервере после maintenance появился:
ID 51919, 01:44.
Нужно определить:
какой запрос создал запись на старом сервере
и как безопасно перенести её в новую базу.
Старый cron выключен.
В access log есть POST на /webhooks/payment
от платёжного провайдера.
Такое описание позволяет искать конкретную потерянную операцию.
Минимальный чек-лист переезда
До работ
Создана резервная копия?
Проверено восстановление?
Составлена карта проекта?
Снижен TTL?
Подготовлен новый сервер?
Проверены версии и расширения?
Выполнен предварительный перенос?
Подготовлен SSL?
Составлен план отката?
Файлы
Код перенесён?
Uploads перенесены?
Символические ссылки созданы?
Права проверены?
Document Root правильный?
База
Создан предварительный дамп?
Проведён тестовый импорт?
Определено окно остановки записи?
Создан финальный дамп?
Сравнены контрольные данные?
Приложение
.env подготовлен?
APP_KEY сохранён?
Кэш очищен?
Production mode включён?
Debug выключен?
Фоновые задачи
Cron старого сервера выключен?
Очереди старого остановлены?
Новые задания запущены только после переключения?
Проверена идемпотентность?
DNS
A изменена?
AAAA проверена?
www настроен?
NS отвечают одинаково?
Поддомены перенесены?
DNSSEC не сломан?
HTTPS
Сертификат покрывает все имена?
Порт 443 работает?
Редирект HTTP → HTTPS настроен?
Нет mixed content?
Почта
Нужно ли менять MX?
Ящики предварительно синхронизированы?
SPF обновлён?
DKIM настроен?
DMARC сохранён?
SMTP сайта проверен?
Интеграции
Платежи работают?
Webhooks приходят?
CRM получает данные?
Uploads сохраняются?
Письма отправляются?
После
Старый сайт закрыт для записи?
Старый cron выключен?
Проверяются старые access logs?
Данные повторно сверены?
Финальная копия сохранена?
Что в итоге
Переезд сайта — это не перенос каталога с одного сервера на другой.
Это последовательная передача роли основной системы:
1. Описать все компоненты
↓
2. Создать резервную копию
↓
3. Подготовить новый сервер
↓
4. Предварительно перенести данные
↓
5. Проверить через hosts или --resolve
↓
6. Остановить изменения
↓
7. Финально синхронизировать файлы и базу
↓
8. Проверить контрольные данные
↓
9. Переключить DNS
↓
10. Запустить только новую среду
↓
11. Контролировать старый сервер
↓
12. Завершить перенос почты и интеграций
Главные источники потерь:
- один старый дамп;
- два одновременно работающих сайта;
- забытая AAAA-запись;
- cron на обоих серверах;
- webhook, пришедший на старый IP;
- почта, которую считали частью сайта;
- откат DNS без обратного переноса новых данных.
Самый надёжный способ переноса обычного динамического проекта — заранее скопировать основной объём, кратковременно остановить запись, выполнить финальную синхронизацию и только после проверки открыть новый сервер.
Несколько минут предсказуемого обслуживания обычно безопаснее нескольких дней поиска потерянных заказов.
После успешного переезда может оказаться, что новый хостинг действительно работает быстрее и предоставляет больше возможностей.
Но рано или поздно проект снова начнёт упираться в ограничения. Возникнет вопрос: достаточно ли перейти на старший тариф, можно ли ещё оптимизировать сайт или виртуальный хостинг уже принципиально не поддерживает нужную архитектуру?
В заключительной части серии разберём признаки того, что виртуальный хостинг стал тесен, и отделим реальные причины перехода на VPS от желания купить сервер «на всякий случай».
- 1 Как выбрать хостинг для сайта и не купить себе вторую работу
- 2 Виртуальный хостинг, VPS или облако: что действительно нужно вашему сайту
- 3 Гигабайты ничего не решают: как читать характеристики тарифа хостинга
- 4 «Безлимитный» хостинг: что заканчивается раньше дискового пространства
- 5 Домен подключён, а сайт не открывается: DNS без мистики
- 6 HTTPS включён, а браузер всё равно ругается: SSL без паники
- 7 Письма с сайта пропадают: SMTP, SPF, DKIM и DMARC на пальцах
- 8 Современный PHP-хостинг: зачем Laravel и Symfony нужны SSH, Composer, Node.js, cron и отдельная public-директория
- 9 Деплой без FTP на виртуальном хостинге: Git, Composer и безопасный откат
- 10 Ошибка 500 после загрузки сайта: где искать причину до обращения в поддержку
- 11 Сайт тормозит на хостинге: виноват тариф, код, база или внешний сервис
- 12 Бэкап есть — восстановить нельзя: проверяем резервные копии до аварии
- 13 Переезд на другой хостинг без потери сайта, писем и заказов вы здесь
- 14 Когда виртуальный хостинг стал тесен: пора на VPS или ещё можно остаться скоро
Была статья полезной: