Ошибка 502 Bad Gateway в Nginx + PHP-FPM: Полное руководство по диагностике и исправлению

Ошибка 502 Bad Gateway в Nginx + PHP-FPM: Полное руководство по диагностике и исправлению

Вы управляете сайтом на популярной связке Nginx и PHP-FPM, и вдруг пользователи начинают жаловаться на загадочную ошибку «502 Bad Gateway». Страницы не грузятся, вместо них — раздражающее сообщение об ошибке. Это не просто технический сбой — это сигнал о нарушении коммуникации между ключевыми компонентами вашего веб-сервера. Давайте разберемся, что скрывается за этой ошибкой, как ее диагностировать и, главное, как надежно исправить.

Что такое ошибка 502 Bad Gateway?

Ошибка 502 (Bad Gateway) — это код состояния HTTP, который означает, что один сервер, выступающий в роли шлюза или прокси, получил недопустимый ответ от вышестоящего сервера. В контексте связки Nginx + PHP-FPM, Nginx выступает в роли этого шлюза. Он принимает запросы от браузеров пользователей, но когда пытается передать запрос на обработку PHP-скриптов серверу PHP-FPM (FastCGI Process Manager), что-то идет не так, и Nginx получает ошибку или вообще не получает ответа.

Ключевая аналогия: Представьте, что Nginx — это секретарь на ресепшене, а PHP-FPM — это специалист в кабинете. Секретарь (Nginx) принимает вопросы посетителей (HTTP-запросы) и передает их специалисту (PHP-FPM). Если специалист не отвечает, заперт в кабинете или кричит что-то невнятное, секретарь не может дать внятный ответ посетителю и говорит: «Извините, не могу связаться со специалистом» (502 Bad Gateway).

Основные причины ошибки 502 в связке Nginx и PHP-FPM

Проблема почти всегда кроется в «обрыве связи» между Nginx и PHP-FPM. Вот главные виновники:

1. Проблемы с самим PHP-FPM

  • Служба PHP-FPM остановлена или не запущена: Самая банальная и частая причина.
  • Исчерпание ресурсов (детей-воркеров): В конфигурации PHP-FPM (обычно в файле www.conf) задано ограничение на количество одновременных процессов (pm.max_children). При высокой нагрузке все процессы могут быть заняты, и новым запросам просто не хватит «свободных рук».
  • Критические ошибки в PHP-скриптах: Скрипт может «падать», вызывая фатальную ошибку (Fatal Error) или превышая лимит времени/памяти до того, как отправит ответ.
  • Неправильные настройки сокета или порта: Nginx настроен на подключение к несуществующему сокету или порту.

2. Проблемы с таймаутами

  • request_terminate_timeout в PHP-FPM: Если выполнение скрипта превышает это значение, PHP-FPM принудительно завершает процесс.
  • fastcgi_read_timeout в Nginx: Время, которое Nginx ждет ответа от PHP-FPM. Если ответ не пришел за это время, Nginx возвращает 502.

3. Проблемы с правами доступа

Nginx (работающий от пользователя, например, www-data или nginx) должен иметь права на чтение/запись в Unix-сокет PHP-FPM (если используется сокет) или возможность подключиться к TCP-порту.

Пошаговая диагностика и решение

Шаг 1: Проверка статуса службы PHP-FPM

Первым делом убедитесь, что служба работает. В терминале выполните:

systemctl status php-fpm  # или php7.4-fpm, php8.1-fpm в зависимости от версии

Если служба неактивна, запустите ее: systemctl start php-fpm.

Шаг 2: Анализ логов — ваш главный инструмент

  1. Логи Nginx (ошибок): /var/log/nginx/error.log. Ищите строки с "upstream timed out" или "connect() failed".
  2. Логи PHP-FPM: Обычно /var/log/php-fpm.log или в системном журнале (journalctl -u php-fpm). Здесь могут быть сообщения о нехватке памяти, достижении max_children или фатальных ошибках в скриптах.

Совет: Сразу после появления ошибки 502 проверьте логи. Часто там содержится точное указание на причину, например, "recv() failed (104: Connection reset by peer)" что часто указывает на падение процесса PHP-FPM из-за ошибки в скрипте или нехватки памяти.

Шаг 3: Проверка и корректировка конфигурации

Сравните настройки в блоке location ~ \.php$ вашего конфига Nginx (например, /etc/nginx/sites-available/your-site) с фактическими параметрами PHP-FPM.

location ~ \.php$ {
    fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Или 127.0.0.1:9000
    fastcgi_read_timeout 60s; # Увеличьте при медленных запросах
    ... # остальные fastcgi_param
}

Убедитесь, что путь к сокету или адрес порта совпадают с настройками в конфиге PHP-FPM (/etc/php/8.1/fpm/pool.d/www.conf). Ищите параметры listen =.

Шаг 4: Оптимизация лимитов PHP-FPM

В файле www.conf обратите внимание на ключевые параметры пула:

  • pm.max_children: Рассчитывайте примерно: Общая доступная память / Средний размер памяти на процесс PHP.
  • pm.start_servers, pm.min_spare_servers, pm.max_spare_servers: Настройте под вашу нагрузку.
  • request_terminate_timeout и request_slowlog_timeout: Увеличьте для тяжелых операций.

После изменений перезагрузите конфигурацию: systemctl reload php-fpm и nginx -s reload.

Шаг 5: Проверка ресурсов сервера

Используйте top, htop или free -m. Возможно, серверу банально не хватает оперативной памяти или процессор загружен на 100%, что приводит к зависаниям.

Профилактика ошибок 502

  • Настройте мониторинг (например, с помощью UptimeRobot или самописных скриптов), который будет проверять доступность не только главной страницы, но и «тяжелого» PHP-эндпоинта.
  • Регулярно обновляйте PHP, Nginx и ваше приложение.
  • Используйте кэширование (OPcache для PHP, кэш страниц в Nginx) для снижения нагрузки на PHP-FPM.
  • Пишите оптимизированный код и настройте корректные лимиты выполнения для фоновых задач.

FAQ — Часто задаваемые вопросы

Ошибка 502 появляется только иногда, а не всегда. В чем дело?

Скорее всего, это проблема с лимитами процессов (pm.max_children) или таймаутами. Ошибка возникает в моменты пиковой нагрузки, когда все процессы PHP-FPM заняты, или когда какой-то конкретный скрипт выполняется дольше обычного. Проверьте логи в момент возникновения ошибки.

Я увеличил pm.max_children, но ошибка не исчезла. Что делать?

Увеличение max_children без контроля может привести к исчерпанию памяти. Проверьте, хватает ли серверу ОЗУ. Возможно, проблема в конкретном «сломанном» скрипте, который «роняет» воркер PHP-FPM. Внимательно изучите логи PHP-FPM на предмет фатальных ошибок (Fatal error).

В чем разница между использованием сокета (unix socket) и порта (127.0.0.1:9000)?

Unix-сокет часто работает немного быстрее, так как не использует сетевой стек. Однако при проблемах с правами доступа или в сложных виртуализированных средах иногда надежнее использовать TCP-порт (localhost). Если перешли с одного метода на другой, не забудьте поправить настройки в Nginx и PHP-FPM и перезапустить службы.

Ошибка 502 возникает после обновления PHP. Как исправить?

1. Убедитесь, что новая версия PHP-FPM запущена (имя службы могло измениться, например, php8.2-fpm).
2. Проверьте, что в конфиге Nginx в директиве fastcgi_pass указан корректный путь к сокету новой версии.
3. Проверьте совместимость вашего приложения с новой версией PHP.