Ошибки 502 и 503 в HAProxy для пользователя выглядят похоже: сайт не открывается, API отвечает нестабильно, мониторинг краснеет. Но для администратора это разные сценарии. Упрощенно: 503 чаще означает, что балансировщику некуда отправить запрос, а 502 — что соединение с backend формально было, но что-то пошло не так уже в процессе обмена.
Отдельно пугает сообщение Layer4 connection problem. Оно почти всегда указывает не на HTTP-уровень, а на TCP: соединение не установилось, было сброшено, не прошло по таймауту или заблокировано между узлами. Поэтому лечить такую ошибку только правкой маршрутов или заголовков обычно бесполезно.
Ниже — практический runbook, который помогает быстро локализовать причину. Он подходит для схем, где HAProxy стоит перед Nginx, Apache, Gunicorn, uWSGI, Node.js или любым TCP-сервисом.
Сначала определяем тип сбоя: 502 или 503
Первое правило — не менять конфиг наугад. Сначала нужно понять, в какой точке цепочки происходит отказ.
Когда чаще встречается 503
503 обычно появляется, когда у frontend нет ни одного доступного сервера в backend. Типовые причины такие:
- все backend-серверы отмечены как
DOWNпо health checks; - приложение не поднялось после деплоя или рестарта;
- ошибка в IP-адресе, порте или DNS-имени backend;
- firewall или сетевые ACL режут доступ от HAProxy к приложению;
- сервис слушает только
127.0.0.1, а HAProxy идет на другой адрес; - тип проверки не соответствует протоколу сервиса.
Когда чаще встречается 502
502 обычно связан не с полным отсутствием живых узлов, а с ошибкой во время запроса к backend. Например:
- backend преждевременно закрыл соединение;
- ответ пришел битый или неполный;
- TLS до backend настроен неверно;
- приложение не уложилось в
timeout server; - TCP-соединение установилось, но HTTP-обмен сорвался.
Если клиенты видят 502, а в логах HAProxy одновременно есть признаки деградации backend, это часто плавающая проблема: часть соединений проходит, а часть отваливается на TCP или в начале ответа.
Смотрим, что HAProxy считает причиной
Главный источник правды — логи и статистика самого HAProxy. Без них очень легко лечить не причину, а последствия.
Начните с базовой проверки конфигурации и статуса процесса:
haproxy -c -f /etc/haproxy/haproxy.cfg
systemctl status haproxy
journalctl -u haproxy -n 100 --no-pager
Если конфиг валидный и процесс жив, переходите к логам запросов и событий health check:
journalctl -u haproxy -f
grep -i 'haproxy' /var/log/syslog | tail -n 100
grep -i 'Layer4 connection problem' /var/log/haproxy.log | tail -n 50
Ищите прежде всего такие признаки:
Layer4 connection problem,Connection refused,timeout,no server available;- какой backend и какой server уходит в
DOWN; - падает один узел или сразу вся группа;
- совпадает ли момент ошибки с релизом, рестартом приложения или сетевыми изменениями.
Подключаем статистический сокет
Если статистический сокет включен, диагностика заметно ускоряется. Через него видно состояние backend, счетчики ошибок и результаты проверок.
echo 'show stat' | socat stdio /run/haproxy/admin.sock
echo 'show info' | socat stdio /run/haproxy/admin.sock
echo 'show servers state' | socat stdio /run/haproxy/admin.sock
Когда backend массово уходит в DOWN, а причины похожи, проблема обычно общая: сеть, маршрут, firewall, DNS, неверный порт или единый сбой приложения после обновления.
Если балансировщик и backend разнесены по разным узлам, на отдельных VDS проще изолировать сетевые и ресурсные проблемы: быстрее понять, где именно теряются соединения и кто упирается в лимиты.
Что означает Layer4 connection problem на практике
Сообщение Layer4 connection problem относится к транспортному уровню. Это не «плохой HTTP», а ситуация, когда HAProxy не смог корректно установить или удержать TCP-соединение до backend.
Чаще всего за этим стоят:
Connection refused— на адресе и порту никто не слушает;timeout connect— соединение не установилось вовремя;- сброс соединения через RST;
- проблемы маршрутизации, ACL или firewall;
- ошибка TLS-рукопожатия при работе с HTTPS backend.
Проверяем доступность backend вручную
Проверка должна выполняться именно с того хоста, где работает HAProxy. Иначе вы проверяете другой сетевой путь и можете сделать неверный вывод.
ss -ltnp | grep ':8080'
nc -vz 127.0.0.1 8080
nc -vz 10.0.0.12 8080
curl -I http://10.0.0.12:8080/
curl -vk https://10.0.0.12:8443/
Если nc или curl с узла HAProxy не проходят, причина уже близко: backend не слушает порт, слушает не на том IP или недоступен по сети.
Проверяем, слушает ли приложение правильный адрес
Очень частая ошибка после миграции или деплоя — приложение слушает только локальный интерфейс.
ss -ltnp | grep 8080
Если видно только 127.0.0.1:8080, а HAProxy идет на 10.0.0.12:8080, health checks закономерно начнут падать. Аналогичная история часто бывает с контейнерами, когда сервис запущен, но порт опубликован не туда.

Health checks: полезны, но часто выбивают живые узлы
Проверки состояния в HAProxy спасают от отправки трафика на мертвый backend, но при неверной настройке сами становятся источником 503. Поэтому их надо проверять отдельно, а не считать заведомо правильными.
Перед изменением таймаутов или retries имеет смысл сначала убедиться, что логика проверок соответствует реальному поведению приложения.
TCP-check и HTTP-check
Если backend — обычный HTTP-сервер, обычно лучше проверять именно HTTP-ответ, а не только факт открытия TCP-порта.
backend app
option httpchk GET /health
http-check expect status 200
server app1 10.0.0.12:8080 check
server app2 10.0.0.13:8080 check
Такой вариант хорош, если endpoint /health быстрый и действительно отражает готовность приложения. Плохая практика — проверять тяжелую страницу, которая зависит от базы, кэша и внешних API.
Если backend — чистый TCP-сервис, используйте TCP-check и не пытайтесь проверять его как HTTP:
backend tcp_app
mode tcp
option tcp-check
server app1 10.0.0.12:3306 check
server app2 10.0.0.13:3306 check
Проверьте URI, Host и ожидаемый код ответа
Типовой сценарий: backend отвечает на /health только при корректном Host или возвращает 301, 302 либо 403, а HAProxy ждет строго 200.
backend app
option httpchk GET /health HTTP/1.1\r\nHost: app.internal
http-check expect status 200
server app1 10.0.0.12:8080 check
Если у вас маршрутизация завязана на виртуальные хосты, отсутствие правильного Host ломает проверку очень часто.
Не делайте health check слишком агрессивным
Слишком маленькие значения inter, fall и rise на проде вызывают флаппинг: сервер то UP, то DOWN. В результате краткая просадка превращается в лавину 503.
server app1 10.0.0.12:8080 check inter 3s fall 3 rise 2
server app2 10.0.0.13:8080 check inter 3s fall 3 rise 2
Если приложение иногда отвечает медленно, а check выполняется слишком часто и с коротким таймаутом, HAProxy будет выбрасывать узел из пула раньше, чем это реально нужно.
Если у вас уже используется HAProxy для более сложной логики трафика, полезно отдельно посмотреть и смежные механизмы, например stick tables и rate limiting в HAProxy, чтобы не спутать сетевую деградацию с последствиями ограничений на уровне балансировщика.
Таймауты: timeout connect, timeout server, timeout client
Неправильные таймауты — одна из самых частых и недооцененных причин нестабильной работы reverse proxy.
timeout connect
Этот параметр определяет, сколько HAProxy ждет установки соединения до backend. Если значение слишком маленькое, вы получите ложные Layer4 connection problem даже при кратковременных сетевых задержках.
defaults
timeout connect 5s
Для локальной сети 5 секунд обычно достаточно. Если backend находится на удаленном узле, в overlay-сети или за VPN, ориентируйтесь на реальную латентность и пики нагрузки.
timeout server
Это максимальное время ожидания ответа от backend после установления соединения. Если приложение долго обрабатывает отчет, тяжелый SQL-запрос или ждет внешнюю систему, слишком маленький timeout server даст 502 и обрывы ответа.
defaults
timeout server 30s
Но и бездумно увеличивать его нельзя: большой таймаут часто маскирует зависания приложения и увеличивает очередь соединений.
timeout client
Этот параметр задает, сколько HAProxy готов ждать клиента. Он не всегда напрямую связан с backend down, но влияет на общую картину, особенно при медленных клиентах, загрузках файлов и долгих соединениях.
defaults
timeout client 30s
Если timeout client слишком короткий, в логах будет много шума, и клиентские обрывы легко принять за ошибки backend.
Частая ошибка — увеличить только один таймаут. На практике нужно сверять лимиты по всей цепочке: HAProxy, frontend-сервер, приложение и иногда даже upstream-сервисы.
Проверяем backend глубже: процесс, ресурсы и лимиты
Если HAProxy сообщает о проблеме с backend, это не значит, что виноват именно он. Очень часто балансировщик просто первым замечает деградацию приложения.
Надежная схема диагностики здесь простая: сначала проверить, жив ли процесс, затем посмотреть логи, после этого оценить ресурсы и только потом менять таймауты или health checks.
systemctl status nginx
systemctl status apache2
systemctl status php8.2-fpm
systemctl status gunicorn
journalctl -u nginx -n 100 --no-pager
journalctl -u php8.2-fpm -n 100 --no-pager
Обычно ищем такие признаки:
- рестарты процессов;
- ошибки bind на порт;
- исчерпание воркеров;
- OOM killer;
- подвисание на старте после релиза;
- переполненные очереди подключения.
Если сервис формально жив, но отвечает медленно, проверьте CPU, память, iowait и число соединений:
uptime
free -m
vmstat 1 5
top -b -n 1 | head -n 20
ss -s
ss -tan state established '( sport = :8080 or dport = :8080 )'
На перегруженном backend health checks начинают сыпаться первыми. После этого HAProxy помечает сервер как DOWN, и пользователь уже видит 503 как следствие, а не как первопричину.
Если сервисы разнесены по разным ролям, держать HAProxy и backend на отдельных VDS обычно удобнее и для диагностики, и для предсказуемой производительности: проще увидеть, где именно упираетесь в CPU, память или сеть.
Firewall, маршрутизация и сетевые ACL
Если backend жив, порт слушает, а timeout connect и Connection refused продолжаются, почти всегда нужно идти в сетевой слой. Особенно после миграции, переезда в приватную подсеть или изменения правил безопасности.
nft list ruleset
iptables -S
ss -ltnp
ip addr
ip route
ping -c 2 10.0.0.12
traceroute 10.0.0.12
Типовые сценарии здесь такие:
- backend после обновления оказался в другой подсети;
- security group разрешает внешний трафик, но не соединения от HAProxy;
- локальный firewall на backend не пропускает внутренний порт;
- маршрут через VPN поднялся не полностью;
- локальные политики безопасности мешают сервису штатно принимать соединения.
Если сеть менялась недавно, полезно сравнить маршрут от HAProxy до backend и правила фильтрации по обе стороны соединения, а не только на одном узле.

TLS до backend: частая причина скрытых ошибок
Когда HAProxy проксирует трафик не на HTTP, а на HTTPS backend, добавляется еще один слой проблем: сертификат, SNI, версия TLS и проверка цепочки.
backend app_tls
server app1 10.0.0.12:8443 ssl verify none check
server app2 10.0.0.13:8443 ssl verify none check
Такой пример может подойти для диагностики, но на проде лучше явно понимать, нужен ли SNI, требуется ли проверка сертификата и какие параметры TLS поддерживает backend.
Проверить это с узла HAProxy можно так:
openssl s_client -connect 10.0.0.12:8443 -servername app.internal
Если рукопожатие зависит от имени хоста, проблема часто именно в SNI. А если до backend поднимается HTTPS с верификацией, стоит заранее привести в порядок и серверные SSL-сертификаты, чтобы не маскировать ошибки TLS параметром verify none.
Типовые ошибки конфигурации HAProxy
Неверный режим backend
Frontend работает в HTTP-режиме, а backend объявлен как TCP, либо наоборот. В результате логика маршрутизации и health checks не соответствует реальному протоколу.
Проверка не того порта
Приложение слушает 8080, а check идет на 8000. Или сервис уже переехал на Unix socket, а HAProxy продолжает стучаться по TCP.
DNS-имя backend обновилось, а HAProxy использует старый адрес
Если backend задается по имени, обязательно проверьте, как именно HAProxy резолвит адрес и когда перечитывает DNS. После смены записи можно долго ходить в устаревший IP.
Неподходящий endpoint для health check
Если endpoint зависит от базы, Redis, очередей и внешних API, то проверка измеряет не готовность веб-сервера, а состояние всей системы целиком. Иногда это нужно, но чаще приводит к ложным отключениям узлов.
Минимальный порядок диагностики, который экономит время
- Определить, ошибка больше похожа на
502или на503. - Посмотреть логи HAProxy и найти точную формулировку причины.
- Убедиться, что backend слушает нужный IP и порт.
- С узла HAProxy выполнить
ncиcurlк backend. - Проверить состояние health checks и флаппинг серверов.
- Сверить
timeout connect,timeout serverиtimeout clientмежду всеми звеньями. - Проверить firewall, маршруты и сетевые ACL.
- Если используется HTTPS до backend — отдельно проверить TLS и SNI.
- На backend посмотреть ресурсы, логи приложений и рестарты процессов.
Пример аккуратного базового конфига
Это не универсальный шаблон, а безопасная отправная точка для типового HTTP backend:
global
log /dev/log local0
stats socket /run/haproxy/admin.sock mode 660 level admin
defaults
mode http
log global
option httplog
timeout connect 5s
timeout client 30s
timeout server 30s
frontend fe_http
bind :80
default_backend be_app
backend be_app
option httpchk GET /health
http-check expect status 200
server app1 10.0.0.12:8080 check inter 3s fall 3 rise 2
server app2 10.0.0.13:8080 check inter 3s fall 3 rise 2
Если даже с такой базой backend регулярно уходит в DOWN, проблема почти всегда уже не в «магии HAProxy», а в сети, приложении, таймаутах или инфраструктуре вокруг него.
Если у вас смешанная среда с Kubernetes, ingress и отдельными reverse proxy, полезно также сверить поведение балансировщика с типовой схемой ingress в k3s и HAProxy: часть ошибок там проявляется похожим образом, хотя причина лежит выше по стеку.
Вывод
Ошибки 502, 503 и сообщение Layer4 connection problem редко лечатся одной случайной правкой конфига. Важно разделять уровни: доступность TCP, корректность health checks, согласованность таймаутов, состояние приложения и сетевой путь между узлами.
Рабочая схема простая: сначала порт и сеть, потом checks, потом таймауты, потом приложение. Если идти именно в таком порядке, причина находится заметно быстрее, а HAProxy из источника тревожных сообщений превращается в удобную точку наблюдения за всей цепочкой.


