Как диагностировать и устранить ошибки 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.sockNginx должен иметь права на чтение и запись для этого файла сокета. Пользователь 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. Как только вы узнаете, является ли сбой отказом в соединении, тайм-аутом, отказом в разрешении или преждевременным закрытием, исправление обычно заключается в вышестоящем сервисе, правах доступа к сокету, настройках тайм-аута или правиле брандмауэра.