Как диагностировать и устранить ошибки Nginx 502 Bad Gateway

Исправьте ошибки Nginx 502, проверив журналы ошибок, работоспособность вышестоящих серверов, права доступа к сокетам, настройки прокси, тайм-ауты и брандмауэры.

Как диагностировать и устранить ошибки Nginx 502 Bad Gateway

Nginx — это мощный и популярный веб-сервер и обратный прокси, часто используемый для обслуживания статического контента, балансировки трафика и перенаправления запросов к различным вышестоящим серверам приложений, таким как PHP-FPM, Node.js, Python Gunicorn или Apache Tomcat. Когда Nginx сталкивается с проблемой при общении с одним из этих вышестоящих серверов, он обычно отвечает ошибкой "502 Bad Gateway".

Начните с журнала ошибок Nginx, затем проверьте, работает ли вышестоящий процесс, доступен ли он и разрешено ли ему отвечать.

Понимание ошибки Nginx 502 Bad Gateway

Ошибка 502 Bad Gateway указывает на то, что Nginx, действуя как обратный прокси, получил неверный ответ от вышестоящего сервера. Это означает, что Nginx успешно подключился к вышестоящему серверу, но не получил ответа, получил неполный ответ или ответ, который не смог понять. Важно отметить, что проблема не в самом Nginx, а в сервисе, с которым Nginx пытается взаимодействовать.

Распространенные вышестоящие серверы включают:

  • PHP-FPM: Для PHP-приложений (например, WordPress, Laravel).
  • Gunicorn/uWSGI: Для Python-приложений (например, Django, Flask).
  • Node.js: Для JavaScript-приложений.
  • Apache Tomcat: Для Java-приложений.
  • Другие веб-серверы: Например, Apache HTTP Server для обслуживания определенного контента.

Ошибка 502 является важным индикатором того, что серверная часть вашего приложения работает неправильно или недоступна для Nginx.

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

Ключ к устранению ошибки 502 — систематическая диагностика. Начните с наиболее вероятных причин и постепенно исследуйте дальше.

1. Сначала проверьте журналы ошибок Nginx

Журналы ошибок Nginx являются основным источником информации. Они часто содержат конкретные детали о том, почему Nginx не смог связаться с вышестоящим сервером.

  • Расположение: Обычно находится в /var/log/nginx/error.log.
  • Команда: Используйте tail -f для мониторинга журналов в реальном времени при попытке воспроизвести ошибку.
tail -f /var/log/nginx/error.log

На что обратить внимание:

  • connect() failed (111: Connection refused): Указывает, что вышестоящий сервер не прослушивает указанный адрес/порт или брандмауэр блокирует соединение.
  • upstream timed out: Вышестоящий сервер слишком долго отвечал.
  • upstream prematurely closed connection: Вышестоящий сервер закрыл соединение до отправки полного ответа.
  • no live upstreams while connecting to upstream: Nginx не смог найти ни одного доступного вышестоящего сервера из настроенных.

2. Проверьте статус вышестоящего сервера

Получив подсказки из журналов ошибок Nginx, проверьте статус вашего вышестоящего сервера приложений.

  • Для PHP-FPM:

    sudo systemctl status php8.2-fpm
    
  • Для Node.js/Python/Других пользовательских приложений: Проверьте, запущен ли процесс.

    ps aux | grep node
    ps aux | grep gunicorn
    

    Если используется менеджер процессов, такой как PM2 (Node.js) или Supervisor (общий), проверьте его статус.

    pm2 status
    sudo supervisorctl status
    

Если сервис не запущен, попробуйте запустить его и проверьте его собственные журналы на наличие ошибок.

sudo systemctl start php8.2-fpm

3. Проверьте сетевое подключение к вышестоящему серверу

Убедитесь, что Nginx может достичь вышестоящего сервера на настроенном порту или пути к сокету.

  • Для TCP/IP-соединений (например, 127.0.0.1:8000): Используйте telnet или nc (netcat) для проверки подключения к порту с сервера Nginx.

    telnet 127.0.0.1 8000
    nc -vz 127.0.0.1 8000
    

    Успешное подключение должно показать Connected to 127.0.0.1. или succeeded!. Если оно зависает или показывает Connection refused, вышестоящий сервис не прослушивается или брандмауэр блокирует его.

  • Для Unix-сокетов (например, unix:/run/php/phpX.X-fpm.sock): Проверьте, существует ли файл сокета и имеет ли правильные права доступа.

    ls -l /run/php/phpX.X-fpm.sock
    

    Nginx должен иметь права на чтение и запись для этого файла сокета. Пользователь Nginx (например, www-data) должен быть частью группы, владеющей сокетом (например, www-data или php-fpm).

Распространенные причины и решения

Основываясь на ваших диагностических шагах, вот наиболее частые причины ошибок 502 и способы их устранения.

1. Вышестоящий сервер не запущен или аварийно завершил работу

Причина: Приложение, к которому Nginx пытается проксировать (например, PHP-FPM, Gunicorn, приложение Node.js), не запущено или аварийно завершило работу.

Решение: Запустите или перезапустите вышестоящий сервис.

# Пример для PHP-FPM
sudo systemctl start php8.2-fpm
# Если он уже запущен и вы подозреваете сбой, перезапустите его:
sudo systemctl restart php8.2-fpm

# Для пользовательских приложений используйте их конкретные команды запуска/перезапуска

Совет: Убедитесь, что ваши вышестоящие сервисы настроены на автоматический запуск при загрузке системы. Для сервисов systemd используйте systemctl enable phpX.X-fpm.

2. Перегрузка вышестоящего сервера / истощение ресурсов

Причина: Вышестоящий сервер перегружен, заканчивается память, процессор или достигаются лимиты процессов, что приводит к прекращению ответов или отказу в новых соединениях.

Симптомы: Журналы ошибок Nginx могут показывать connection refused или upstream timed out с перерывами, особенно под нагрузкой. Инструменты мониторинга системы (top, htop, free -h) показывают высокое использование ресурсов.

Решения:

  • Для PHP-FPM: Настройте параметры пула PHP-FPM в его конфигурационном файле (например, /etc/php/X.X/fpm/pool.d/www.conf).

    • pm.max_children: Максимальное количество дочерних процессов, которые могут быть активны одновременно.
    • pm.start_servers: Количество дочерних процессов, создаваемых при запуске.
    • pm.min_spare_servers, pm.max_spare_servers: Контролируют количество простаивающих дочерних процессов.
    ; Пример для динамического управления процессами
    pm = dynamic
    pm.max_children = 50
    pm.start_servers = 10
    pm.min_spare_servers = 5
    pm.max_spare_servers = 20
    
    • Увеличьте memory_limit в php.ini, если скрипты исчерпывают память.
  • Для других приложений: Увеличьте количество рабочих процессов, потоков или выделите больше памяти, если это возможно. Отслеживайте конкретные метрики вашего приложения.

  • Тайм-ауты Nginx: Увеличьте директивы proxy_connect_timeout, proxy_send_timeout и proxy_read_timeout в вашей конфигурации Nginx, но понимайте, что это лишь откладывает ошибку, если серверная часть действительно испытывает трудности.

    http {
        ...
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        ...
    }
    

3. Неправильная конфигурация вышестоящего сервера в Nginx

Причина: Nginx настроен на подключение к неправильному IP-адресу, порту или пути Unix-сокета для вышестоящего сервера.

Симптомы: Журналы ошибок Nginx показывают connect() failed (111: Connection refused) сразу после запроса.

Решение: Внимательно проверьте конфигурацию блока сервера Nginx (/etc/nginx/sites-available/your_site.conf).

  • Для HTTP/HTTPS вышестоящих серверов:

    location /app {
        proxy_pass http://127.0.0.1:8000; # Убедитесь, что IP и порт правильные
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
  • Для PHP-FPM через Unix-сокет:

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/phpX.X-fpm.sock; # Проверьте, что этот путь точно соответствует конфигурации PHP-FPM
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    
  • Для PHP-FPM через TCP/IP:

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000; # Проверьте IP и порт
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    

После внесения изменений всегда проверяйте конфигурацию Nginx и перезагружайте/перезапускайте Nginx:

nginx -t
systemctl reload nginx # Или перезапустите, если -t указывает на необходимость

4. Превышение request_terminate_timeout в PHP-FPM

Причина: PHP-скрипт выполняется дольше, чем установлено в request_terminate_timeout в PHP-FPM. Nginx ждет ответа, но PHP-FPM завершает скрипт, в результате чего Nginx получает неполный ответ.

Симптомы: Журналы ошибок Nginx могут показывать upstream timed out или script timed out. Журналы PHP-FPM могут показывать child XX exited on signal 9 (SIGKILL).

Решение:

  • Увеличьте request_terminate_timeout: В конфигурации пула PHP-FPM (www.conf) найдите и настройте эту директиву. Установка значения 0 отключает тайм-аут, но это обычно не рекомендуется, так как долго выполняющиеся скрипты могут зависать ресурсы.

    request_terminate_timeout = 300 # Увеличьте до 5 минут (300 секунд)
    
  • Увеличьте fastcgi_read_timeout в Nginx: Этот тайм-аут Nginx должен быть равен или больше request_terminate_timeout.

    location ~ \.php$ {
        ...
        fastcgi_read_timeout 300s; # Должен быть >= request_terminate_timeout в PHP-FPM
        ...
    }
    

Предупреждение: Хотя увеличение тайм-аутов может устранить ошибку 502, это может маскировать основные проблемы с производительностью. Лучшим долгосрочным решением является оптимизация медленного PHP-скрипта.

5. Проблемы с брандмауэром

Причина: Брандмауэр (на сервере Nginx или на вышестоящем сервере, если они разделены) блокирует соединения к порту или сокету вышестоящего сервера.

Решение:

  • Проверьте статус брандмауэра:

    sudo ufw status # Для UFW (Ubuntu/Debian)
    sudo firewall-cmd --list-all # Для firewalld (CentOS/RHEL)
    sudo iptables -L # Для iptables
    
  • Откройте необходимые порты: Убедитесь, что порт, который Nginx использует для подключения к вышестоящему серверу (например, 9000 для PHP-FPM через TCP/IP), открыт.

    sudo ufw allow from 127.0.0.1 to any port 9000 # Разрешить localhost подключаться к 9000
    sudo firewall-cmd --permanent --add-port=9000/tcp # Для firewalld
    sudo firewall-cmd --reload
    
  • Временно отключите брандмауэр для целей тестирования только в контролируемой среде, затем снова включите и настройте его правильно.

6. Вмешательство SELinux или AppArmor

Причина: Улучшения безопасности, такие как SELinux (на RHEL/CentOS) или AppArmor (на Ubuntu/Debian), могут препятствовать доступу Nginx к вышестоящему сокету или сетевым соединениям, даже если права доступа к файлам и брандмауэры настроены правильно.

Симптомы: Журналы могут показывать permission denied или подобные сообщения, особенно в /var/log/audit/audit.log (для SELinux).

Решение:

  • Проверьте audit.log:

    sudo grep nginx /var/log/audit/audit.log
    
  • Временно установите SELinux в разрешающий режим: sudo setenforce 0. Если ошибка исчезнет, виновник — SELinux. Затем вам нужно будет сгенерировать и применить соответствующие политики SELinux (например, audit2allow). Не забудьте вернуть его обратно в принудительный режим (sudo setenforce 1).

  • Проверьте статус AppArmor: sudo aa-status. Если AppArmor активен, вам может потребоваться изменить профиль Nginx.

7. Большие тела запросов/ответов (буферизация прокси)

Причина: Настройки буферизации прокси по умолчанию в Nginx могут быть слишком малы для очень больших тел запросов или ответов, что приводит к преждевременному закрытию соединения.

Симптомы: Журналы ошибок Nginx могут показывать upstream prematurely closed connection while reading response header from upstream или upstream prematurely closed connection while reading response body from upstream.

Решение: Настройте директивы буферизации прокси Nginx в вашем блоке http, server или location.

http {
    ...
    proxy_buffer_size   128k; # Размер буфера для первой части ответа
    proxy_buffers   4 256k; # Количество и размер буферов для остальной части ответа
    proxy_busy_buffers_size   256k; # Максимальный размер занятых буферов
    proxy_temp_file_write_size 256k; # Размер для записи во временные файлы, если буферизация переполняется
    ...
}

Примечание: Эти настройки потребляют больше памяти. Настраивайте их осторожно, исходя из ресурсов вашего сервера и типичного размера ответов вашего приложения.

Общие советы по устранению неполадок

  • Просмотрите все соответствующие журналы: Помимо журналов ошибок Nginx, также проверьте журналы доступа Nginx, журналы вышестоящих приложений (PHP-FPM, Gunicorn, журналы приложений Node.js) и системные журналы (/var/log/syslog, dmesg).
  • Перезапустите Nginx: После любых изменений конфигурации всегда перезапускайте Nginx, чтобы они вступили в силу: systemctl restart nginx.
  • Проверьте конфигурацию Nginx: Перед перезапуском проверьте синтаксис конфигурации Nginx: nginx -t.
  • Изолируйте проблему: Попробуйте обойти Nginx и получить доступ к вышестоящему приложению напрямую. Например, если ваше приложение Node.js находится на localhost:3000, используйте curl http://localhost:3000 из командной строки сервера. Если это также не удается, проблема определенно в вашем приложении, а не в Nginx.
  • Проверьте дисковое пространство: Полный диск может помешать приложениям записывать временные файлы или журналы, что приводит к сбоям или отказам. Используйте df -h, чтобы проверить использование диска.

Вывод

Начните с /var/log/nginx/error.log, затем проверьте, работает ли вышестоящий сервер и доступен ли он с хоста Nginx. Как только вы узнаете, является ли сбой отказом в соединении, тайм-аутом, отказом в разрешении или преждевременным закрытием, исправление обычно заключается в вышестоящем сервисе, правах доступа к сокету, настройках тайм-аута или правиле брандмауэра.