Ошибка 502 в Nginx почти всегда указывает на сбой связи между Nginx и сервисом за ним: PHP-FPM, Node.js, Python-приложением, контейнером, Apache или другим upstream. Быстрое исправление начинается с логов, проверки backend-сервиса, сокета или порта, затем переходит к конфигурации, правам, ресурсам и таймаутам.

502 возникает на границе между Nginx и backend-сервисом
Код 502 Bad Gateway относится к классу серверных HTTP-ошибок. В спецификации HTTP он означает, что сервер в роли шлюза или прокси получил недействительный ответ от входящего сервера, к которому обратился для выполнения запроса. Для сайта на Nginx это обычно выглядит так: браузер отправляет запрос, Nginx принимает его, передаёт дальше в приложение, затем возвращает пользователю страницу с ошибкой, если корректный ответ от backend-сервиса получить не удалось.
В реальной инфраструктуре Nginx часто работает как reverse proxy. Он принимает внешний трафик, обслуживает статику, завершает TLS-соединение, направляет запросы в приложение и может балансировать нагрузку между несколькими backend-серверами. Официальная документация NGINX описывает передачу запросов через proxy_pass для HTTP-сервисов и через fastcgi_pass для FastCGI, включая PHP-FPM.
Упрощённая цепочка выглядит так:
Браузер → Nginx → PHP-FPM / Node.js / Python / Docker-контейнер / Apache → приложение → база данныхЕсли приложение падает, PHP-FPM слушает другой сокет, контейнер перезапускается, порт закрыт файрволом или backend отдаёт повреждённые заголовки, Nginx показывает 502. Сам Nginx в этот момент может работать исправно: проблема часто находится на следующем участке цепочки.
Первые минуты диагностики дают больше пользы, чем хаотичная правка конфига
Главная ошибка при 502 — сразу менять таймауты, буферы и случайные параметры. Такой подход маскирует причину и может создать новые сбои. Надёжнее идти от факта к гипотезе: сначала зафиксировать симптом, затем найти строку в логах, после этого проверять конкретный сервис.
Начните с проверки статуса Nginx:
sudo systemctl status nginx
sudo nginx -tКоманда nginx -t проверяет синтаксис конфигурации. Если в конфиге опечатка, неверный блок или сломанный include-файл, Nginx сообщит об этом до перезагрузки.
Дальше откройте error log:
sudo tail -n 100 /var/log/nginx/error.logДля конкретного сайта путь может быть другим:
sudo tail -n 100 /var/log/nginx/example.com.error.logAccess log помогает увидеть, какие URL дают 502 и с каких IP идут запросы:
sudo tail -n 100 /var/log/nginx/access.logМодуль логирования Nginx пишет логи запросов в заданном формате через access_log, а сообщения об ошибках помогают связать код ответа с upstream, сокетом, IP, портом и фазой обработки запроса.
Полезные фразы в error log:
| Фрагмент в логе | Вероятная причина | Первый шаг |
connect() failed (111: Connection refused) | Backend-сервис не слушает порт или упал | Проверить systemctl status, порт и контейнер |
No such file or directory рядом с .sock | Nginx смотрит на неверный Unix-сокет | Сверить fastcgi_pass и фактический сокет PHP-FPM |
Permission denied | Nginx не имеет доступа к сокету или файлу | Проверить владельца, группу и права |
upstream timed out | Backend отвечает слишком долго | Смотреть нагрузку, медленные запросы, БД, таймауты |
upstream sent too big header | Заголовки ответа превышают буфер | Проверить cookies, headers, буферы |
upstream prematurely closed connection | Backend закрыл соединение до полного ответа | Смотреть логи приложения и PHP-FPM |
PHP-FPM чаще всего ломает связку Nginx с PHP-сайтом
Для WordPress, Laravel, Symfony, Drupal, Bitrix и других PHP-проектов Nginx обычно передаёт PHP-запросы в PHP-FPM через Unix-сокет или TCP-порт. Официальная документация Nginx показывает, что fastcgi_pass может указывать на localhost:9000 или на Unix-сокет вида unix:/tmp/fastcgi.socket.
Сначала проверьте службу PHP-FPM:
sudo systemctl status php8.3-fpmВерсия может отличаться:
systemctl list-units --type=service | grep fpmЕсли служба остановлена, запустите её:
sudo systemctl restart php8.3-fpmПроверьте, какой сокет реально создан:
ls -lah /run/php/В конфигурации Nginx путь должен совпадать:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}Типичная причина 502 после обновления PHP — старый путь в fastcgi_pass. Например, на сервере уже работает php8.3-fpm.sock, а в конфиге остался php8.2-fpm.sock.
После изменения конфигурации выполните проверку и мягкую перезагрузку:
sudo nginx -t
sudo systemctl reload nginxЗатем проверьте логи PHP-FPM:
sudo journalctl -u php8.3-fpm -n 100 --no-pager
sudo tail -n 100 /var/log/php8.3-fpm.logНа разных дистрибутивах путь к логам отличается. Если отдельного файла нет, используйте journalctl.
Reverse proxy требует точного адреса upstream
Для Node.js, Python, Go, Java и микросервисов Nginx часто проксирует запросы через proxy_pass:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Если приложение слушает порт 3001, а Nginx отправляет запросы на 3000, появится 502. Если приложение слушает только внутри Docker-сети, а Nginx расположен на хосте, адрес 127.0.0.1 может указывать на сам Nginx, а не на контейнер.
Проверьте порт:
sudo ss -ltnp | grep -E ':3000|:8000|:8080'Проверьте локальный ответ backend-сервиса с сервера:
curl -I http://127.0.0.1:3000
curl http://127.0.0.1:3000/healthЕсли Nginx проксирует в upstream-группу, убедитесь, что все адреса доступны:
upstream app_backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
}
server {
location / {
proxy_pass http://app_backend;
}
}Документация NGINX указывает, что upstream-модуль может возвращать 502, когда сервер для обработки запроса выбрать нельзя в пределах заданного условия очереди или таймаута.
Docker и контейнеры добавляют сетевой слой к диагностике
В Docker-схеме 502 часто возникает из-за неправильного имени сервиса, закрытого порта, несовпадения сети или перезапуска контейнера. Проверка начинается с состояния контейнеров:
docker ps
docker compose psЛоги приложения:
docker logs --tail=100 app
docker compose logs --tail=100 appПроверка из контейнера Nginx:
docker compose exec nginx sh
curl -I http://app:3000Если Nginx находится в одном docker-compose.yml с приложением, в proxy_pass обычно используют имя сервиса:
location / {
proxy_pass http://app:3000;
}Если Nginx установлен на хосте, а приложение работает в контейнере, порт контейнера должен быть опубликован наружу:
services:
app:
ports:
- "3000:3000"После правки Docker-конфигурации проверьте доступ с хоста:
curl -I http://127.0.0.1:3000Права на сокет и владельцы процессов часто дают Permission denied
Unix-сокет PHP-FPM быстрее и удобнее TCP-порта на одном сервере, хотя требует корректных прав доступа. Если в error log есть Permission denied рядом с .sock, Nginx видит сокет, но не может им пользоваться.
Проверьте пользователя Nginx:
ps aux | grep nginxПроверьте настройки пула PHP-FPM:
sudo grep -E '^(user|group|listen|listen.owner|listen.group|listen.mode)' /etc/php/8.3/fpm/pool.d/www.confРабочий вариант для Ubuntu часто выглядит так:
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660После изменения пула:
sudo systemctl restart php8.3-fpm
sudo systemctl reload nginxЕсли Nginx работает от другого пользователя, например nginx, добавьте согласованные права через группу или измените настройки пула осознанно. Открывать сокет режимом 0777 ради быстрого запуска сайта опасно: такой режим расширяет доступ к backend-интерфейсу.
Таймауты помогают только после проверки медленного backend
Таймауты стоит менять, когда логи показывают upstream timed out, а приложение действительно выполняет долгую задачу: экспорт, генерацию отчёта, тяжёлый запрос к базе, обращение к внешнему API. Для FastCGI Nginx использует fastcgi_connect_timeout, fastcgi_send_timeout, fastcgi_read_timeout; документация указывает, что fastcgi_read_timeout задаёт интервал между двумя операциями чтения ответа, а значение по умолчанию равно 60 секундам.
Пример для PHP-FPM:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 120s;
fastcgi_read_timeout 120s;
}Для HTTP reverse proxy используются свои директивы:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_connect_timeout 60s;
proxy_send_timeout 120s;
proxy_read_timeout 120s;
}Увеличение таймаутов не лечит перегрузку приложения. Если PHP-воркеры заняты, база отвечает медленно, очередь задач выполняется в веб-запросе или внешний API зависает, пользователь всё равно будет ждать слишком долго. В такой ситуации лучше переносить тяжёлые операции в фоновые задачи, оптимизировать запросы к базе, включать кеширование и ограничивать параллельные тяжёлые операции.
Большие заголовки ответа приводят к upstream sent too big header
Ошибка upstream sent too big header while reading response header from upstream часто связана с крупными cookies, слишком большими заголовками авторизации, раздутыми session-cookie или большим количеством служебных заголовков. В PHP-проектах это может проявляться после установки плагина, изменения механизма авторизации или перехода на SSO.
Для FastCGI можно увеличить буферы:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_buffer_size 32k;
fastcgi_buffers 16 16k;
}Для reverse proxy:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_buffer_size 32k;
proxy_buffers 16 16k;
}Официальная документация Nginx описывает fastcgi_buffer_size, fastcgi_buffers, proxy_buffer_size и proxy_buffers как параметры чтения ответа от upstream-сервера; первая часть ответа обычно содержит заголовки.
Увеличивать буферы стоит аккуратно. Если cookie разрослась до десятков килобайт, полезно найти источник роста и уменьшить объём данных в заголовках.
Нагрузка на сервер превращает единичную ошибку в массовый сбой
502 может появляться короткими всплесками во время пикового трафика. В такой ситуации backend перестаёт обслуживать новые запросы, воркеры заняты, очередь подключений растёт, а Nginx начинает получать отказы соединения, пустые ответы или обрывы.
Проверьте ресурсы:
top
htop
free -m
df -h
iostat -xz 1Проверьте количество процессов PHP-FPM:
ps -ylC php-fpm8.3 --sort:rssПроверьте настройки пула:
sudo grep -E '^(pm|pm.max_children|pm.start_servers|pm.min_spare_servers|pm.max_spare_servers|pm.max_requests)' /etc/php/8.3/fpm/pool.d/www.confЕсли в логах PHP-FPM есть сообщения о достижении pm.max_children, пулу не хватает процессов для текущей нагрузки. Увеличение pm.max_children требует расчёта по памяти: один PHP-процесс может занимать десятки или сотни мегабайт в зависимости от приложения. При недостатке RAM сервер начнёт активно использовать swap, и 502 станет чаще.
Простой расчёт:
доступная RAM для PHP-FPM / средний размер одного PHP-процесса = безопасный pm.max_childrenНапример, если под PHP-FPM доступно около 2 ГБ, а один процесс занимает 100 МБ, безопасное значение будет около 20 процессов с запасом для Nginx, базы данных, Redis и системных служб.
Конфигурация Nginx должна проходить проверку перед каждым reload
После любой правки конфигурации используйте:
sudo nginx -tЗатем применяйте изменения:
sudo systemctl reload nginxДля аварийного перезапуска:
sudo systemctl restart nginxreload мягче, потому что Nginx перечитывает конфигурацию без полного ручного остановa сервиса. restart полезен при зависшем состоянии, смене модулей или нестандартной проблеме, но на боевом сервере его лучше применять осознанно.
Минимальный порядок безопасной правки:
- Скопируйте текущий конфиг.
- Измените только один логический блок.
- Запустите
nginx -t. - Примените
reload. - Проверьте страницу через
curl. - Посмотрите error log.
- Зафиксируйте результат.
sudo cp /etc/nginx/sites-available/example.com /etc/nginx/sites-available/example.com.bak.$(date +%F-%H%M)
sudo nginx -t
sudo systemctl reload nginx
curl -I https://example.comПрактический сценарий для Laravel, WordPress и других PHP-проектов
Для сайта на PHP используйте такой маршрут диагностики:
# 1. Проверить Nginx
sudo nginx -t
sudo systemctl status nginx
# 2. Проверить PHP-FPM
sudo systemctl status php8.3-fpm
systemctl list-units --type=service | grep fpm
# 3. Проверить сокет
ls -lah /run/php/
# 4. Найти fastcgi_pass
sudo grep -R "fastcgi_pass" /etc/nginx/sites-enabled /etc/nginx/conf.d
# 5. Сравнить путь сокета в Nginx с фактическим сокетом
# пример: unix:/run/php/php8.3-fpm.sock
# 6. Посмотреть логи
sudo tail -n 100 /var/log/nginx/error.log
sudo journalctl -u php8.3-fpm -n 100 --no-pager
# 7. Перезапустить PHP-FPM после исправления
sudo systemctl restart php8.3-fpm
sudo nginx -t
sudo systemctl reload nginxДля Laravel дополнительно проверьте права на каталоги:
sudo chown -R www-data:www-data storage bootstrap/cache
sudo find storage bootstrap/cache -type d -exec chmod 775 {} \;
sudo find storage bootstrap/cache -type f -exec chmod 664 {} \;Проверьте логи приложения:
tail -n 100 storage/logs/laravel.logЕсли ошибка появляется после деплоя, проверьте зависимости, .env, кеш конфигурации и миграции:
php artisan config:clear
php artisan cache:clear
php artisan route:clear
php artisan view:clear
php artisan migrate --forceДля WordPress проверьте PHP-ошибки, плагины, тему, лимиты памяти и недавние изменения. Временное отключение проблемного плагина через переименование его каталога может вернуть сайт к работе, если лог указывает на фатальную ошибку PHP.
Практический сценарий для Node.js, Python и API-сервисов
Для приложения за reverse proxy порядок такой:
# 1. Проверить Nginx
sudo nginx -t
sudo systemctl status nginx
# 2. Проверить приложение
sudo systemctl status app
sudo journalctl -u app -n 100 --no-pager
# 3. Проверить порт
sudo ss -ltnp | grep ':3000'
# 4. Проверить ответ приложения локально
curl -I http://127.0.0.1:3000
curl http://127.0.0.1:3000/health
# 5. Проверить конфиг Nginx
sudo grep -R "proxy_pass" /etc/nginx/sites-enabled /etc/nginx/conf.d
# 6. Применить исправления
sudo nginx -t
sudo systemctl reload nginxЕсли приложение запускается через systemd, полезно проверить рабочую директорию, переменные окружения и команду запуска:
sudo systemctl cat appДля Python-проектов с Gunicorn проверьте Unix-сокет или порт Gunicorn, число воркеров, права на сокет и ошибки импорта. Для Node.js проверьте NODE_ENV, порт, переменные окружения, менеджер процессов PM2 или systemd unit.
Отличие 502 от соседних ошибок помогает быстрее сузить поиск
Коды 500, 502, 503 и 504 часто путают. Разница помогает выбрать направление диагностики.
| Код | Смысл для администратора | Типичный участок поиска |
| 500 | Приложение вернуло внутреннюю ошибку | Логи приложения, PHP, framework |
| 502 | Nginx получил недействительный ответ от upstream или не смог корректно связаться с ним | Сокет, порт, backend, proxy/FastCGI |
| 503 | Сервис временно недоступен или перегружен | Maintenance, пул воркеров, лимиты |
| 504 | Gateway не дождался ответа за отведённое время | Долгие запросы, сеть, БД, внешние API |
MDN относит HTTP-статусы 500–599 к серверным ошибкам, а 502 описывает как ситуацию, в которой gateway или proxy получил недействительный ответ от upstream.
Для 502 главная зона поиска — связь между Nginx и backend. Для 504 акцент смещается на время ожидания. Для 500 чаще всего нужно смотреть само приложение.
Чек-лист восстановления сайта при 502
Используйте этот чек-лист как рабочий порядок на боевом сервере:
- Откройте страницу через
curl -I, чтобы подтвердить код ответа. - Посмотрите
error.logNginx за последние минуты. - Найдите точную фразу рядом с
upstream. - Проверьте статус backend-сервиса.
- Проверьте порт или Unix-сокет.
- Сравните
proxy_passилиfastcgi_passс фактическим адресом backend. - Проверьте права на сокет и каталоги проекта.
- Посмотрите логи приложения.
- Проверьте RAM, CPU, диск и число воркеров.
- Исправьте одну найденную причину.
- Запустите
nginx -t. - Примените
reload. - Повторно проверьте сайт и логи.
Команды для быстрой проверки:
curl -I https://example.com
sudo tail -n 100 /var/log/nginx/error.log
sudo systemctl status nginx
sudo nginx -t
sudo ss -ltnp
sudo journalctl -xe --no-pagerПрофилактика снижает риск повторного 502 после релиза и обновлений
Чтобы 502 не появлялась после каждого деплоя, обновления PHP или перезапуска контейнеров, настройте базовую профилактику:
- health-check endpoint в приложении, например
/health; - мониторинг Nginx, PHP-FPM, приложения и базы данных;
- алерты по количеству 5xx-ответов;
- отдельные error log для каждого сайта;
- проверку
nginx -tв деплой-скрипте; - автоматический restart backend-сервиса через systemd при падении;
- ограничение тяжёлых операций в веб-запросах;
- фоновые очереди для экспорта, рассылок и генерации отчётов;
- контроль свободной RAM и диска;
- документирование версии PHP, пути сокета и схемы Docker-сети.
Пример systemd-настройки для автоперезапуска приложения:
[Service]
Restart=always
RestartSec=5Для PHP-FPM полезно отдельно наблюдать за pm.max_children, медленными запросами, потреблением памяти и ошибками приложения. Для reverse proxy — за доступностью upstream-портов и временем ответа health-check.
Главный вывод для администратора
502 bad gateway nginx нужно разбирать как проблему связи Nginx с backend-сервисом. Самый быстрый путь к исправлению проходит через error log, проверку службы приложения, сокета или порта, затем через права, ресурсы и таймауты.
Если сайт уже лежит, начните с трёх команд:
sudo tail -n 100 /var/log/nginx/error.log
sudo systemctl status php8.3-fpm
sudo nginx -tДля Node.js, Python, Go или Docker замените проверку PHP-FPM на статус своего приложения, контейнера или upstream-порта. После нахождения точной строки в логе причина обычно становится понятной: сервис остановлен, сокет изменился, порт закрыт, backend перегружен, заголовки слишком большие или приложение падает на конкретном запросе.