Це Частина 2 моєї серії міграцій WordPress без headless. Розгортання headless WordPress — це там, де починаються справжні проблеми, бо DNS, SSL, зображення, форми та редиректи ламаються по-різному. У Частині 1 я за один день відбудував фронтенд за допомогою Claude Code, Stitch MCP і Next.js. У цій статті я показую проблеми розгортання, з якими зіткнувся, як їх виправив, і чому AI все одно потребував людського судження.
Проблема розгортання headless WordPress, про яку ніхто не говорить
Зібрати фронтенд — це найпростіше. У моєму досвіді розгортання headless WordPress стає складним у той момент, коли ти розділяєш один сайт на дві системи: Vercel для фронтенду та WordPress для бекенду. Тепер у тебе вже немає одного простого стеку. У тебе є DNS, сертифікати, медіа-URL, REST endpoints і адмін-доступ, які тягнуть у різні боки.
Коли `optagonen.se` переїхав на Vercel, кожен запит, який раніше йшов у WordPress, почав потрапляти на новий фронтенд. Це зламало GraphQL, завантаження, Contact Form 7 і адмін-доступ за один крок. Якщо ти плануєш власне розгортання headless WordPress, тобі потрібно продумати ці точки розриву ще до того, як перемкнеш DNS.
Я перевірив це на реальній міграції в продакшені, а не в пісочниці. Висновок був очевидний: код зробився швидко, але інфраструктура забрала час.
Розділення DNS для розгортання headless WordPress
Найчистіше рішення — дати WordPress власний піддомен: `wp.optagonen.se`. Так я розділив фронтенд і бекенд без примусу до reverse proxy всього через одне походження. Це також зробило архітектуру простішою для розуміння під час троблшутингу SSL і доставки медіа.
| Domain | Points to | Purpose |
|---|---|---|
| --- | --- | --- |
| `optagonen.se` | Vercel | Frontend in Next.js |
| `wp.optagonen.se` | Origin server | WordPress backend |
Я додав `wp.optagonen.se` як alias у Hestia, вказав DNS A record на IP origin-сервера та оновив змінну середовища у фронтенді:
Ця частина проста на папері. На практиці розгортання headless WordPress спричинило ланцюгову реакцію. Кожна система, яка припускала старий домен, потребувала нового цільового адресату.
Розгортання headless WordPress і збої сертифікатів SSL
Першим зламався SSL. Старий сертифікат Let's Encrypt покривав лише `optagonen.se` і `www.optagonen.se`, тож `https://wp.optagonen.se` падав одразу. Це очікувана поведінка. Let's Encrypt перевіряє належність домену для кожного hostname, і браузер відхилить з’єднання, якщо сертифікат не збігається.
Вбудоване автоматичне продовження в Hestia не спрацювало, бо воно все ще намагалося валідовати основний домен через HTTP-01, але тепер основний домен вказував на Vercel. Certbot не спрацював з іншої причини: Hestia перехоплював ACME challenge і повертав свій власний thumbprint замість thumbprint Certbot. Саме такий конфлікт AI не може вивести з перших принципів. Потрібно знати, як поводиться панель.
Я виправив це, тимчасово виніс конфігурацію ACME challenge Hestia з шляху include для nginx, видав сертифікат лише для `wp.optagonen.se`, а потім скопіював оновлені файли назад у директорію SSL Hestia. Я також додав renewal hook, щоб процес залишався автоматичним.
Для довіри я спирався на офіційну документацію від Let's Encrypt і Certbot. Це допомогло підтвердити ACME flow, перш ніж я знову торкнувся продакшена.
Чому розгортання headless WordPress відхилило піддомен
Коли SSL запрацював, WordPress усе одно не прийняв новий хост. Замість того щоб повертати дані GraphQL, він редиректнув на `/wp-signup.php`. Це підказало, що WordPress не подобається вхідний host header.
Виправлення було одним nginx-директивою:
Цей рядок змусив WordPress поводитися так, ніби запити все ще приходять з основного домену, тоді як браузер залишався на `wp.optagonen.se`. У розгортанні headless WordPress така нормалізація хоста важить більше, ніж люди очікують. WordPress дуже принциповий щодо URL сайту.
Я бачив цей самий клас проблем і в інших міграціях. Фронтенд працює, бекенд відповідає, а потім один невідповідний host header тихо ламає flow сесії.
Після розгортання headless WordPress зламались зображення
Після деплою кожне зображення повертало помилку 502. Це сталося тому, що медіа-URL у WordPress усе ще вказували на `/wp-content/uploads/...`, і ці шляхи тепер резолвились у бік Vercel замість origin-сервера. У моїй конфігурації проблема прийшла з двох місць: hardcoded URLs у статичних файлах і динамічні URL, які поверталися WPGraphQL.
Спочатку я виправив hardcoded URLs. Я замінив кожне посилання `https://optagonen.se/wp-content/uploads/` на `https://wp.optagonen.se/wp-content/uploads/` у всіх шести файлах. Це закрило приблизно 70 шляхів до зображень.
Потім я виправив динамічні GraphQL URL через rewrite в Next.js:
Це зберегло фронтенд чистим і уникнуло переписування медіа-даних у WordPress. Також це зробило розгортання headless WordPress більш підтримуваним, бо браузер усе ще запитує той самий шлях, а сервер уже займається proxying.
Якщо хочеш глибше зануритися в такий дизайн систем, я рекомендую прочитати мою AI-powered WordPress migration workflow→ і мою multi-agent content pipeline→. Ці пости показують, як я структурую інфраструктуру та системи контенту навколо автоматизації.
Contact Forms, IDs і остання пастка деплою
Contact Form 7 спочатку виглядав нормально, але форма перестала працювати, бо ID у фронтенді був неправильний. Дефолтний form ID був `1`, але реальна форма в WordPress мала `8`. Швидка перевірка через API це підтвердила.
Це була невелика правка, але вона важлива. У розгортанні headless WordPress один неправильний ID може зробити робочу форму схожою на зламану, навіть якщо бекенд здоровий. Я встановив `CF7_FORM_ID=8`, і форма одразу повернулась в онлайн.
Ось чому я завжди тестую повний flow вручну:
Ця послідовність знаходить проблеми швидше, ніж гадати лише з логів.
Що AI допоміг зробити і що він пропустив
Claude Code допоміг мені рухатися швидко, але він не замінив розуміння. Він добре впорався з повторюваними частинами: grepping config files, генерацією nginx snippets, допомогою з командами certbot і масовою заміною image URLs. Він також тримав ланцюжок помилок у пам’яті, що заощадило час, коли одна правка створювала іншу проблему.
Однак AI не міг вирішити повну архітектуру. Він не знав, що Hestia перехоплюватиме ACME запити. Він не знав, коли використовувати піддомен замість reverse proxy. І він не знав порядок операцій, який дозволить уникнути простою.
Це справжня цінність AI у розгортанні headless WordPress: він пришвидшує діагностику, але тобі все одно потрібна людина, яка розуміє стек. Я використовую той самий принцип у своїй роботі з AI automation systems for e-commerce→ і в роботі над моїм content pipeline.
Фінальна архітектура після деплою
Після виправлень стек стабілізувався у чистий розподіл:
| Component | Location | Purpose |
|---|---|---|
| --- | --- | --- |
| Next.js frontend | Vercel | Serves pages and handles routing |
| WordPress + WPGraphQL | `wp.optagonen.se` | Content API and media storage |
| Contact Form 7 | `wp.optagonen.se` | Form handling |
| Image proxy | Next.js rewrite rule | Routes uploads to origin |
| Frontend SSL | Vercel | Automatic management |
| Backend SSL | Certbot + renewal hook | Auto-renewed certificates |
Ця структура стабільна й проста для дебагу. Вона також зберігає швидкість фронтенду, одночасно зберігаючи редакційний workflow всередині WordPress. Для розгортання headless WordPress саме цей баланс — ціль.
Висновки з цього розгортання headless WordPress
Ось що я виніс із міграції:
Ці уроки прийшли з реального переїзду в продакшені, а не з підручника. Саме тому я тепер закладаю стільки ж часу на деплой, скільки й на розробку.
Висновок
Розгортання headless WordPress не складне через код. Воно складне, бо DNS, SSL, медіа та host headers залежать одне від одного. У цій міграції я виправив розділення на піддомен, валідацію сертифікатів, доставку зображень і Contact Form 7, і я точно зрозумів, де AI допомагає, а де зупиняється.
Якщо ти плануєш власну міграцію, спочатку прочитай відбудову фронтенду, рано протестуй flow сертифікатів і перевір кожен медіа-шлях перед запуском. Потім перевір live сайт, підтвердь форми та переконайся, що бекенд поводиться так, як очікує WordPress.
Якщо хочеш більше практичних розборів деплою, продовжуй читати пов’язані пости й порівнюй їх зі своїм стеком. Це найшвидший спосіб уникнути помилок у твоєму наступному розгортанні headless WordPress.
Suggested image alt text:
