504 не означает что Nginx сломан. Nginx работает — он просто устал ждать ответа от того кто стоит за ним. php-fpm, Apache, Node.js — один из них либо завис, либо думает слишком долго, либо перегружен настолько что вообще не успевает ответить. Чинить нужно именно бэкенд, а не Nginx.
Шаг 1: понять где именно обрывается
Прежде чем трогать конфиги — посмотреть с чем реально столкнулись.
На каких URL происходит 504 и как часто:
grep " 504 " /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20
Это не просто «есть 504» — это список самых проблемных эндпоинтов с количеством ошибок. Сразу видно: один тяжёлый скрипт или проблема везде.
Детали из error.log — там бывает точная причина:
tail -100 /var/log/nginx/error.log | grep "upstream timed out"
Шаг 2: проверить что бэкенд вообще жив
Статус php-fpm:
systemctl status php8.1-fpm
Если упал — поднять и смотреть логи:
sudo systemctl start php8.1-fpm
journalctl -u php8.1-fpm -n 50
Сколько процессов php-fpm сейчас работает:
ps aux | grep php-fpm | grep -v grep | wc -l
Сравнить с pm.max_children в конфиге пула — если цифры совпадают, все воркеры заняты и новые запросы висят в очереди. Это одна из самых частых причин массового 504.
Загрузка CPU и память — если сервер задыхается:
top -bn1 | head -20
free -h
Шаг 3: найти медленный скрипт
Если 504 периодический и непонятно на чём — включить slow-log в php-fpm. Он пишет трассировку стека для скриптов которые выполняются дольше порога.
Открыть конфиг пула:
sudo nano /etc/php/8.1/fpm/pool.d/www.conf
Добавить или раскомментировать:
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 3s
Перезапустить:
sudo systemctl restart php8.1-fpm
Читать лог в реальном времени:
tail -f /var/log/php-fpm/www-slow.log
В строках лога — функция и файл которые тормозят. Не URL, а конкретная строка кода.
Шаг 4: увеличить таймауты если скрипт работает долго намеренно
Импорт данных, генерация отчёта, конвертация видео — всё это может занимать больше 60 секунд. Nginx по умолчанию столько не ждёт.
Для php-fpm — добавить в блок location ~ \.php$:
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
Для обратного прокси на Apache или Node.js — добавить в блок server или location:
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;
Проверить синтаксис и применить:
sudo nginx -t && sudo systemctl reload nginx
Важно: таймаут нужно увеличить и в самом php-fpm, иначе он убьёт скрипт раньше чем Nginx успеет дождаться. В конфиге пула:
request_terminate_timeout = 300
И в php.ini:
max_execution_time = 300
Шаг 5: увеличить количество воркеров php-fpm
Если сервер справляется с нагрузкой но воркеров не хватает — новые запросы стоят в очереди. Открыть конфиг пула:
sudo nano /etc/php/8.1/fpm/pool.d/www.conf
Найти и скорректировать:
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_children — потолок. Каждый воркер потребляет RAM — перед увеличением проверить сколько памяти занимает один процесс php-fpm и сколько памяти доступно.
Шпаргалка
| Симптом | Что проверить | Решение |
|---|---|---|
| 504 на одном URL | slow-log, конкретный скрипт | Оптимизировать или увеличить таймаут |
| 504 везде | systemctl status php-fpm, воркеры |
Поднять упавший сервис или увеличить pm.max_children |
| 504 на долгих операциях | Таймаут 60с по умолчанию | fastcgi_read_timeout 300 + request_terminate_timeout = 300 |
| Nginx проксирует на Apache/Node.js | Таймаут прокси | proxy_read_timeout 300 |
| Сервер перегружен | top, free -h |
Оптимизация кода или апгрейд VPS |