Переїзд сайту на інший сервер зазвичай відкладають до останнього – «працює ж». Наш випадок: старий сервер на Ubuntu 18.04 з панеллю керування, яку давно не підтримують, і PHP 7.4, для якого оновлення безпеки припинилися ще в листопаді 2022 року. PHP 8 на цій версії ОС через стандартні репозиторії вже не встановити, тож лишався один шлях – новий сервер. Нижче – чек-лист, за яким ми перенесли сайт і headless-CMS без простою, і пастки, на які варто зважати.

Крок 0. Аудит: що на сервері насправді живе

Перш ніж щось переносити, з’ясуйте, що з цього взагалі потрібно. Ми перевірили кожен домен на сервері: чи резолвиться він у DNS, що віддає по HTTPS, коли спливає сертифікат.

dig +short A example.com @1.1.1.1
curl -s -o /dev/null -w '%{http_code}' https://example.com/

Результат здивував: половина доменів уже не існувала (NXDOMAIN), але їхні файли, бази і PHP-процеси продовжували жити на сервері. Ще у двох сайтів сертифікати прострочилися місяці тому, а один віддавав 502, бо його PHP-пул «упав» і ніхто цього не помітив. Старі WordPress-установки, до яких ніхто не заходить, – ідеальна ціль для зламу, тож прибирання – це теж безпека.

Крок 1. Архівувати правильно – і перевірити архів

Архів, який ніхто не перевіряв, – це не архів, а надія. Для кожного сайту ми зберігали окремо файли, дамп бази і конфіги вебсервера:

tar czf site.files.tar.gz -C /home/user/web site.com
mysqldump --single-transaction --routines --triggers db_name | gzip > site.db.sql.gz

А потім перевіряли, перш ніж щось видаляти:

  • gzip -t для кожного архіву – чи він не битий;
  • кількість файлів в архіві дорівнює кількості на диску;
  • кількість CREATE TABLE у дампі дорівнює кількості таблиць у живій базі, а в кінці дампу є рядок Dump completed.

Тільки якщо всі перевірки зійшлися – видалення. Скрипт, який ми запускали, просто зупинявся на першій розбіжності.

Пастка: «масові» дії в панелі керування

Під час видалення кількох мертвих доменів поспіль панель після кожного домену перезапускала PHP-FPM – навіть коли її явно просили цього не робити. За кілька секунд systemd побачив «забагато перезапусків» і заблокував сервіс (start-limit-hit). Усі PHP-сайти на сервері віддавали 502 – близько хвилини, доки ми не зняли блокування.

systemctl reset-failed php7.4-fpm
systemctl start php7.4-fpm

Висновок: масові операції – з паузами або з одним перезапуском у кінці. І завжди після них перевіряйте, що живі сайти відповідають 200.

Крок 2. Новий сервер: ізоляція з першого дня

Новий сервер – Ubuntu 24.04, nginx, PHP 8.4, MySQL 8. Замість панелі – прості конфіги, де кожен сайт ізольований:

  • окремий системний користувач і окремий PHP-FPM-пул для CMS – злам одного сайту не дає доступу до іншого;
  • окремий користувач БД з правами лише на свою базу і новим паролем;
  • заборона виконання PHP у теці завантажень і закритий xmlrpc.php, якщо він не потрібен.

Перед переїздом варто перевірити сумісність коду з новою версією PHP. Плагіни зазвичай оновлюються самі, а от власна тема, міні-плагіни і сніпети – ні. Найпростіша перевірка – прогнати їх через php -l потрібної версії ще до переносу.

Крок 3. Перенести і довести, що все однакове

Базу і файли ми переливали напряму зі старого сервера на новий, а потім звіряли: кількість таблиць і записів, кількість файлів. Але найкорисніша перевірка – порівняти відповіді API старого і нового сервера ще до зміни DNS. Для цього не треба нічого міняти в DNS: curl --resolve відправляє запит на потрібний IP з правильним доменом.

curl -s https://cms.example.com/wp-json/wp/v2/posts | md5sum
curl -s --resolve cms.example.com:443:NEW_IP 
     https://cms.example.com/wp-json/wp/v2/posts | md5sum

Однакові хеші для постів, сторінок і меню – і можна спати спокійно.

Крок 4. SSL, який працює з першої секунди

Класична проблема: DNS уже переключили, а сертифіката на новому сервері ще немає, бо Let’s Encrypt не може перевірити домен, який досі вказує на старий IP. Рішення – тимчасово скопіювати чинні сертифікати зі старого сервера. HTTPS працює одразу після перемикання, а власні сертифікати випускаються через certbot, коли DNS уже оновився. Ми використали метод webroot – він не чіпає конфіги nginx, а автоподовження потім працює саме.

Крок 5. DNS: перемкнути і перевірити звідусіль

За тиждень до переїзду варто знизити TTL записів (у нас було 15 хвилин – цього достатньо). Після зміни перевіряйте не лише свій комп’ютер, а й авторитетні DNS-сервери та публічні резолвери:

dig +short A example.com @ns1.your-dns.com
dig +short A example.com @1.1.1.1
dig +short A example.com @8.8.8.8

Неочевидний момент: кеш DNS є і на самому новому сервері. WordPress ще кілька хвилин після перемикання звертався до власного wp-cron на старому IP. Вирішується однією командою: resolvectl flush-caches.

Крок 6. Деплой: секрети міняємо разом з DNS

Фронтенд у нас деплоїться з GitHub Actions по SSH. На новому сервері ми створили того самого користувача для деплою з тим самим публічним ключем, тож змінювати довелося лише два секрети – адресу сервера і шлях. Головне – міняти їх у момент перемикання DNS, не раніше: інакше наступний git push задеплоїть сайт туди, куди ще не йде трафік.

Бонус-знахідка під час ревізії: в адресі git-репозиторію відкритим текстом лежав персональний GitHub-токен з доступом до всього акаунта. Ми його відкликали, git перевели на авторизацію через GitHub CLI, а для вебхука з CMS створили новий fine-grained токен з доступом лише до одного репозиторію.

Крок 7. Не видаляйте старе одразу

Старі сайти ми не видалили, а призупинили: файли й бази лишились на диску, архів – поруч. Відкат займає хвилину: повернути DNS і зняти призупинення. Остаточно старий сервер вимикається тоді, коли все перевірено в бою: деплой, форма зворотного зв’язку, вебхуки.

Чек-лист одним списком

  1. Аудит доменів: DNS, HTTP-статус, сертифікати.
  2. Архів кожного сайту + перевірка архіву.
  3. Масові дії – з паузами, після них перевірка живих сайтів.
  4. Новий сервер з ізоляцією сайтів і окремими користувачами БД.
  5. Перевірка коду на нову версію PHP до переносу.
  6. Перенос і звірка: кількості, хеші відповідей API через curl --resolve.
  7. Тимчасові сертифікати до перемикання DNS, потім certbot.
  8. Знижений TTL, перевірка з кількох резолверів, скидання кешу на сервері.
  9. Секрети деплою – в момент перемикання.
  10. Старе – призупинити, а не видалити.

Плануєте переїзд на новий сервер?

Проведу аудит поточного сервера, перенесу сайт і CMS без простою, налаштую SSL, автодеплой і план відкату – а старий сервер вимкнемо лише тоді, коли все перевірено в роботі.

Обговорити переїзд