Подробный гайд: Ошибка 502 Bad Gateway на веб-серверах
1. Что такое 502 Bad Gateway?
HTTP 502 означает, что сервер, выступающий в роли шлюза (Nginx, Apache, Cloudflare, AWS ALB и т.д.), получил от вышестоящего (upstream) сервера:
- некорректный HTTP-ответ,
- пустой ответ,
- ответ, нарушающий протокол,
- либо не смог установить соединение вовсе.
Важно:
- 502 ≠ 503 (Service Unavailable) и ≠ 504 (Gateway Timeout).
На практике их часто путают, но причина разная:
502→ upstream ответил, но ответ "битый" или соединение сброшено.504→ upstream не ответил в отведённый таймаут.503→ upstream явно отказался обслуживать запрос (maintenance, overload, circuit breaker).
2. Где возникает 502 в типовой архитектуре
Клиент → CDN/Балансировщик → Z-сеть (Nginx/Apache) → Backend (PHP-FPM/Node/Python/Java) → БД/Сервисы
↑
Здесь появляется 502
Ошибка всегда указывает на стык между Z-сетью и upstream. Клиентский код, браузер или БД редко являются прямой причиной.
3. Топ-7 причин появления 502
| № | Причина | Типичные симптомы |
|---|---|---|
| 1 | Backend упал или не запущен | connection refused, no live upstreams |
| 2 | Нехватка ресурсов/лимиты | OOM-kill, pm.max_children исчерпан, queue переполнен |
| 3 | Сетевые/файрвол-проблемы | iptables, ufw, security groups, DNS resolution failure |
| 4 | SSL/TLS mismatches | Z-сеть ожидает HTTPS, upstream отдаёт HTTP (или наоборот), просроченный сертификат |
| 5 | Контейнерная среда (Docker/K8s) | CrashLoopBackOff, failed readiness probe, network policy блокирует трафик |
4. Пошаговая диагностика
Шаг 1. Проверьте статус upstream-сервиса
# Systemd
systemctl status php8.3-fpm # или nodejs, gunicorn, tomcat и т.д.
journalctl -u php8.3-fpm --since "1 hour ago"
# Docker
docker ps -a
docker logs <container_id> --tail 100
# Kubernetes
kubectl get pods -l app=your-backend
kubectl describe pod <pod-name>
kubectl logs <pod-name> --tail 100
Ищите:
exited,killed,OOMKilled,CrashLoopBackOff,fatal error.
Шаг 2. Проверьте логи
# Nginx
tail -f /var/log/nginx/error.log | grep "502\|upstream\|connect\|reset"
# Apache
tail -f /var/log/apache2/error.log | grep "AH01114\|502"
Типичные записи:
upstream prematurely closed connectionno live upstreams while connecting to upstreamrecv() failed (104: Connection reset by peer)
Шаг 3. Проверьте соединяемость вручную
# Если upstream на порту
curl -v http://127.0.0.1:3000/health
telnet 127.0.0.1 3000
ss -tlnp | grep :3000
# Если upstream на Unix-socket
curl -v --unix-socket /var/run/php/php8.3-fpm.sock http://localhost/
ls -la /var/run/php/
Шаг 4. Проверьте ресурсы системы
htop # CPU/RAM
free -h # Swap
df -h # Диск (особенно /var/log, /tmp)
ulimit -a # Лимиты открытых файлов
dmesg -T | grep -i oom # OOM-killer
Шаг 5. Проверьте конфигурацию Z-сети
nginx -t && systemctl reload nginx
apachectl configtest && systemctl reload apache2
5. Решения по популярным стекам
Nginx + PHP-FPM
Проблема:
fastcgi_passуказывает на порт, а PHP-FPM слушает сокет (или наоборот).
Решение:
# В /etc/nginx/sites-available/your-site
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock; # или 127.0.0.1:9000
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
PHP-FPM пул: /etc/php/8.3/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 10
request_terminate_timeout = 60s
php_admin_value[memory_limit] = 256M
После изменений:
systemctl restart php8.3-fpm
Docker / Kubernetes
| Проблема | Диагностика | Решение |
|---|---|---|
CrashLoopBackOff |
kubectl describe pod |
Проверьте env vars, volumes, entrypoint |
Readiness probe failed |
kubectl get events |
Настройте корректный /health endpoint |
| Network policy blocks | kubectl exec -it <pod> -- curl upstream:port |
Разрешите трафик в NetworkPolicy |
| Resource limits too low | kubectl top pods |
Увеличьте resources.limits/requests |
6. Типовые ошибки конфигурации и как их избежать
| Ошибка | Последствие | Исправление |
|---|---|---|
worker_connections слишком мал |
no live upstreams под нагрузкой |
Увеличьте в events { worker_connections 1024; } |
7. Мониторинг и профилактика
1. Health checks
Настройте active или passive проверки upstream:
upstream backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001 backup;
health_check interval=10s fails=3 passes=2;
}
2. APM & Tracing
Prometheus + Grafana, Datadog, New Relic, OpenTelemetry. Отслеживайте:
- upstream_response_time
- nginx_upstream_fail
- Backend GC, heap, thread pool
3. Graceful reload/restart
- Nginx:
nginx -s reload - PHP-FPM:
systemctl reload php8.3-fpm - Node/Go: используйте
SIGUSR2или zero-downtime deploy (PM2, systemd socket activation)
4. Логирование с корреляцией
Добавляйте X-Request-ID во все слои. Упрощает поиск причины в распределённой системе.
8. Экспресс-чеклист быстрого восстановления
- [ ]
systemctl status <backend>→ запущен? - [ ]
tail /var/log/nginx/error.log→ естьupstream prematurely closed? - [ ]
curl http://127.0.0.1:<port>/health→ отвечает 200? - [ ]
htop / free -h→ нет OOM/CPU starvation? - [ ]
df -h→ диск не забит логами? - [ ] Конфиг валиден?
nginx -t/apachectl configtest - [ ] Последний деплой откатить?
docker image ls,kubectl rollout undo - [ ] Перезапустить Z-сеть + backend:
systemctl restart nginx php8.3-fpm
9. Нюансы для CDN/Cloudflare/Облачных балансировщиков
Если 502 отдаёт Cloudflare, AWS ALB, Yandex Cloud LB:
- Проверьте, что origin-сервер доступен извне (не заблокирован файрволом)
- Убедитесь, что порт и протокол в настройках CDN совпадают с реальным upstream
- Проверьте TLS handshake:
openssl s_client -connect yourdomain:443 -servername yourdomain - В Cloudflare: включите
Browser Integrity Checkoff временно для диагностики, проверьтеAlways Online - Для ALB: проверьте
Target Group health checksиderegistration delay
Заключение
502 Bad Gateway — это всегда симптом, а не корневая причина.
Алгоритм всегда один:
Логи → Логи upstream → Статус сервиса → Ресурсы → Сеть/Конфиг → Восстановление/Откат
При правильном логировании, мониторинге и грамотных таймаутах 95% инцидентов решаются за 3–5 минут. Если после прохождения гайда ошибка остаётся — проверьте, не является ли проблема на уровне приложения (deadlock, infinite loop, memory leak), который "обрушивает" upstream, заставляя Z-сеть видеть 502.