Reverse proxy и балансировка нагрузки: Traefik, Nginx или HAProxy
Чем отличаются три главных обратных прокси на Linux, как каждый балансирует трафик и проверяет бэкенды и что выбрать под ваш стек.

Коротко: Nginx — универсальный выбор по умолчанию: прокси, статика, TLS и кэш в одном процессе. HAProxy — специализированный балансировщик с лучшими проверками бэкендов, метриками и TCP-режимом. Traefik — прокси для Docker и Kubernetes, который сам находит сервисы по меткам и сам выпускает сертификаты. Брать стоит тот, который совпадает с тем, как у вас выкатываются сервисы.
Обратный прокси — это первая программа, которую видит каждый запрос к вашему сервису: она принимает соединение, снимает TLS, решает, какому бэкенду отдать запрос, и следит, чтобы мёртвый экземпляр не получал трафик. Ошибка в этом слое бьёт сразу по всем пользователям, поэтому выбирать его лучше осознанно, а не «потому что так было в туториале». Особенно это касается API, на которые завязаны клиенты: если вы заказываете разработку мобильного приложения с собственным бэкендом, спросите подрядчика заранее, что будет стоять перед API, как он переживёт пик push-рассылки и как приложение поведёт себя, пока один из серверов перезапускается.
Ниже — без бенчмарк-маркетинга: чем три инструмента реально отличаются, рабочие конфиги для одной и той же задачи и места, где на практике чаще всего ломается.
Что такое reverse proxy и зачем он нужен?
Прямой прокси работает от имени клиента (браузер ходит в интернет через него). Обратный — от имени сервера: клиенты видят один адрес, а за ним может быть сколько угодно экземпляров приложения. Типичные задачи обратного прокси:
- Терминация TLS. Сертификаты и шифрование — в одном месте, приложение слушает обычный HTTP во внутренней сети.
- Балансировка нагрузки. Запросы распределяются между несколькими бэкендами по выбранному алгоритму.
- Проверки здоровья. Упавший бэкенд исключается из ротации, восстановившийся — возвращается.
- Маршрутизация.
/api— в один сервис,/admin— в другой,static.example.org— в третий. - Защита и ограничения. Rate limiting, ограничение размера тела запроса, заголовки безопасности, скрытие внутренней топологии.
- Обновления без простоя. Экземпляры выводятся из ротации по одному, пока на них выкатывается новая версия.
Nginx: универсал по умолчанию
Nginx умеет быть веб-сервером, обратным прокси, кэшем и TCP/UDP-балансировщиком (модуль stream). Если вы уже отдаёте им статику, добавить проксирование на приложение — пара блоков в конфиге. Подробнее о том, чем он отличается от Apache, — в нашем разборе Nginx vs Apache в 2026.
Алгоритмы балансировки в открытой версии: round-robin по умолчанию (с весами weight), least_conn, ip_hash и hash по произвольному ключу. Проверки здоровья в открытой версии только пассивные: если запросы к бэкенду падают max_fails раз за fail_timeout, он временно исключается. Активные проверки (Nginx сам периодически опрашивает /healthz) есть в коммерческой NGINX Plus (документация модуля upstream).
# /etc/nginx/conf.d/app.conf
upstream app_backend {
least_conn;
server 10.0.0.11:8080 max_fails=3 fail_timeout=10s;
server 10.0.0.12:8080 max_fails=3 fail_timeout=10s;
keepalive 32; # постоянные соединения к бэкендам
}
server {
listen 443 ssl;
http2 on;
server_name api.example.org;
ssl_certificate /etc/letsencrypt/live/api.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.org/privkey.pem;
location / {
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_next_upstream error timeout http_502 http_503;
}
}
Сильные стороны: огромная база знаний, пакет в любом дистрибутиве, статика и кэш «бесплатно», предсказуемое потребление памяти. Слабые: конфигурация статическая — добавили бэкенд, нужно править файл и делать nginx -s reload; сертификаты Let's Encrypt — через внешний certbot; метрики в открытой версии скромные (stub_status).
HAProxy: балансировщик, для которого это основная работа
HAProxy не отдаёт статику и не кэширует страницы — он делает одно, но очень хорошо: принимает соединения и распределяет их. Работает в режиме http (видит заголовки, пути, куки) и tcp (проксирует любые протоколы: PostgreSQL, Redis, SMTP, MQTT). Именно HAProxy придумал PROXY protocol, который сейчас понимают почти все прокси и многие приложения.
Алгоритмы: roundrobin, leastconn, source, uri, hdr, random и другие. Активные проверки здоровья есть в открытой версии: HAProxy сам опрашивает каждый сервер и может проверять код ответа и тело. Плюс встроенная страница статистики, экспорт метрик в Prometheus и Runtime API, через который бэкенд можно вывести из ротации без перезагрузки (документация HAProxy).
# /etc/haproxy/haproxy.cfg (фрагмент)
frontend fe_https
bind :443 ssl crt /etc/haproxy/certs/api.example.org.pem alpn h2,http/1.1
mode http
option forwardfor
http-request set-header X-Forwarded-Proto https
default_backend be_app
backend be_app
mode http
balance leastconn
option httpchk
http-check send meth GET uri /healthz
http-check expect status 200
server app1 10.0.0.11:8080 check inter 3s fall 3 rise 2
server app2 10.0.0.12:8080 check inter 3s fall 3 rise 2
frontend stats
bind 127.0.0.1:8404
mode http
stats enable
stats uri /stats
http-request use-service prometheus-exporter if { path /metrics }
Обратите внимание: HAProxy ждёт сертификат и ключ в одном PEM-файле — это частая причина «не стартует после выпуска сертификата». Вывести сервер из ротации на время деплоя: echo "set server be_app/app1 state drain" | socat stdio /run/haproxy/admin.sock (сокет должен быть объявлен в секции global с level admin).
Сильные стороны: лучшие проверки здоровья и наблюдаемость из трёх, TCP-режим, минимальная задержка и расход CPU на запрос, управление на лету. Слабые: нет статики и автоматического Let's Encrypt, синтаксис нужно учить, автообнаружение сервисов — через DNS или внешние инструменты.
Traefik: прокси, который читает Docker и Kubernetes
Traefik написан на Go и спроектирован под динамическую инфраструктуру. Вместо списка бэкендов в конфиге он подключается к провайдерам — Docker, Kubernetes, Consul, файлам — и сам строит маршруты по меткам контейнеров или объектам Ingress. Запустили новый контейнер с нужными labels — через секунду на него идёт трафик, без reload. Встроенный ACME-клиент выпускает и продлевает сертификаты Let's Encrypt (документация Traefik). В k3s Traefik стоит ингресс-контроллером по умолчанию — подробнее о k3s в статье Kubernetes для небольших команд.
# docker-compose.yml: Traefik + два экземпляра приложения
services:
traefik:
image: traefik:v3.1
command:
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.websecure.address=:443
- --certificatesresolvers.le.acme.tlschallenge=true
- --certificatesresolvers.le.acme.email=admin@example.org
- --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
ports: ["443:443"]
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
app:
image: registry.example.org/team/app:1.4.2
deploy:
replicas: 2
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=Host(`api.example.org`)
- traefik.http.routers.app.entrypoints=websecure
- traefik.http.routers.app.tls.certresolver=le
- traefik.http.services.app.loadbalancer.server.port=8080
- traefik.http.services.app.loadbalancer.healthcheck.path=/healthz
- traefik.http.services.app.loadbalancer.healthcheck.interval=5s
Два экземпляра app Traefik найдёт сам и будет распределять запросы между ними по round-robin (с весами есть и взвешенный вариант). Сессионная привязка включается меткой loadbalancer.sticky.cookie=true.
Сильные стороны: нулевая ручная работа при добавлении сервисов, автоматический HTTPS, middleware (rate limit, basic auth, редиректы, заголовки) прямо в метках, дашборд. Слабые: доступ к Docker-сокету — фактически root на хосте (используйте :ro и socket-proxy), меньше пропускная способность на ядро, чем у HAProxy и Nginx, на обычных статических серверах преимущества почти не видны.
Сравнение Nginx, HAProxy и Traefik в одной таблице
| Критерий | Nginx | HAProxy | Traefik |
|---|---|---|---|
| Главная роль | Веб-сервер + прокси | Балансировщик | Прокси для контейнеров |
| Конфигурация | Файлы + reload | Файл + reload, Runtime API | Динамически из Docker/K8s |
| Активные health checks | Только в NGINX Plus | Да, гибкие | Да, базовые |
| Let's Encrypt | Через certbot | Через внешний клиент | Встроен |
| TCP/UDP | Да (stream) | TCP — основной режим | Да |
| Статика и кэш | Отлично | Нет | Нет |
| Метрики | stub_status, остальное — экспортёры | Подробная статистика + Prometheus | Prometheus, дашборд |
| Производительность | Высокая | Самая высокая | Ниже, но достаточная для большинства |
| Порог входа | Низкий | Средний | Низкий в Docker, средний в K8s |
Про скорость: в публичных бенчмарках HAProxy обычно впереди по запросам в секунду и расходу CPU, Nginx рядом, Traefik заметно отстаёт. Но для сервиса, который обслуживает сотни запросов в секунду, это различие не играет роли — упираться вы будете в приложение и базу, а не в прокси.
Какой алгоритм балансировки выбрать?
- Round-robin — по очереди. Хорош, когда запросы примерно одинаковые по стоимости, а бэкенды одинаковые по мощности.
- Least connections — тому, у кого меньше активных соединений. Лучший выбор для API с запросами разной длительности, долгих загрузок и WebSocket.
- Hash по IP или ключу — один клиент всегда попадает на один бэкенд. Нужен для локальных кэшей и сессий в памяти, но при выпадении сервера часть клиентов перераспределяется.
- Веса — когда серверы разной мощности или вы выкатываете canary-версию на 10 % трафика.
Если приложение хранит сессию в памяти процесса, балансировка без привязки «сломает» логин при каждом втором запросе. Правильное лечение — вынести сессии в Redis или базу; sticky-сессии — временный костыль.
Где на практике ломается обратный прокси?
Приложение видит IP прокси вместо IP клиента
Логи, rate limit и антифрод начинают считать всех пользователей одним адресом. Прокси должен передавать X-Forwarded-For, а приложение — доверять этому заголовку только от адреса прокси, иначе клиент подделает свой IP. Если перед Nginx стоит ещё один балансировщик, используйте модуль realip (set_real_ip_from 10.0.0.5; real_ip_header X-Forwarded-For;) или PROXY protocol: в HAProxy — send-proxy на сервере, в Nginx — listen 443 ssl proxy_protocol;.
WebSocket обрывается через минуту
Для Nginx WebSocket требует явной передачи заголовков апгрейда и увеличенного таймаута чтения: по умолчанию proxy_read_timeout равен 60 секундам, и молчащее соединение рвётся.
location /ws/ {
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 1h;
}
В HAProxy аналог — timeout tunnel 1h в бэкенде. Traefik проксирует WebSocket без дополнительных настроек.
502 во время каждого деплоя
Пассивные проверки узнают о смерти бэкенда только по упавшим запросам пользователей. Нужны две вещи: эндпоинт /healthz, который отвечает 200 только когда приложение готово, и порядок деплоя «вывести из ротации → дождаться завершения запросов → обновить → проверить → вернуть». В HAProxy это state drain через Runtime API, в Traefik — healthcheck в метках, в Nginx OSS — proxy_next_upstream плюс снятие сервера из upstream и reload.
Сам прокси — единственная точка отказа
Два бэкенда за одним прокси не дают отказоустойчивости: упал прокси — упало всё. Классическая схема на своих серверах — два прокси и keepalived с плавающим IP по VRRP: адрес живёт на основном узле и переезжает на резервный за секунды. В облаке ту же роль играет managed-балансировщик провайдера перед вашими прокси.
Что выбрать под ваш сценарий?
| Ситуация | Выбор | Почему |
|---|---|---|
| Один-два сервера, сайт + API, статика | Nginx | Один инструмент на всё, его знают все |
| Docker Compose / Swarm, сервисы часто меняются | Traefik | Маршруты из меток, HTTPS без certbot |
| Kubernetes, k3s | Traefik или ingress-nginx | Нативная работа с Ingress и CRD |
| Высокая нагрузка, строгие SLA, много бэкендов | HAProxy | Проверки, метрики, управление на лету |
| Балансировка PostgreSQL, Redis, MQTT | HAProxy | Зрелый TCP-режим и проверки |
| Граница сети перед контейнерами | HAProxy на входе + Traefik внутри | Каждый делает то, что умеет лучше |
Комбинации — нормальная практика: HAProxy или облачный балансировщик на краю, Traefik или Nginx рядом с приложениями. А если хочется вообще не думать о сертификатах на маленьком проекте, посмотрите на Caddy — у него автоматический HTTPS включён по умолчанию, а конфиг для прокси занимает три строки.
Чек-лист перед запуском в прод
- TLS: только TLS 1.2+ и HTTP/2, редирект с HTTP, сертификат продлевается автоматически, а истечение мониторится.
- Заголовки
X-Forwarded-ForиX-Forwarded-Protoпередаются, приложение доверяет им только от прокси. - У приложения есть
/healthz, прокси его проверяет. - Таймауты заданы явно: соединение, чтение, WebSocket и долгие загрузки.
- Ограничены размер тела запроса и частота запросов на чувствительные эндпоинты (логин, восстановление пароля).
- Метрики прокси (коды ответов, задержка, состояние бэкендов) — в Prometheus, логи — централизованно. См. Prometheus и Grafana и логирование в продакшене.
- Порты бэкендов закрыты снаружи файрволом — см. базовую защиту сервера.
- Конфиг проверяется перед перезагрузкой (
nginx -t,haproxy -c -f /etc/haproxy/haproxy.cfg) и лежит в git. - Прокси не единственный: есть второй узел с keepalived или облачный балансировщик.
Частые вопросы
Можно ли использовать Nginx и HAProxy вместе?
Да, и это частая схема: HAProxy принимает трафик и балансирует его между несколькими серверами, а на каждом сервере Nginx отдаёт статику и проксирует на приложение. Главное — передавать реальный IP клиента через X-Forwarded-For или PROXY protocol.
Нужен ли reverse proxy, если у меня один сервер приложения?
Да. Даже с одним бэкендом прокси берёт на себя TLS, HTTP/2, сжатие, статику, лимиты и заголовки безопасности, а приложение не держит открытым порт наружу. Когда появится второй экземпляр, балансировка добавится парой строк.
Traefik медленнее Nginx — это проблема?
Для подавляющего большинства проектов — нет. Разница заметна только на десятках тысяч запросов в секунду на одной машине. Если вы до такого дорастёте, на краю можно поставить HAProxy, оставив Traefik для маршрутизации внутри.
Чем активные проверки здоровья лучше пассивных?
Активные проверки сами опрашивают бэкенд по расписанию и исключают его до того, как на него попадёт пользовательский запрос. Пассивные замечают проблему только по уже упавшим запросам, поэтому часть пользователей увидит 502.
Как обновлять приложение за балансировщиком без простоя?
По одному экземпляру: вывести из ротации, дождаться завершения текущих запросов, обновить, проверить health check, вернуть в ротацию и перейти к следующему. В HAProxy для этого есть Runtime API, в Docker и Kubernetes — rolling update с readiness-проверками.
Безопасно ли давать Traefik доступ к Docker-сокету?
Доступ к сокету равносилен root на хосте. Монтируйте его только для чтения, а лучше ставьте docker-socket-proxy, который разрешает Traefik лишь чтение списка контейнеров, и не публикуйте дашборд Traefik наружу без аутентификации.
Что выбрать новичку для первого проекта?
Nginx: по нему больше всего документации на русском, он есть в репозитории любого дистрибутива и закрывает задачи небольшого проекта целиком. Если проект изначально живёт в Docker Compose — можно сразу начинать с Traefik.