WordPress «Вас перенаправляють»: зупинка циклів перенаправлень через SSL і cookie

Було корисно?

Якщо ви коли-небудь заходили в wp-admin, бачили індикатор завантаження, а потім опинялися назад на сторінці входу, ніби нічого не сталося — ласкаво просимо у світ циклів перенаправлень WordPress. Браузер каже «занадто багато перенаправлень», або WordPress показує «Вас перенаправляють». Ваші користувачі кажуть «сайт не працює». Ви кажете слова, непридатні для журналу змін.

Цей режим відмови рідко означає «WordPress зламався». Майже завжди це невідповідність між тим, що ваш запит вважає за HTTP vs HTTPS, і тим, що вважає WordPress, або ж cookie, яке не зберігається. Виправлення зазвичай невелике. Полювання може затягнутися, якщо ви не ставитеся до нього як до інциденту SRE: відтворіть, спостерігайте, звузьте, змініть одну річ, перевірте.

Що насправді означає ця помилка (і чому виникає цикл)

Цикли перенаправлень у WordPress — це суперечка між шарами. Ваш браузер виконує інструкції на кшталт: «йди на https://…», потім «ні, йди на http://…», потім «опа, знову https». Або ви входите, але автентифікаційне cookie не відповідає хосту/схемі/шляху, які очікує WordPress, тож WordPress вирішує, що ви неавторизовані, і перенаправляє вас назад на вхід, що знову намагається увійти, і знову провалюється. Коло за колом.

WordPress сам виконує перенаправлення з кількох місць:

  • Канонізація URL сайту (невідповідність Home/SiteURL або неправильна схема/хост): WordPress намагається примусово встановити те, що вважає URL сайту.
  • Примусове HTTPS в адмінці (FORCE_SSL_ADMIN, правила wp-admin): шляхи входу і адмінки примусово переводяться на HTTPS.
  • Плагінні auth cookie (COOKIE_DOMAIN, secure cookies, cookie path): якщо cookie не підходить, поводиться так, ніби ви ніколи не входили.
  • Рішення проксі/CDN (X-Forwarded-Proto, CF-Visitor, TLS offload): WordPress бачить «HTTP» на бекенді, тоді як у користувача в браузері «HTTPS».
  • Перезаписи на сервері (.htaccess, Nginx return 301, перенаправлення на рівні застосунку): кілька механізмів перенаправлення конкурують за контроль.

У продакшні у вас майже завжди є як мінімум три системи, які вважають себе «єдиним правдивим місцем для перенаправлень»: CDN, балансувальник навантаження/зворотний проксі та origin web server. WordPress — це четвертий. Якщо двоє з них не погоджуються щодо схеми або хоста, ви отримаєте цикл. Якщо вони погоджуються, але cookie не зберігається, отримаєте цикл входу, який виглядає схоже, але інший за суттю.

Одна суха порада, що окупає витрати: виберіть саме один шар, який відповідає за HTTP→HTTPS та www→без-www канонічні перенаправлення. Інші мають лише пропускати запит і правильно встановлювати заголовки.

Швидкий план діагностики

1) Підтвердьте, який це тип циклу (схема/хост чи cookie)

Якщо ланцюжок перенаправлень чергує http і https, або www і кореневий домен, ви в канонізаційному пеклі. Якщо він постійно повертає вас до /wp-login.php після успішного POST, ймовірно, це cookie‑пекло.

2) Спостерігайте ланцюг перенаправлень ззовні, а не з браузера

Використовуйте curl, щоб бачити заголовки Location. Ваш браузер корисний, поки не стає — він приховує деталі за «занадто багато перенаправлень».

3) Визначте точку завершення SSL

Де закінчується TLS? CDN? Балансувальник? Nginx на хості? Якщо origin бачить HTTP, тоді як клієнт бачить HTTPS, потрібно передавати інформацію про схему через заголовки і навчити WordPress їм довіряти.

4) Перевірте «правду» WordPress: Home і SiteURL

WordPress зберігає ці значення в базі даних і іноді в wp-config.php. Якщо вони не відповідають публічному URL, WordPress буде «виправляти» це перенаправленнями вічно.

5) Лише потім дивіться на плагіни, кешування і дивні правила перезапису

Плагіни справді викликають цикли, але більшість «плагінних» циклів — це все ж проблеми схеми/cookie. Вимикайте плагіни останніми, а не першими. Ви ж хочете налагоджувати системи, а не виконувати екзорцизм.

Цитата, бо пасує: «Сподівання — не стратегія.» — Генерал Гордон Р. Салліван

Таксономія циклів перенаправлень: SSL vs cookie vs кешування

A) SSL-термінація / невідповідність заголовків проксі

Класичний сценарій: клієнт підключається через HTTPS до CDN або балансувальника, який підключається до origin через HTTP. WordPress на origin бачить $_SERVER['HTTPS'] як вимкнений, а порт сервера — 80. WordPress будує URL як http://, тоді edge примушує https://, потім WordPress знову примушує http://, і ви побудували перпетуум-мобіле, що породжує лише розчарування.

Шаблон виправлення: переконайтеся, що edge встановлює X-Forwarded-Proto: https (і/або вендорний заголовок), і що origin та WordPress правильно його інтерпретують. Потім переконайтеся, що лише один шар відповідає за HTTPS‑перенаправлення.

B) Cookie не встановлюється / не повертається (цикл входу)

Ви вводите облікові дані, відбувається «вхід», а потім ви повертаєтеся до екрану входу. Це WordPress не бачить валідного auth cookie у наступному запиті. Причини включають:

  • Secure cookie встановлюється по HTTPS, але сайт доступний по HTTP (або навпаки).
  • Неправильний домен cookie (COOKIE_DOMAIN — невідповідність між example.com та www.example.com).
  • Проксі переписує заголовок Host; WordPress встановлює cookie для неправильного домену.
  • Політики SameSite взаємодіють із вбудованими потоками входу (рідше для стандартного wp-admin, частіше для SSO-потоків).
  • Кеш-шар кешує сторінку входу або відповіді перенаправлення. Так, люди так роблять. Ні, це не закінчується добре.

C) Конфліктуючі канонічні перенаправлення (www, слеші, мультисайт)

WordPress прагне канонічного URL. Те саме прагнуть ваш CDN, ваш зворотний проксі і п’ять різних плагінів, що хочуть «допомогти SEO». Коли кілька компонентів кожен «виправляє» URL по-своєму — додаючи/видаляючи www, примушуючи кінець слешем, нормалізуючи регістр або додаючи /index.php — ви можете створити цикл без участі SSL взагалі.

D) Наслідки кешування та «оптимізацій»

Відповіді перенаправлення можуть кешуватися. Деякі кеші агресивно зберігають 301/302, якщо їм так сказали, і деякі адміністратори випадково кешують їх надто широко. Якщо кеш зберіг поганий заголовок Location, ви можете виправити origin і все одно бачити цикл з певних гео або лише для певних користувачів.

Жарт №1: Цикли перенаправлень схожі на офісну політику — всі наполягають, що вони «просто узгоджують», а ніхто не відповідає за реальний наслідок.

Практичні завдання (команди, виводи, рішення)

Ці завдання розраховані на виконання з адмінської оболонки на origin-хості або з бастіону. Якщо ви не можете виконувати команди, адаптуйте їх під своє оточення. Суть та сама: збирайте докази, а потім приймайте рішення.

Завдання 1: Проінспектуйте ланцюг перенаправлень за допомогою curl

cr0x@server:~$ curl -sS -D - -o /dev/null -L --max-redirs 10 https://example.com/wp-admin/ | sed -n '1,120p'
HTTP/2 302
location: https://example.com/wp-login.php?redirect_to=https%3A%2F%2Fexample.com%2Fwp-admin%2F&reauth=1
set-cookie: wordpress_test_cookie=WP%20Cookie%20check; path=/; secure; HttpOnly

HTTP/2 302
location: https://example.com/wp-admin/
set-cookie: wordpress_logged_in_abc123=cr0x%7C1735900000%7Ctoken; path=/; secure; HttpOnly

HTTP/2 302
location: https://example.com/wp-login.php?redirect_to=https%3A%2F%2Fexample.com%2Fwp-admin%2F&reauth=1

Що це означає: Ми скачуємося між wp-login і wp-admin навіть після встановлення cookie logged_in. Це сильно натякає, що cookie не повертається або недійсне для наступних запитів.

Рішення: Перейдіть до перевірок, орієнтованих на cookie: домен, прапорець secure, заголовки проксі Host і кешування ендпоінтів автентифікації.

Завдання 2: Перевірте, чи відбувається чергування http↔https

cr0x@server:~$ curl -sS -I http://example.com/ | egrep -i '^(HTTP|location)'
HTTP/1.1 301 Moved Permanently
Location: https://example.com/

cr0x@server:~$ curl -sS -I https://example.com/ | egrep -i '^(HTTP|location)'
HTTP/2 301
location: http://example.com/

Що це означає: Ваш edge перенаправляє HTTP→HTTPS, але origin (або застосунок) перенаправляє HTTPS→HTTP. Це чистий двовузловий цикл.

Рішення: Виберіть канонічну схему (ми в 2025; це HTTPS), потім вимкніть конфліктне перенаправлення на одному шарі і виправте обробку forwarded-proto.

Завдання 3: Підтвердіть, що WordPress вважає URL сайту (WP-CLI)

cr0x@server:~$ cd /var/www/html
cr0x@server:/var/www/html$ sudo -u www-data wp option get home
http://example.com
cr0x@server:/var/www/html$ sudo -u www-data wp option get siteurl
http://example.com

Що це означає: WordPress вважає, що сайт HTTP. Якщо публічний сайт HTTPS, WordPress буде постійно намагатися «виправити» це, залежно від налаштувань і плагінів.

Рішення: Оновіть home і siteurl на HTTPS (після підтвердження, що TLS коректно завершується і заголовки проксі вірні).

Завдання 4: Безпечно встановіть Home/SiteURL за допомогою WP-CLI

cr0x@server:/var/www/html$ sudo -u www-data wp option update home 'https://example.com'
Success: Updated 'home' option.
cr0x@server:/var/www/html$ sudo -u www-data wp option update siteurl 'https://example.com'
Success: Updated 'siteurl' option.

Що це означає: Ви змінили канонічні URL в БД. WordPress тепер буде генерувати HTTPS‑URL.

Рішення: Негайно повторно протестуйте ланцюг перенаправлень. Якщо цикл лишається, ймовірно, у вас є правило перенаправлення вищого рівня або невідповідність проксі.

Завдання 5: Перевірте wp-config.php на жорстко прописані переоприділення URL

cr0x@server:~$ sudo egrep -n "WP_HOME|WP_SITEURL|FORCE_SSL_ADMIN|COOKIE_DOMAIN|COOKIEPATH|SITECOOKIEPATH" /var/www/html/wp-config.php
82:define('WP_HOME','http://example.com');
83:define('WP_SITEURL','http://example.com');

Що це означає: Навіть якщо ви виправили БД, ці константи її переоприділяють. Це поширена пастка «чому нічого не змінилося?».

Рішення: Змініть їх на HTTPS або видаліть і керуйте через БД (виберіть одну площину керування; не змішуйте необачно).

Завдання 6: Перевірте, яку схему вважає origin

cr0x@server:~$ sudo -u www-data php -r 'var_export([$_SERVER["HTTPS"]??null,$_SERVER["SERVER_PORT"]??null,$_SERVER["HTTP_X_FORWARDED_PROTO"]??null,$_SERVER["HTTP_HOST"]??null]);'
array (
  0 => NULL,
  1 => '80',
  2 => 'https',
  3 => 'example.com',
)

Що це означає: TLS завершується upstream (HTTPS null, порт 80), але проксі надсилає X-Forwarded-Proto=https. WordPress не буде автоматично довіряти цьому, якщо стек не налаштовано відповідним чином.

Рішення: Переконайтеся, що зворотний проксі послідовно передає заголовок, і налаштуйте WordPress/PHP так, щоб вони трактували X-Forwarded-Proto як авторитетний (акуратно — лише коли ви довіряєте проксі).

Завдання 7: Перегляньте заголовки проксі в Nginx (поширена причина)

cr0x@server:~$ sudo nginx -T 2>/dev/null | egrep -n "proxy_set_header (Host|X-Forwarded-Proto|X-Forwarded-For)|return 301|listen 443|listen 80" | sed -n '1,120p'
45:    listen 80;
61:    return 301 https://$host$request_uri;
90:    listen 443 ssl http2;
132:    proxy_set_header Host $host;
133:    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
134:    proxy_set_header X-Forwarded-Proto $scheme;

Що це означає: Якщо origin стоїть за іншим проксі, $scheme може бути http, навіть коли клієнт використовував HTTPS. Тоді WordPress бачить forwarded-proto=http і генерує HTTP‑перенаправлення.

Рішення: Якщо TLS завершується на edge, встановлюйте X-Forwarded-Proto https (або передавайте заголовок proto від edge) між проксі, а не використовуйте $scheme.

Завдання 8: Перевірте правила перезапису Apache (.htaccess) на наявність конфліктних перенаправлень

cr0x@server:~$ sudo sed -n '1,160p' /var/www/html/.htaccess
# BEGIN WordPress
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

Що це означає: Це примушує HTTPS на origin. Якщо ваш edge вже примушує HTTPS, але спілкується з origin по HTTP, Apache перенаправляє на HTTPS на origin — іноді на неправильний хост, іноді з приватним ім’ям, іноді просто в петлю з edge.

Рішення: Перемістіть примус HTTPS на edge (рекомендовано) або термінуйте TLS на origin. Не робіть цього наполовину на обох.

Завдання 9: Підтвердіть поведінку Cloudflare/Flexible SSL (за даними заголовків)

cr0x@server:~$ curl -sS -I https://example.com/ | egrep -i "^(cf-|server:|location:|x-forwarded-proto:)"
server: cloudflare
cf-cache-status: DYNAMIC

Що це означає: Ви за Cloudflare (або подібним CDN). Якщо CDN налаштований у режимі, коли він підключається до origin по HTTP, але клієнту показує HTTPS, ви повинні переконатися, що origin-стек розуміє реальну схему.

Рішення: Віддавайте перевагу режимам «Full»/end-to-end TLS і узгодженому обробленню forwarded-proto. Також переконайтеся, що CDN не переписує заголовки Location дивовижним чином.

Завдання 10: Перевірте, чи куки повертаються (curl cookie jar)

cr0x@server:~$ curl -sS -c /tmp/cj.txt -b /tmp/cj.txt -L --max-redirs 5 https://example.com/wp-login.php -o /dev/null -D - | egrep -i "set-cookie:|location:|HTTP/"
HTTP/2 200
set-cookie: wordpress_test_cookie=WP%20Cookie%20check; path=/; secure; HttpOnly

cr0x@server:~$ grep -v '^#' /tmp/cj.txt | sed -n '1,5p'
example.com	FALSE	/	TRUE	0	wordpress_test_cookie	WP%20Cookie%20check

Що це означає: Cookie має прапорець Secure і обмежене до example.com та /. Якщо ви заходите через www.example.com або по HTTP, воно не буде відправлено. Також, якщо проксі переписує Host, домен cookie може бути неправильним.

Рішення: Переконайтеся, що публічне ім’я хоста відповідає тому, що використовує WordPress, і уникайте стрибків між www і кореневим доменом під час входу.

Завдання 11: Підтвердіть збереження заголовка Host через проксі

cr0x@server:~$ curl -sS -H 'Host: example.com' -I http://127.0.0.1/ | egrep -i "^(HTTP|location|set-cookie)"
HTTP/1.1 301 Moved Permanently
Location: https://example.com/

Що це означає: Ваш локальний vhost відповідає коректно, коли встановлено Host. Якщо натомість ви бачите перенаправлення на внутрішнє ім’я, ваша конфігурація проксі/origin проявляє внутрішні імена в заголовках Location.

Рішення: Виправте vhost/server_name і proxy_set_header Host; також підтвердіть, що home/siteurl WordPress відповідають бажаному публічному хосту.

Завдання 12: Пошукайте кешовані перенаправлення в Nginx або кеш-проксі

cr0x@server:~$ sudo egrep -R "proxy_cache|fastcgi_cache|expires|add_header Cache-Control|location = /wp-login.php|location ~ \\.php" -n /etc/nginx | sed -n '1,120p'
/etc/nginx/sites-enabled/example.conf:55:    fastcgi_cache WORDPRESS;
/etc/nginx/sites-enabled/example.conf:56:    add_header X-Cache $upstream_cache_status;
/etc/nginx/sites-enabled/example.conf:80:    location = /wp-login.php { include fastcgi_params; }
/etc/nginx/sites-enabled/example.conf:81:    fastcgi_cache WORDPRESS;

Що це означає: Хтось кешує PHP‑відповіді, включаючи wp-login.php. Це може кешувати перенаправлення та Set-Cookie заголовки, породжуючи дивні цикли, що змінюються для різних користувачів.

Рішення: Вимкніть кешування для ендпоінтів входу/адмінки та для відповідей, що встановлюють auth cookie. Кешуйте анонімний фронтенд, а не потоки автентифікації.

Завдання 13: Перевірте, чи WordPress неправильно визначає HTTPS (швидкий mu-plugin тест)

cr0x@server:~$ sudo install -d /var/www/html/wp-content/mu-plugins
cr0x@server:~$ sudo tee /var/www/html/wp-content/mu-plugins/00-proxy-https.php >/dev/null <<'PHP'
<?php
// Trust X-Forwarded-Proto only if coming from known proxies (adjust CIDRs).
$trusted = ['10.0.0.0/8','172.16.0.0/12','192.168.0.0/16'];
$remote = $_SERVER['REMOTE_ADDR'] ?? '';
function ip_in_cidrs($ip, $cidrs) {
  foreach ($cidrs as $cidr) {
    [$subnet,$bits] = explode('/', $cidr);
    $ip_long = ip2long($ip);
    $sub_long = ip2long($subnet);
    $mask = -1 << (32 - (int)$bits);
    if (($ip_long & $mask) === ($sub_long & $mask)) return true;
  }
  return false;
}
if (ip_in_cidrs($remote, $trusted)) {
  if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
    $_SERVER['SERVER_PORT'] = 443;
  }
}
PHP

Що це означає: Це прагматичний тест, щоб примусово виявляти HTTPS за довіреними проксі. Це не «остаточне» рішення для всіх середовищ, але швидко доводить, чи виявлення схеми є причиною.

Рішення: Якщо цикли зникають, реалізуйте чистіше довготривале рішення в стеку проксі/застосунку і збережіть межу довіри точною.

Завдання 14: Перевірте Home/SiteURL на рівні БД без WP-CLI (якщо CLI зломано)

cr0x@server:~$ mysql -N -e "SELECT option_name, option_value FROM wp_options WHERE option_name IN ('home','siteurl');"
home	http://example.com
siteurl	http://example.com

Що це означає: Те саме, що і WP-CLI, але працює, коли PHP/CLI інтеграція зламана.

Рішення: Оновіть ці значення (обережно), якщо вони неправильні. Якщо ви використовуєте multisite, зупиніться і прочитайте розділ FAQ для multisite нижче спочатку.

Завдання 15: Переконайтеся, що адмін-куки не відсікаються політикою заголовків безпеки

cr0x@server:~$ curl -sS -I https://example.com/wp-login.php | egrep -i "set-cookie|content-security-policy|strict-transport-security|x-frame-options"
strict-transport-security: max-age=31536000; includeSubDomains; preload

Що це означає: HSTS корисний і зазвичай допомагає. Але якщо ви встановлюєте includeSubDomains і маєте застарілі піддомени на HTTP, ці клієнти будуть примушені до HTTPS і можуть потрапити на некоректні ендпоінти — іноді це породжує плутанину перенаправлень.

Рішення: Залишайте HSTS, але лише після перевірки покриття TLS для всіх необхідних піддоменів. Не встановлюйте preload необдумано.

Жарт №2: Якщо ваш WordPress застряг у циклі перенаправлень, вітаю — ваш сайт досяг перпетуум-мобіле, просто не корисного виду.

Три міні-історії з корпоративного життя

1) Інцидент, спричинений помилковим припущенням: «Балансувальник HTTPS, отже застосунок знає про HTTPS»

Вони тільки-но мігрували з однієї VM з Apache до «правильного» стеку: CDN → балансувальник → Nginx → PHP-FPM. У запиті на зміну було «без функціональних змін». Ця фраза закінчувала більше вечорів, ніж будь-який інший інцидент.

Сайт піднявся. Головна сторінка виглядала нормально. Потім редактори спробували увійти і отримали цикл «Вас перенаправляють». Інженер на чергуванні виконав стандартний танець: очистити cookie браузера, спробувати інкогніто, відключити кілька плагінів. Нічого. Тим часом маркетинг відкрив нові способи оновлення сторінки.

Основне припущення було тонким: оскільки клієнт використовував HTTPS, застосунок мав знати, що він HTTPS. Але TLS завершувався на балансувальнику, а трафік до origin був по HTTP. Nginx встановлював X-Forwarded-Proto використовуючи $scheme, який на цьому етапі був http. WordPress бачив HTTP, встановлював очікування без secure, і відскакував адмінське перенаправлення.

Виправлення було негарним і негайним: встановити X-Forwarded-Proto на основі вхідного заголовка від балансувальника, а не локальної схеми; додати невеликий фрагмент для визначення HTTPS у WordPress з чіткою межею довіри до проксі; потім стандартизувати власника перенаправлень на edge. Після цього цикл входу зник.

Постмортем висновок був ще менш гламурний: «не припускайте нічого про схему; дивіться заголовки на кожному хопі». Вони додали однорядковий endpoint для дампу заголовків для внутрішнього дебагу і закріпили, хто може змінювати логіку проксі-заголовків. Інцидент не був героїчним; це була відсутність факту.

2) Оптимізація, що відкотилася: кешування wp-login.php «заради продуктивності»

Інша організація мала проблему зі сплеском трафіку. Фронтенд був на WordPress і коефіцієнт попадань кешу був… амбітним. Доброзичлива ініціатива продуктивності розгорнула агресивні правила Nginx fastcgi_cache. Мета була розумною: знизити навантаження на PHP, зменшити латентність, уникнути витрат на масштабування.

У стенді все виглядало чудово. Потім настав продакшн: випадкові відмови входу, деякі користувачі бачили редиректи після входу інших користувачів, і дивний цикл перенаправлень, що відбувався лише в певних регіонах. Це не відбувалося стабільно, що робило проблему схожою на «WordPress глючить». Але це не так.

Вони кешували відповіді з /wp-login.php і деякі перенаправлення з /wp-admin/. Це означало кешовані заголовки Location і кешовану поведінку Set-Cookie, що по суті «повторно використовує стару хореографію автентифікації». Якщо ви хочете озброїти кеш проти власної системи автентифікації — це ефективний спосіб.

Рішення: зробити явні правила no-cache для /wp-login.php, /wp-admin/ та будь-якого запиту/відповіді, що встановлює auth cookie. Також вони зробили ключ кешу чутливим до схеми/хоста та кількох заголовків, що мають значення. Продуктивність трохи впала. Надійність різко зросла. Це компроміс, який варто робити.

Після цього вони продовжили кешувати — але тільки для анонімних GET і тільки для контентних сторінок. Команда також навчилася трактувати кешування 301/302 як функціональність, контрольовану змінами. Кешування перенаправлень може бути корисним; може також бути інцидентом в плащі.

3) Нудна, але коректна практика, що врятувала день: один шар власник перенаправлень + записані тести перенаправлень

Третя команда керувала WordPress для кількох бізнес-одиниць за CDN і двома шарами проксі. Їх вже обпікали раніше, тож вони зробили дещо глибоко немодне: встановили правило і задокументували його.

Правило: CDN відповідає за HTTP→HTTPS і нормалізацію www. Origin ніколи не виконує перенаправлень схеми/хоста, лише на рівні застосунку (наприклад, постійні посилання). Усі проксі мають зберігати Host і послідовно встановлювати forwarded proto. Home/SiteURL WordPress має відповідати публічному URL, а будь-які переоприділення в wp-config.php заборонені, якщо на це немає тикета з обґрунтуванням.

Вони також створили невеликий регресійний тест ланцюга перенаправлень як частину перевірки розгортання. Він запускав curl -IL проти ключових ендпоінтів (/, /wp-admin/, /wp-login.php) і перевіряв: максимум 3 перенаправлення, фінальна схема https, фінальний хост канонічний, без стрибків між login/admin. Якщо ланцюг змінювався, розгортання блокувалося.

Через місяць оновлення плагіна вендора додало нову канонічну поведінку, яка б конфліктувала з правилами CDN. Тест зловив це до клієнтів. Героїзм не був потрібний; був потрібний нудний ворота, що каже «не сьогодні».

Поширені помилки: симптом → причина → виправлення

1) «Занадто багато перенаправлень» тільки по HTTPS

  • Симптом: HTTP працює (або перенаправляє один раз), HTTPS зациклюється.
  • Причина: Origin вважає, що запити — HTTP, бо TLS завершується upstream; WordPress генерує HTTP URL і перенаправлення.
  • Виправлення: Правильно передайте і довіряйте X-Forwarded-Proto=https; встановіть home/siteurl WordPress на https; переконайтеся, що лише один шар примушує схему.

2) Цикл входу: облікові дані приймаються, а потім повертають на wp-login.php

  • Симптом: POST до wp-login успішний, але потім перенаправляє назад на вхід з reauth=1.
  • Причина: Auth cookie не повертається (невідповідність домену, прапорця secure, кешування або перепис заголовка Host).
  • Виправлення: Забезпечте послідовний хост (www vs кореневий), правильний COOKIE_DOMAIN (або скиньте), не кешуйте ендпоінти автентифікації, зберігайте Host через проксі.

3) Перемикання між www і non-www в заголовках Location

  • Симптом: Ланцюг перенаправлень перемикається між example.com і www.example.com.
  • Причина: CDN примушує один хост; home/siteurl WordPress або правило сервера примушує інший.
  • Виправлення: Оберіть канонічний хост, встановіть його лише на одному шарі, вирівняйте home/siteurl WordPress і видаліть конкуруючі правила перезапису.

4) Цикл перенаправлень з’являється тільки після ввімкнення HSTS

  • Симптом: Деякі клієнти застрягають; інші в порядку.
  • Причина: HSTS примушує HTTPS для піддоменів, які ще не готові; піддомен перенаправляє на HTTP, а браузери відмовляються.
  • Виправлення: Приберіть includeSubDomains, поки не забезпечите покриття TLS для всіх піддоменів, або виправте TLS для всіх піддоменів; не поспішайте з preload.

5) Цикл тільки для певних регіонів / провайдерів

  • Симптом: Тікети підтримки надходять з одного регіону; у вас не відтворюється локально.
  • Причина: Edge‑кеш зберігає застарілий 301/302 або неузгоджена конфігурація CDN по POP.
  • Виправлення: Очистіть кешовані перенаправлення; зменшіть кешованість перенаправлень; перевірте однорідність конфігурації по POP.

6) Цикл починається одразу після зміни URL сайту в налаштуваннях WordPress

  • Симптом: Адмінка стає недоступною негайно після зміни URL.
  • Причина: Новий URL не відповідає реальному vhost/маршрутизації ingress; WordPress перенаправляє вас на хост, який не обслуговує WordPress.
  • Виправлення: Оновлюйте через WP-CLI або БД обережно; переконайтеся, що DNS/vhost співпадають; тимчасово додайте запис у hosts для тестування.

7) Мультисайт: цикли адмінки після змін у доменному мапінгу

  • Симптом: Мережевий адмін працює на одному домені, але не на замаплених сайтах.
  • Причина: Неправильний domain mapping або конфлікти cookie domain/path між підсайтами.
  • Виправлення: Підтвердіть константи мультисайту і налаштування domain mapping; вирівняйте конфігурацію cookie з обраною стратегією мапінгу; переконайтеся, що проксі зберігає Host для кожного сайту.

Чеклісти / покроковий план

Покроково: виправлення SSL/proxy циклу перенаправлень (поширений випадок)

  1. Спостерігайте ланцюг перенаправлень за допомогою curl. Підтвердіть, чи чергуються схеми або хости.
  2. Визначте завершення TLS: CDN, LB, origin. Намалюйте діаграму хопів. Не здогадуйтеся.
  3. Оберіть власника перенаправлень: зазвичай edge (CDN/LB) для схеми й канонічного хоста.
  4. Вимкніть конкуруючі перенаправлення на інших шарах (видаліть конфліктні Nginx/Apache return/rewrite правила; проведіть аудит плагінів, які примушують SSL).
  5. Виправте forwarded заголовки: зберігайте Host; встановлюйте X-Forwarded-Proto відповідно до схеми клієнта; переконайтеся, що upstream→origin хопи не перезаписують їх неправильно.
  6. Навчіть WordPress інтерпретувати схему за проксі (через довірений proxy-конфіг/фрагмент), але не довіряйте довільним заголовкам від клієнта в інтернеті.
  7. Встановіть home/siteurl WordPress на канонічний публічний URL (краще через БД або константи в wp-config, але не обидва одночасно).
  8. Повторно протестуйте ланцюг перенаправлень: макс. кількість редиректів, фінальний URL, послідовний хост, послідовна схема.
  9. Очистіть кеші (CDN та будь-які зворотні проксі), якщо перенаправлення були закешовані.
  10. Додайте регресійний чек, щоб наступна «дрібна зміна» не стала інцидентом.

Покроково: виправлення циклу cookie/входу

  1. Відтворіть через curl cookie jar, щоб підтвердити, чи cookie встановлюються і повертаються.
  2. Стабілізуйте ім’я хоста: завжди використовуйте канонічний хост для входу/адмінки. Не стрибайте між www і кореневим доменом.
  3. Перевірте область cookie: домен і шлях. Уникайте примусу COOKIE_DOMAIN, якщо це не необхідно.
  4. Забезпечте послідовність secure cookie: якщо cookie мають Secure, обслуговуйте вхід/адмінку завжди по HTTPS end-to-end.
  5. Вимкніть кешування для ендпоінтів автентифікації всюди: правила CDN, Nginx/Apache, плагіни.
  6. Перевірте збереження заголовка Host через проксі; WordPress використовує його при побудові редиректів і cookie.
  7. Лише потім підозрюйте плагіни, що змінюють потоки входу, security‑плагіни або кастомні SSO інтеграції.

Операційний чекліст: що зафіксувати під час інциденту

  • Точні URL, що падають, і чи стосується це анонімних користувачів або лише автентифікованих.
  • Вивід ланцюга перенаправлень (curl -IL з заголовками) з принаймні одного зовнішнього ракурсу.
  • Де завершується TLS і які заголовки форвардяться на кожному хопі.
  • Поточні значення home/siteurl і будь‑які переоприділення у wp-config.
  • Шари кешування на шляху і чи кешуються перенаправлення.
  • Що змінилося нещодавно (правило CDN, плагін, міграція, оновлення сертифіката, політика балансувальника).

Факти та історичний контекст

  • Факт 1: Ранні вебзастосунки часто покладалися на наявність серверних змінних, як-от HTTPS=on; зворотні проксі зламали це припущення задовго до того, як воно стало масовим.
  • Факт 2: Заголовок X-Forwarded-Proto виник як де-факто стандарт, тому що бекенди потребували знати оригінальну схему клієнта після завершення TLS upstream.
  • Факт 3: WordPress зберігає home і siteurl у базі даних — дизайн, що полегшив переміщення/перейменування сайту, поки ви не забули їх оновити під час міграції.
  • Факт 4: Логін WordPress залежить від кількох cookie (test cookie, logged_in, auth, secure_auth), і різні шляхи/області можуть застосовуватися для адмінки та фронтенду.
  • Факт 5: Кеші стали поширеними перед WordPress, бо рендеринг PHP під навантаженням був дорогим; кешування потоків автентифікації завжди було поганою ідеєю, але «завжди» ніколи не зупиняло всіх.
  • Факт 6: HTTPS перестав бути «потрібним для платежів» і став «стандартною очікуваною практикою» завдяки змінам UX браузерів і SEO‑стимулам, що збільшило частоту помилок невідповідності HTTP/HTTPS.
  • Факт 7: HSTS створено, щоб запобігати SSL‑stripping атакам; в операційному плані це також означає, що одна неправильна конфігурація HTTPS може надовго закріпитися на клієнтах.
  • Факт 8: Статуси перенаправлення важливі: 301 можуть кешуватися агресивно браузерами і CDN, роблячи тимчасову помилку надзвичайно стійкою.
  • Факт 9: Режими на кшталт «Flexible SSL» існують, щоб полегшити інтеграцію, але вони також нормалізують небезпечний шаблон HTTPS‑на‑edge і HTTP‑на‑origin, у якому народжується багато циклів.

Часті запитання

1) Чому WordPress каже «Вас перенаправляють» замість показу помилки?

Це повідомлення зазвичай означає, що WordPress намагається відправити перенаправлення (часто через JavaScript/meta refresh), коли вважає, що URL запиту неправильний або автентифікація неповна. Браузер потім потрапляє на наступний URL і цикл повторюється.

2) Чи завжди це спричинено SSL?

Ні. Невідповідність SSL/proxy — поширена, але проблеми з областю cookie (домен/шлях/secure flag), кешовані перенаправлення та конфліктні правила www/non-www також трапляються часто. Найшвидший спосіб розрізнити — дивитися ланцюг: чергування схем підказує SSL; стрибки входу/адмінки підказують cookie.

3) Чи вирішити це, прописавши WP_HOME та WP_SITEURL у wp-config.php?

Іноді. Це валідна площина керування, особливо якщо ви хочете конфігурацію як код. Але не змішуйте її необережно з значеннями в БД; переоприділення можуть заплутати майбутнього вас. Якщо ви встановлюєте їх у wp-config.php, позбавтеся спокуси «просто змінити це в інтерфейсі».

4) Я за балансувальником. Які заголовки мають бути коректними?

Щонайменше: зберігайте Host і передавайте X-Forwarded-Proto, що відображає схему клієнта. Також передавайте X-Forwarded-For для логів/лімітування. Потім переконайтеся, що WordPress/PHP довіряють цим заголовкам лише від відомих IP проксі.

5) Чому це працює для мене, але не для інших користувачів?

Зазвичай через кешування. POP CDN може мати закешований поганий 301/302; або браузер закешував 301; або певний шлях кешується зі стертими Set-Cookie. Очистіть edge‑кеші і перевірте Cache-Control на відповідах перенаправлень.

6) Як зрозуміти, що cookie — проблема?

Якщо вхід «успішний», але ви опиняєтеся назад на wp-login.php, це майже завжди cookie. Підтвердьте, захопивши Set-Cookie і переконайтеся, що cookie повертається у наступному запиті (curl cookie jar або панель розробника браузера в заголовках запиту).

7) Чи може плагін спричинити цикл перенаправлень?

Так, особливо security/SSL/SEO плагіни. Але звинувачувати плагіни потрібно на останньому етапі після підтвердження, що інфраструктура не брешить щодо схеми/хоста. Вимикайте плагіни лише після зйомки ланцюга перенаправлень і перевірки home/siteurl і заголовків проксі.

8) А мультисайт — чи відрізняються виправлення?

Multisite додає більше способів неправильно налаштувати домен/область cookie. Home/siteurl може не описувати всю картину, domain mapping додає складності, і cookie domain/path можуть різнитися для підсайтів. Підходьте так само — спостерігайте перенаправлення і cookie — але перевіряйте для кожного сайту його хостнейм і мережеві налаштування.

9) Я виправив origin, але браузери все ще зациклюються. Чому?

Браузери агресивно кешують 301. CDN також може кешувати перенаправлення, якщо йому так сказали. Тестуйте з чистим клієнтом, очищайте кеші і розгляньте тимчасове використання 302 під час стабілізації міграції, потім перемикайте на 301 коли впевнені.

10) Чи є «найкраща» архітектура, щоб цього уникнути?

Так: end-to-end HTTPS, один власник канонічних перенаправлень (зазвичай edge), коректні forwarded заголовки і явні правила no-cache для auth/admin. Це не захоплююче. Саме тому це працює.

Висновок: наступні кроки, що не марнують вашого дня

Якщо ви візьмете тільки одну операційну звичку з цього: завжди фіксуйте ланцюг перенаправлень і поведінку cookie перед тим, як щось змінювати. Цикли перенаправлень здаються хаотичними, але вони детерміновані. Система робить саме те, що ви їй наказали — просто не те, що ви хотіли.

Практичні наступні кроки:

  1. Запустіть перевірки ланцюга перенаправлень за допомогою curl і класифікуйте цикл (схема/хост чи cookie).
  2. Вирівняйте home/siteurl WordPress з публічним канонічним URL і видаліть конфліктні переоприділення.
  3. Виправте проксі-заголовки і межі довіри, щоб origin знав схему і хост клієнта.
  4. Нехай один шар володіє канонічними перенаправленнями; відключіть інші.
  5. Виключіть login/admin з усіх шарів кешування, потім очистіть кешовані перенаправлення.
  6. Додайте невеликий регресійний тест перенаправлень у розгортання, щоб це стало вирішеною задачею, а не постійною зустріччю.
← Попередня
Debian/Ubuntu: «Працює в LAN, не працює в WAN» — перевірки маршрутизації/NAT, що виявляють причину (case #85)
Наступна →
Повільні DNS‑запити в Linux: виправте systemd-resolved правильно

Залишити коментар