Коли WordPress викидає 502 або 504, бізнес не бачить «проблему з upstream». Вони бачать «касa не працює», «реклама впала» або «пост CEO не публікується». Ви бачите інше: Nginx, що сидить поміж інтернетом і PHP-FPM, ніби вишибала, який іноді забуває список гостей.
Це польовий посібник по конкретних помилках конфігурації Nginx, які надійно генерують 5xx помилки в WordPress, як підтвердити їх за допомогою команд та що змінити, щоб тимчасовий інцидент не став повсякденною роботою.
Цікаві факти та контекст (чому це постійно трапляється)
- Nginx починався як відповідь на проблему C10k (обробка 10 000 одночасних з’єднань) і був побудований навколо подієвого вводу/виводу. WordPress, натомість, — це PHP-додаток з базою даних, який любить синхронну роботу. Поєднайте їх — отримаєте дуже ефективний вебсервер, що відкриває дуже неефективний шлях обробки запиту.
- «Bad Gateway» — це не моральна оцінка Nginx. Це констатація факту: Nginx запитав upstream (PHP-FPM) відповідь і не отримав придатної.
- Більшість 5xx інцидентів у WordPress самонавідувані: таймаути, стандартні буфери, невідповідність прав доступу та хибні припущення про масштабування PHP-FPM. Справжні баги існують, але повторювані проступки — це помилки конфігурації.
- PHP-FPM — це менеджер процесів, а не магія. Якщо ви дасте йому занадто мало воркерів, він ставить у чергу. Якщо занадто багато — він буде збирати пам’ять і вмирати. Обидва випадки можуть виглядати як «Nginx зламався».
- HTTP/2 не зменшив навантаження на сервер для динамічних сторінок; він зменшив накладні витрати з’єднань і покращив мультиплексування. Один клієнт тепер може відправляти багато запитів паралельно по одному з’єднанню, що змінює форму трафіку й може швидше виявити насичення FPM.
- WordPress admin-ajax.php — це маленький URL з великим радіусом ураження. Плагіни використовують його для всього, зокрема довготривалих задач. Якщо ви ставитесь до нього як до звичайного запиту сторінки, ви зіткнетеся з 504 на «випадкові» дії в адмінці.
- Заголовки стали більшими за роки. Роздування cookie через плагіни, A/B тестування та аналітику може спричинити «upstream sent too big header» і проявитися як 502/500 залежно від точного шляху помилки.
- Стандартні таймаути рідко узгоджені. Nginx має свої таймаути, PHP-FPM — таймаути запитів, а ваша база даних — очікування блокувань. Несинхронність породжує класичні «вмирає рівно через 60 секунд» загадки.
Одна перефразована ідея часто приписувана Werner Vogels (операції та надійність): Усе ламається; задача — проектувати під відмови і швидко відновлюватися.
Жарт №1: Єдина річ, що надійніша за неправильно налаштований Nginx upstream — це Slack-канал, що наповнюється «хтось ще бачить 502?» протягом 30 секунд.
Швидкий план діагностики (перші/другі/треті перевірки)
Коли сайт на WordPress починає видавати 5xx, не починайте з переписування всього серверного блоку. Проводьте триаж. Визначте, чи збій — це маршрутизація, здоров’я upstream, пропускна здатність чи політика (права/ліміти). Цей план — найкоротший шлях, який я знаю, до «виправити або ізолювати».
Перше: визначте який саме 5xx і де він генерується
- 502/504 зазвичай вказують на проблеми з upstream (PHP-FPM, мережа, сокет, таймаути).
- 500 може бути аварія upstream, фатальна помилка скрипта, цикл переписування або внутрішня помилка Nginx.
- 503 часто пов’язана з лімітуванням, режимом технічного обслуговування, upstream, позначеним як недоступний, або вичерпанням потужностей.
Друге: перевірте журнали помилок, які говорять правду
- Журнал помилок Nginx для помилок upstream, проблем з буферами, циклів переписування, проблем з правами.
- Журнал PHP-FPM для «server reached pm.max_children», повільних запитів, сегфолтів і вбитих воркерів.
- Журнал ядра / systemd для OOM kill, перезапусків, виснаження дескрипторів файлів.
Третє: вирішіть, чи це баг одиночного запиту, чи подія чергування/пропускної здатності
- Баг одиночного запиту: лише один URL падає; інші сторінки працюють; помилка повторюється миттєво. Думайте про переписування, права, фатал у скрипті, захист від обходу шляхів, специфічну поведінку плагіна.
- Черги/пропускна здатність: масові 504, повільні відповіді, зростаючий час підключення до upstream, FPM заповнений, DB повільна. Думайте про налаштування pm, таймаути та сплеск трафіку.
Четверте: оберіть безпечне пом’якшення
- Тимчасово підвищіть деталізацію логування (не назавжди).
- Обережно підніміть конкретні таймаути тільки там, де це відповідає реальності.
- Збільшіть/масштабуйте FPM, якщо доступна пам’ять.
- Відключіть конкретний шлях плагіна, що виконує 2-хвилинну роботу через HTTP.
Практичні завдання: команди, очікуваний вивід та рішення (12+)
Ось команди, які я реально виконую, коли дзвінок пейджера. Кожна включає, що означає вивід і яке рішення з нього випливає. Запускайте їх на хості з Nginx, якщо не зазначено інше.
Завдання 1: Підтвердити, що конфіг Nginx розібрано без помилок
cr0x@server:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Що це означає: Синтаксис валідний. Це не означає, що конфіг коректний, лише що його можна розпарсити.
Рішення: Якщо це падає — зупиніться. Виправте синтаксис, перш ніж шукати призракові 5xx, які насправді просто помилка при перезавантаженні.
Завдання 2: Перевірити, чи Nginx завантажив ваш останній конфіг
cr0x@server:~$ sudo systemctl status nginx --no-pager
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
Active: active (running) since Fri 2025-12-27 09:12:41 UTC; 3h 10min ago
Docs: man:nginx(8)
Main PID: 1327 (nginx)
Tasks: 2 (limit: 18962)
Memory: 8.9M
CGroup: /system.slice/nginx.service
├─1327 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
└─1330 nginx: worker process
Що це означає: Nginx працює. Командний рядок master може показати, чи використовується альтернативний шлях до конфігу.
Рішення: Якщо він не активний або в циклі перезапусків — спочатку це виправте. Якщо ви редагували файли, але не перезавантажили — ви дебагуєте вчорашній конфіг.
Завдання 3: Підтягнути журнал помилок Nginx і відтворити проблемний запит
cr0x@server:~$ sudo tail -n 50 /var/log/nginx/error.log
2025/12/27 12:18:07 [error] 1330#1330: *481 upstream prematurely closed connection while reading response header from upstream, client: 203.0.113.19, server: example.com, request: "GET /wp-admin/ HTTP/2.0", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "example.com"
2025/12/27 12:18:08 [error] 1330#1330: *482 connect() to unix:/run/php/php8.2-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 203.0.113.19, server: example.com, request: "GET /wp-login.php HTTP/2.0", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "example.com"
Що це означає: Дві різні корінні причини вже кричать: upstream закрив з’єднання (воркер FPM впав/таймаут) і проблема з правами сокета.
Рішення: Не гадати. Візьміть верхній повторюваний рядок помилок і виправляйте цей конкретний режим збоїв першим.
Завдання 4: Підтвердити, що PHP-FPM запущений і слухає там, де Nginx думає
cr0x@server:~$ sudo systemctl status php8.2-fpm --no-pager
● php8.2-fpm.service - The PHP 8.2 FastCGI Process Manager
Loaded: loaded (/lib/systemd/system/php8.2-fpm.service; enabled)
Active: active (running) since Fri 2025-12-27 09:11:02 UTC; 3h 12min ago
Docs: man:php-fpm8.2(8)
Process: 1051 ExecStartPost=/usr/lib/php/php-fpm-socket-helper install /run/php/php8.2-fpm.sock /etc/php/8.2/fpm/pool.d/www.conf 82 (code=exited, status=0/SUCCESS)
Main PID: 1018 (php-fpm8.2)
Tasks: 18 (limit: 18962)
Memory: 312.4M
CGroup: /system.slice/php8.2-fpm.service
├─1018 php-fpm: master process (/etc/php/8.2/fpm/php-fpm.conf)
├─1032 php-fpm: pool www
└─1033 php-fpm: pool www
Що це означає: Сервіс живий. Це ще не підтверджує, що Nginx може дістатися до сокета, лише що FPM не зник.
Рішення: Якщо неактивний або перезапускається — розбирайтеся чому (OOM, помилка конфігу). Якщо активний — перевірте шлях сокета і права наступним кроком.
Завдання 5: Перевірити права доступу до FastCGI сокета
cr0x@server:~$ ls -l /run/php/php8.2-fpm.sock
srw-rw---- 1 www-data www-data 0 Dec 27 09:11 /run/php/php8.2-fpm.sock
Що це означає: Лише root і учасники групи www-data можуть підключитись. Якщо воркери Nginx працюють як nginx, вони отримуватимуть permission denied.
Рішення: Або запускати Nginx як www-data (поширено на Debian/Ubuntu), або змінити власника/групу pool сокета в FPM щоб відповідати користувачу Nginx. Не робіть «chmod 777» і не заходьте в інцидент із безпеки.
Завдання 6: Підтвердити користувача воркерів Nginx і узгодити його з сокетом
cr0x@server:~$ grep -R "^\s*user\s" /etc/nginx/nginx.conf
user www-data;
Що це означає: Воркери Nginx працюють як www-data, тож вищезгаданий сокет має бути доступний.
Рішення: Якщо користувач Nginx відрізняється (наприклад, nginx), змініть або користувача Nginx, або власника сокета FPM; тримайте це консистентно на всіх хостах.
Завдання 7: Перевірити, чи PHP-FPM насичений (pm.max_children досягнуто)
cr0x@server:~$ sudo grep -R "pm.max_children" /etc/php/8.2/fpm/pool.d/www.conf
pm.max_children = 20
cr0x@server:~$ sudo tail -n 30 /var/log/php8.2-fpm.log
[27-Dec-2025 12:21:44] WARNING: [pool www] server reached pm.max_children setting (20), consider raising it
Що це означає: Запити чергуються в FPM. Nginx бачить повільних upstream і починає таймаутити або падати з’єднаннями.
Рішення: Або підніміть pm.max_children (якщо є запас пам’яті), або зменшіть вартість кожного запиту (кеш, БД), або масштабуйтесь горизонтально. Якщо піднімаєте бездумно, обміняєте 504 на OOM kill-и.
Завдання 8: Підтвердити точний HTTP-статус і часи з краю
cr0x@server:~$ curl -sS -o /dev/null -w "code=%{http_code} ttfb=%{time_starttransfer} total=%{time_total}\n" https://example.com/wp-admin/
code=504 ttfb=60.002 total=60.002
Що це означає: 60-секундна межа натякає на таймаут Nginx (часто fastcgi_read_timeout у деяких конфігах) або upstream, що стабільно застрягає.
Рішення: Якщо збій відбувається на круглу цифру, шукайте таймаути й черги. Якщо падає миттєво — шукайте права, відсутні сокети або миттєві PHP-фатали.
Завдання 9: Перевірити, чи маршрутизація WordPress (try_files) вірна
cr0x@server:~$ sudo nginx -T 2>/dev/null | sed -n '/server_name example.com/,/}/p' | sed -n '1,140p'
server {
server_name example.com;
root /var/www/example.com/public;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
}
Що це означає: Канонічний патерн присутній: якщо статичний ресурс існує — віддати його, інакше передати до index.php з аргументами запиту.
Рішення: Якщо ви бачите try_files $uri /index.php; без $args, очікуйте «випадкової» поведінки і збоїв плагінів. Якщо бачите рекурсію (маршрутизація до URI, що знову потрапляє в той самий location), очікуйте 500 через внутрішні цикли редіректів.
Завдання 10: Перевірити «upstream sent too big header» (роздування cookie)
cr0x@server:~$ sudo grep -R "too big header" -n /var/log/nginx/error.log | tail -n 5
/var/log/nginx/error.log:1928:2025/12/27 11:04:15 [error] 1330#1330: *211 upstream sent too big header while reading response header from upstream, client: 198.51.100.77, server: example.com, request: "GET /wp-admin/ HTTP/2.0", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "example.com"
Що це означає: Nginx не зміг вмістити заголовки від upstream у сконфігуровані буфери. Сторінки адмінки і плагіни — часті винуватці через великі cookies і редіректи.
Рішення: Збільшіть FastCGI буфери у конкретному server/location; також зменшіть роздування cookie, якщо можливо. Не піднімайте глобально без причини — це роздує споживання пам’яті під навантаженням.
Завдання 11: Знайти, чи ви втрачаєте завантаження (413), але користувачі скаржаться на «5xx»
cr0x@server:~$ sudo grep -R "client intended to send too large body" -n /var/log/nginx/error.log | tail -n 3
/var/log/nginx/error.log:2210:2025/12/27 10:31:19 [error] 1330#1330: *302 client intended to send too large body: 134217728 bytes, client: 203.0.113.58, server: example.com, request: "POST /wp-admin/async-upload.php HTTP/2.0", host: "example.com"
Що це означає: Це 413, а не 5xx, але в тікетній системі перетворюється на «завантаження не працює, сайт зламався».
Рішення: Встановіть client_max_body_size у розумне значення для вашого бізнесу та синхронізуйте з PHP-лімітами (upload_max_filesize, post_max_size).
Завдання 12: Виявити OOM kill-и, що виглядають як випадкові 502
cr0x@server:~$ sudo journalctl -k --since "2 hours ago" | grep -i -E "oom|killed process" | tail -n 10
Dec 27 11:58:22 server kernel: Out of memory: Killed process 1033 (php-fpm) total-vm:1324080kB, anon-rss:512000kB, file-rss:0kB, shmem-rss:0kB
Що це означає: Ядро вбило PHP-FPM воркер. Nginx повідомляє про premature close або 502. Відчуття нестабільності, бо це залежить від тиску пам’яті.
Рішення: Припиніть бездумне підвищення pm.max_children. Зменшіть кількість воркерів, виправте витоки пам’яті (плагіни), додайте RAM або ізолюйте навантаження. OOM — це сервер, який дипломатично каже «ні».
Завдання 13: Підтвердити ліміти дескрипторів файлів (тиха фабрика 5xx)
cr0x@server:~$ sudo cat /proc/$(pidof nginx | awk '{print $1}')/limits | grep "Max open files"
Max open files 1024 524288 files
Що це означає: Soft limit — 1024. Під сплесками keepalive + HTTP/2 + upstream сокетів це небагато.
Рішення: Підніміть soft limit через systemd override і Nginx worker_rlimit_nofile. Потім провалідуйте під навантаженням. Інакше будете полювати на «випадкові» upstream помилки тижнями.
Завдання 14: Перевірити помилки підключення до upstream (неправильний шлях сокета або не створений)
cr0x@server:~$ sudo grep -R "fastcgi_pass" -n /etc/nginx/sites-enabled | head
/etc/nginx/sites-enabled/example.com.conf:42: fastcgi_pass unix:/run/php/php8.2-fpm.sock;
cr0x@server:~$ test -S /run/php/php8.2-fpm.sock; echo $?
0
Що це означає: Код виходу 0 означає, що сокет існує і є сокет-файлом. Якщо повертає 1 — Nginx вказує на фантазійний шлях.
Рішення: Виправте шлях сокета або перейдіть на TCP (127.0.0.1:9000), якщо потрібно міжконтейнерне/просторове з’єднання. Але тримайте це консистентним і задокументованим.
Завдання 15: Визначити повільні PHP-запити і зіставити їх із таймаутами Nginx
cr0x@server:~$ sudo grep -R "request_slowlog_timeout" /etc/php/8.2/fpm/pool.d/www.conf
request_slowlog_timeout = 5s
cr0x@server:~$ sudo tail -n 20 /var/log/php8.2-fpm/www-slow.log
[27-Dec-2025 12:19:11] [pool www] pid 1099
script_filename = /var/www/example.com/public/wp-admin/admin-ajax.php
[0x00007f2b9c8a2e10] mysqli_query() /var/www/example.com/public/wp-includes/wp-db.php:2056
Що це означає: PHP витрачає час на DB-запити. Nginx чекає. Якщо таймаут Nginx коротший за час виконання повільного запиту — отримаєте 504.
Рішення: Виправте повільність (індекси БД, плагін), перш ніж розширювати таймаути. Великі таймаути без пропускної здатності — шлях до повільно прогресуючого інциндету замість швидкого відпаду.
Поширені помилки: симптом → корінна причина → виправлення
Це секція «я кровоточю; яка артерія?». Читайте симптом, перевіряйте журнали, застосовуйте цільове виправлення.
1) 502 Bad Gateway миттєво на PHP-сторінках
Симптоми: Статичні ресурси віддаються. Будь-який маршрут .php відразу падає. Журнал Nginx показує connect() ... failed (2: No such file or directory) або (13: Permission denied).
Корінна причина: Неправильний шлях у fastcgi_pass, відсутній сокет (FPM не запущений) або невідповідність прав між користувачем Nginx і pool FPM.
Виправлення: Узгодьте fastcgi_pass з реальним сокетом, переконайтесь що FPM активний, і встановіть директиви pool FPM як:
listen = /run/php/php8.2-fpm.sock,
listen.owner = www-data,
listen.group = www-data,
listen.mode = 0660.
Перезавантажте FPM і Nginx.
2) 504 Gateway Timeout на сталих часових межах (30s/60s/120s)
Симптоми: Сайт «працює, але іноді таймаутить», часто на круглій межі. Журнал Nginx показує upstream timed out.
Корінна причина: Несинхронізовані таймаути: Nginx fastcgi_read_timeout надто малий для реального часу запиту, або FPM/БД створюють чергу, через яку запит чекає.
Виправлення: Спочатку знайдіть, чому запити повільні (насичення FPM, блокування БД, плагін). Потім встановіть таймаути навмисно: таймаути Nginx мають бути трохи вищі за реалістичний максимум для інтерактивних запитів. Для довгих робіт — робіть їх асинхронно.
3) 500 Internal Server Error відразу після деплою/перезавантаження
Симптоми: Був спокій, потім reload, потім 500. Журнал Nginx згадує rewrite or internal redirection cycle або could not build the variables_hash або помилку include.
Корінна причина: Цикли переписування, зламана послідовність include, або неправильні regex locations, що ловлять більше ніж треба.
Виправлення: Використовуйте відомий робочий WordPress location-структур, тримайте переписування мінімальними і уникайте «хитрих» regex, що намагаються парсити WordPress. Nginx — чудовий маршрутизатор і поганий PHP-фреймворк.
4) 502/500 тільки в wp-admin, головна сторінка ок
Симптоми: Головна сторінка завантажується. Адмінка падає з помилками буфера/заголовків. Журнал показує upstream sent too big header.
Корінна причина: Великі заголовки від upstream (зазвичай cookie) від плагінів або флоу авторизації перевищують FastCGI буфери.
Виправлення: Збільшіть FastCGI буферизацію для цього server блоку, наприклад fastcgi_buffer_size та fastcgi_buffers. Також скоротіть роздування cookie (відключіть плагін, що записує роман у кукі).
5) 503 Service Unavailable під навантаженням, потім відновлюється
Симптоми: Сплески викликають 503, часто супроводжені логами про «limiting requests» або upstream failures. Іноді лише частина клієнтів отримує помилку.
Корінна причина: Надто агресивне rate limiting, обмеження з’єднань на IP (погано під NAT) або колапс upstream (FPM переповнений).
Виправлення: Тюнінг лімітування на основі реального трафіку. Не карайте всіх за одним NAT. Якщо upstream колапсує — спочатку вирішіть capacity і кешування; rate limiting має захищати, а не тримати вічно.
6) Випадкові 502 з “upstream prematurely closed connection”
Симптоми: Переривчасті збої, гірше під навантаженням. Логи Nginx показують premature closed connection while reading response headers.
Корінна причина: Воркер PHP-FPM падає, вбивається (OOM), досягає request_terminate_timeout або сегфолть через розширення.
Виправлення: Перевірте OOM логи ядра, логи FPM і PHP error log. Стабілізуйте пам’ять, обмежте кількість воркерів, видаліть підозрілі розширення і встановіть адекватні terminate таймаути, щоб швидко фіксувати і чистити помилки.
7) 500/502 після увімкнення «microcache» або fastcgi_cache
Симптоми: Залоговані користувачі бачать неправильні сторінки, адмін-дії падають, іноді 5xx через блокування кешу/стампедо, дивні заголовки.
Корінна причина: Кешування динамічного/автентифікованого контенту неправильно, кешуються відповіді, що треба обходити, або кешуються сторінки з помилками.
Виправлення: Кешуйте лише анонімний GET/HEAD, обходьте кеш для cookie wordpress_logged_in_ і адмін-шляхів, і не кешуйте 5xx. Microcache може бути чудовим; але це також пастка з гарним маркетингом.
8) 500 на конкретних URL із «Primary script unknown»
Симптоми: Деякі PHP маршрути падають; журнал або FPM лог згадує Primary script unknown.
Корінна причина: Неправильна мапа root/fastcgi_param SCRIPT_FILENAME, часто через копіпаст generic PHP-конфігу, що не відповідає вашій структурі директорій.
Виправлення: Використовуйте дистрибутивні FastCGI сниппети, коли можливо, і переконайтеся, що root вказує на WordPress document root. Підтвердіть фактичний шлях до index.php на файловій системі.
Детальні розбори: звичні винуватці в Nginx + WordPress
FastCGI: базові поняття, яким не варто нехтувати
Nginx не «запускає PHP». Він спілкується по FastCGI з PHP-FPM. Ця розмова має три повторювані режими відмови:
- Помилка підключення (сокет відсутній/неправильний/права) → миттєвий 502.
- Upstream помер під час відповіді (краш, OOM, terminate timeout) → 502 з «prematurely closed connection».
- Upstream занадто повільний (черги, повільна БД, довга робота) → 504.
Якщо ви трактуватимете їх як одне й те саме — будете робити одне й те саме виправлення по колу і дивуватися, чому графік не рухається.
Маршрутизація WordPress: одна try_files-стрічка, що має значення
WordPress хоче «приємні посилання» і очікує, що неіснуючі шляхи перенаправляться до index.php. Чистий підхід в Nginx — try_files, що перевіряє реальний файл, потім директорію, потім передає до /index.php?$args.
Помилки, що спричиняють 5xx, майже завжди бувають варіаціями:
- Втрата
$args, що ламає поведінку рядка запиту і може спричиняти дивну логіку плагінів, редіректи та (так) цикли за певних умов. - Неправильний root, так що
/index.phpне існує там, де Nginx думає. Nginx передає в PHP; PHP не може знайти файл; ви бачите 500/502 залежно від конфігу. - Regex locations, що перехоплюють забагато, особливо ті, що намагаються «захистити WordPress» блокуванням патернів. Чорні списки — місце, де добрі наміри перетворюються на відмови.
Таймаути: узгодьте ланцюжок, не просто підвищуйте числа
Тюнінг таймаутів — це те, за що SRE звинувачують у «занадто обережності», допоки сервер не почне повільно колапсувати.
Таймаути є в кількох місцях:
- Nginx:
client_header_timeout,client_body_timeout,send_timeout, плюс FastCGI таймаути:fastcgi_connect_timeout,fastcgi_send_timeout,fastcgi_read_timeout. - PHP-FPM:
request_terminate_timeoutі (опційно) max execution на PHP-рівні. - PHP:
max_execution_time(CLI відрізняється від FPM), ліміти пам’яті і таймаути на рівні розширень. - База даних: очікування блокувань і таймаути запитів (або їх відсутність).
Якщо Nginx відпустить через 60 секунд, а FPM буде тримати воркер зайнятим 180 секунд — ви створили витік ресурсів: запити продовжують виконуватись після того, як клієнту вже сказали «таймаут». Так починається спіраль: більше таймаутів → більше застряглих воркерів → більше таймаутів.
Робіть так:
- Задавайте бюджет часу для інтерактивних запитів (наприклад, адмін-сторінки мають бути швидкими; фонова робота — асинхронна).
- Переконайтесь, що таймаут Nginx трохи вищий за очікуваний максимум для цих інтерактивних endpoint-ів.
- Переконайтесь, що terminate timeout FPM трохи вищий за Nginx, щоб логувались повільні скрипти і їх можна було чистити.
- Перенесіть довгу роботу у черги/cron/CLI воркери. WordPress може це робити, але не «за бажанням».
Буфери: прихована причина, чому адмінка «випадково» вмирає
FastCGI буфери — це фактично «скільки заголовків/тіла відповіді Nginx тримає під час читання від upstream». Якщо вони замалі, Nginx не зможе прочитати заголовки і поверне 502.
Адмінські відповіді WordPress можуть рости в заголовках через:
- Великі cookies (декілька плагінів, що ставлять трекінгові або станні cookie).
- Багато
Set-Cookieзаголовків під час флоу авторизації. - Довгі ланцюги редіректів або плагіни безпеки, що додають заголовки.
Правильний підхід — цільовий тюнінг з доказами з логів. Збільшіть буфери у server block, що обслуговує WordPress, оцініть вплив на пам’ять, і — те, що всі пропускають — скоротіть cookie-роздування. Вам не потрібен cookie довжиною як коротка повість.
Права файлів і власність: нудна річ, що спричиняє реальні відмови
WordPress потребує доступу на читання до PHP-файлів і доступу на запис для upload-ів, кешів і іноді оновлень плагінів (залежно від процесу деплою). Найпоширеніша відмова — не «права неправильні», а «права змінились на одному хості під час екстреного ручного фікса».
Слідкуйте за:
- Користувач Nginx не може перейти по директоріях (відсутній біт виконання).
- FPM pool працює під іншим користувачем, ніж очікувалося, і не може читати код або писати uploads.
- Система деплою створює файли власником CI з обмежувальними режимами.
Виправляйте послідовною власністю і моделлю деплою, що не покладається на вебсервер як на інструмент змін коду. Якщо ваш production план включає «сайт сам себе оновлює» — ви прийняли хаос як фічу.
HTTP/2 і паралелізм: чому «кілька користувачів» можуть розтопити PHP-FPM
HTTP/2 дозволяє одному клієнту відкрити багато паралельних стрімів. Це чудово для швидкого завантаження сторінки. Але це також спосіб для однієї вкладки браузера (або бота) створити сплеск паралельних PHP-хітів: адмін панелі, API endpoint-и і ресурси, проксовані через PHP через неправильну конфігурацію.
Якщо ваш конфіг Nginx віддає занадто багато через PHP (наприклад, зображення через PHP або відсутній статичний кеш), HTTP/2 може прискорити біль. Виправлення — віддавати статичні файли як статичні, агресивно й правильно, і дозволити PHP обробляти тільки те, що потребує PHP.
Коли «жорстке підсилення безпеки» спричиняє 5xx
WordPress притягує сниппети хардінгу як метелики до світильника. Багато з них хороші. Деякі ламають uploads, REST endpoints або адмін-флоу, забороняючи методи або шляхи неправильно.
Типові патерни поломки:
- Блокування
POSTдо/wp-json/або/wp-admin/admin-ajax.phpчерез «AJAX страшний». Це може спливти як 500/503 залежно від того, як оброблена відмова і як додаток очікує відповідь. - Заборона доступу до
/wp-content/uploads/надто широкими правилами, що змушує плагіни падати і давати 5xx, коли вони не можуть отримати ресурси. - Спроба блоку виконання PHP в uploads, але випадкова блокада легітимних PHP-ендпоінтів через поганий regex.
Хардінг треба тестувати як код додатка. Проганяйте через staging. Додайте регресійні перевірки для адмін-дій. І тримайте правила читабельними, бо саме їх ви будете читати о 2-й ночі.
Жарт №2: Найшвидший спосіб дізнатися, що у вас немає staging — це деплоїти «сниппет безпеки» прямо в прод і назвати це відвагою.
Три корпоративні міні-історії з поля бою
Міні-історія 1: Інцидент, спричинений хибним припущенням
Середня компанія запускала WordPress за Nginx на двох нодах. Вони оновили PHP, і новий пакет використав інший шлях сокета PHP-FPM, ніж старий. У чеклісті деплою було «перезапустити сервіси», і всі це зробили. Хелсчек балансувальника були базові: вони хітали / і чекали HTTP 200.
На одній ноді Nginx конфіг сайту ще вказував на старий сокет. Статичний контент головної сторінки кешувався і віддавався, тож хелсчек залишився зеленим. Перший реальний користувач, що спробував увійти, отримав 502. Потім усі редактори отримали 502. Маркетинг помітив це, коли намагались опублікувати терміновий пост і бачили, як адмінка крутиться до зникнення.
On-call інженер спочатку подумав «оновлення PHP винне» і почав відкат. Але відкат не допоміг, бо перезапуск сервісів зберіг невідповідність шляху сокета і старий Nginx конфіг лишився. Це не була помилка софту; це було припущення, що «PHP-FPM завжди живе за одним шляхом».
Виправлення було болісно простим: вказати fastcgi_pass на правильний сокет, перезавантажити Nginx і додати хелсчек, що вправляє динамічний PHP маршрут (щось легке як /health.php). Також додали запобіжник: перевірку перед reload, що підтверджує існування сокета і можливість підключення від імені Nginx-користувача.
Що змінилось назавжди — не шлях сокета. Змінилась культура: вони перестали вважати «головна сторінка повертає 200» ознакою здоров’я PHP-додатка.
Міні-історія 2: Оптимізація, що повернулась бумерангом
Інша команда хотіла «прискорити WordPress» без покупки серверів. Вони увімкнули microcaching в Nginx і відчули себе героями. Анонімний трафік став швидшим. Графіки покращились. Хтось вставив скрін у квартальний слайд.
Потім почалось дивне. Залоговані користувачі іноді бачили чужі адмін-сторінки. Редактори скаржилися, що збереження чернетки інколи повертає 502. Саппорт отримав тікети «натиснув публікати і воно зникло». On-call інженер подивився логи і побачив мікс upstream таймаутів і поведінки, пов’язаної з блокуванням кешу під сплесками.
Корінна причина не в microcaching як такому; а в його занадто широкому застосуванні. Вони кешували відповіді, які ніколи не мали б кешуватись: адмін-сторінки, запити з auth cookie і деякі плагін-ендпоінти. Під навантаженням утворився cache stampede: багато запитів чекали на ту саму upstream-роботу, але через ключ кешу і умови обходу вони не кагрегувались.
Виправлення включало суворі правила обходу для всього з WordPress auth cookies, явне no-cache для адмінки і AJAX, і консервативне кешування лише анонімних GET/HEAD. Також додали правило «не кешувати 5xx», бо кешування помилки перетворює тимчасовий збій у тривалу відмову.
Урок не в тому, щоб ніколи не кешувати. Урок у тому, що кешування — це поведінка додатка. Трактуйте її як код, тестуйте як код і впроваджуйте поступово — ви за це відповідаєте.
Міні-історія 3: Нудна, але правильна практика, що врятувала день
Велике підприємство мало WordPress як один із багатьох сайтів на спільній Nginx платформі. Їх конфіги генерувались з шаблонів і комітилися в VCS. Кожна зміна вимагала тест конфігу і автоматизований смоук-тест, що хітив: головну, динамічний PHP endpoint, сторінку логіну і upload медіа з маленьким файлом.
Одного дня інженер запропонував «уніфікувати FastCGI includes по всім сайтам». Вони модифікували спільний сниппет для десятків хостів. Здавалося безпечно. Ні.
Сниппет змінив спосіб обчислення SCRIPT_FILENAME, що зламало підмножину сайтів з неоднорідними root шляхами.
Пайплайн зловив це. Смоук-тест впав на логін-руті з 500, а логи показали Primary script unknown. Нікому не довелось вчитися на цій помилці під час live-інциденту. Виправлення — оновити шаблон, щоб враховувати кожен root, і додати тест, що перевіряє очікувані резольвнуті шляхи для кожного vhost.
Це не була гламурна інженерія. Ніхто не відчув «дофаміну» від «ми запобігли відмові». Але це зекономило години простоя і багато внутрішньої довіри.
Мораль: нудні практики масштабуются краще за героїчний дебаг.
Контрольні списки / покроковий план (деплой без драм)
Крок за кроком: від 5xx алерту до стабільної служби
- Підтвердьте радіус ураження. Один URL чи всі PHP-маршрути? Тільки анонімні чи й адмін?
- Витягніть топ рядків помилок Nginx. Шукайте upstream connect failures, таймаути, помилки буферів/заголовків, цикли переписування.
- Перевірте здоров’я PHP-FPM. Статус сервісу, існування сокета, узгодження прав, попередження max_children.
- Перевірте OOM/перезапуски. Логи ядра і systemd часто розповідають реальну історію.
- Виміряйте запит. Використайте curl timing, щоб побачити, чи це миттєва відмова чи таймаут.
- Зробіть безпечне пом’якшення. Масштабуйте FPM в межах пам’яті, обходьте проблемний кеш, відключіть плагін-ендпоінт, що виконує довгу роботу, або тимчасово підвищіть таймаути з тикетом на корінну правку.
- Підтвердіть через динамічний health endpoint. Не оголошуйте перемогу по статичному контенті.
- Запишіть сигнатуру. «Якщо бачиш X в логах — це Y корінна причина.» Це зменшить MTTR більше, ніж будь-який тюнінг.
Контрольний конфіг: мінімальний життєздатний server block для WordPress
- Правильний root вказаний на WordPress document root.
- try_files містить
$args:try_files $uri $uri/ /index.php?$args; - PHP location містить правильний сниппет і правильний
fastcgi_pass. - Розумно забороняти доступ до чутливих файлів (
.htaccess, резервні wp-config), без regex-хаосу. - Статичне кешування для ассетів, що віддаються напряму Nginx, не через PHP.
- Розмір завантаження узгоджений з PHP-лімітами.
- Логування містить таймінги upstream хоча б під час інцидентів.
Операційний чекліст: запобігання повторним 5xx інцидентам
- Health checks має хітати PHP. Один динамічний endpoint може врятувати від «півзелених» пулів.
- Фіксуйте та відстежуйте шлях сокета PHP-FPM. Уникайте неявних дефолтів, що змінюються при оновленнях.
- Ограничте і моніторьте FPM. Встановлюйте
pm.max_childrenна основі замірів пам’яті, а не відчуттів. - Увімкніть slow logs. Якщо не знаєте, що повільно — ви будете «лікувати» таймаути вічно.
- Не дозволяйте production самонавчатись. Деплойте як дорослі: CI, артефакти, відкати.
- Перевіряйте перезавантаження Nginx.
nginx -t— не опція. Так само як і перевірка, що новий конфіг дійсно завантажено.
ЧаПи
1) Чому я отримую 502 замість 504?
502 зазвичай означає, що Nginx не зміг встановити або підтримати валідне upstream-з’єднання (сокет відсутній, permission denied, upstream закрився раніше). 504 означає, що Nginx підключився, але не отримав відповідь вчасно. Журнал помилок зазвичай робить це очевидним.
2) Коли використовувати Unix сокет або TCP для php-fpm?
На тому ж хості Unix сокет поширений та ефективний, з менше рухомих частин. Використовуйте TCP, коли потрібна міжконтейнерна або міжхостова підключеність, або коли середовище робить проблемними права сокетів. В обох випадках тримайте вибір консистентним і під моніторингом.
3) Я підняв fastcgi_read_timeout і 504 зникли. Чи все гаразд?
Можливо, ви просто обміняли «швидку відмову» на «довшу чергу». Якщо запити повільні через насичення FPM або БД, більші таймаути збільшать навантаження на конкурентність і погіршать пікові інциденти. Використовуйте slow logs і метрики черг, щоб підтвердити, що ви виправили причину, а не симптом.
4) Що спричиняє «upstream sent too big header» у WordPress?
Зазвичай роздування cookie: занадто багато cookie, занадто великі cookie або багато Set-Cookie заголовків. Адмінка WordPress плюс плагіни — ідеальний шторм. Виправлення: збільшити FastCGI буфери і скоротити зростання cookie, де можливо.
5) Чи можуть перезаписи Nginx спричиняти 500?
Так. Цикли переписування і внутрішні редірект-цикли можуть дати 500. WordPress зазвичай потребує простого try_files і мінімуму перезаписів. Якщо ви робите складну rewrite-логіку — швидше за все ви погано відтворюєте маршрутизацію WordPress.
6) Як зрозуміти, чи вузьке місце — PHP-FPM, чи база даних?
Почніть з FPM slow logs. Якщо стек-трейси вказують на виклики БД (наприклад, у wp-db.php), БД, ймовірно, є обмежувачем. Також дивіться на попередження max_children (черги) і корелюйте з метриками БД (lock waits, slow queries). 504 часто означає «хтось чекав на щось інше».
7) Чому падають лише wp-admin і wp-login.php, коли головна сторінка ок?
Адмін-сторінки генерують більші заголовки і залежать від cookie. Вони також більш динамічні, тож виявляють upstream-проблеми швидше. Якщо головна сторінка кешована або в основному статична, вона може приховувати проблеми upstream. Ось чому статичні хелсчекі — брехня.
8) Чи безпечно увімкнути fastcgi_cache для WordPress?
Може бути безпечно для анонімного трафіку, якщо ви обходите кеш для логованих cookie, адмін-шляхів, preview URL, кошиків/чекаутів і всього персоналізованого. Неправильне кешування ламає коректність перш за все, потім доступність. Тестуйте ретельно і впроваджуйте поступово.
9) Яка найпоширеніша «проста» причина 502 після технічних робіт?
Невідповідний шлях сокета після оновлення PHP або перезапуск сервісу, що створив сокет з іншими правами. Це соромно поширено і швидко діагностується перевіркою fastcgi_pass і ls -l на сокеті.
10) Чи потрібно тюнити Nginx worker_processes, worker_connections для проблем 5xx у WordPress?
Іноді, але рідко як перше виправлення. Відмови WordPress зазвичай пов’язані з upstream CPU/RAM/БД, а не зі зірваними воркерами Nginx. Проте якщо ви бачите ліміти дескрипторів файлів або обмеження з’єднань — виправляйте їх. Nginx зазвичай кур’єр, а не вбивця.
Висновок: наступні кроки, що запобігають повторенням
Якщо ви бачите 5xx на WordPress за Nginx, ваша задача — перестати трактувати це як містичний настрій веб-сервера. Режими відмови послідовні: підключення до сокета, пропускна здатність upstream, таймаути, буфери і маршрутизація. Журнали скажуть, який саме, якщо читати їх як оператор, а не ворожка.
Практичні наступні кроки:
- Додайте динамічний health endpoint і змусьте балансувальник його перевіряти.
- Уніфікуйте та перевіряйте шляхи сокетів і права під час деплоїв і апгрейдів.
- Увімкніть PHP-FPM slow logging і розглядайте «повільно» як баг надійності.
- Налаштуйте кількість воркерів FPM на підставі замірів пам’яті, і зупиніться, коли досягли безпечного запасу.
- Зробіть кешування явним і консервативним: лише анонімні GET/HEAD, якщо немає сильної причини інакше.
- Напишіть короткий runbook на основі завдань вище, щоб наступний інцидент був процедурою, а не дебатами.
Зробіть це — і ваш наступний 502 не буде загадкою. Це буде відомий клас проблем з коротким списком виправлень — і це те, як виглядає «надійність» в реальному світі.