OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

HAProxy продвинуто: HTTP/2, gRPC и Lua-фильтры на одном балансировщике

На одном HAProxy можно без конфликтов обслуживать HTTP/2 сайты и gRPC‑микросервисы: завершать TLS, маршрутизировать по ALPN и заголовкам, подключать Lua‑фильтры. В статье — готовая конфигурация, таймауты, health‑checks, логи ALPN и советы по тюнингу.
HAProxy продвинуто: HTTP/2, gRPC и Lua-фильтры на одном балансировщике

Современный периметр часто требует от одного балансировщика одновременно обслуживать классический веб‑трафик (HTTP/1.1 и HTTP/2) и gRPC‑стримы, при этом внедрять трассировку, лёгкую бизнес‑логику и санитаризацию заголовков. Всё это реально в одном HAProxy с правильной конфигурацией TLS+ALPN, маршрутизации по признакам gRPC и Lua‑фильтрами. Ниже — практический разбор, на который можно опираться в проде.

Версии, предпосылки и базовые принципы

Для стабильной работы HTTP/2 на фронтенде и бэкенде, а также gRPC и Lua, ориентируйтесь на HAProxy 2.6+ (желательно 2.8 LTS или новее). В сборке должен быть включён Lua (опция USE_LUA), а для TLS с ALPN — OpenSSL 1.1.1+ или 3.x. В типовой установке пакетного HAProxy это уже есть.

Если балансировщик ещё не развёрнут, удобнее запускать его на изолированном сервере — подойдёт наш VDS, где можно гибко настроить ядро, sysctl и обновления ядра/библиотек без влияния на соседей.

Ключевые идеи конфигурации:

  • Один публичный порт 443, завершение TLS на HAProxy, ALPN: h2,http/1.1.
  • Маршрутизация gRPC по заголовкам: content-type: application/grpc и te: trailers.
  • Отдельные бэкенды: для обычного веба (HTTP/1.1/HTTP/2) и для gRPC (стримы, длинные таймауты, TCP keepalive).
  • Lua‑фильтры для X‑Request‑ID/санитаризации, но без попыток модификации бинарного тела gRPC.
  • Расширенное логирование: фиксируем ALPN, тип трафика и корреляционный ID.
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

TLS и ALPN: единый 443 для всего

ALPN решает, какой протокол на клиентской стороне будет выбран: HTTP/2 или HTTP/1.1. gRPC строится поверх HTTP/2, поэтому клиент с gRPC почти всегда договаривается на h2. Нам важно корректно настроить bind с alpn, кривыми ECDHE и шифрами. Не забудьте о валидном сертификате: оформить и обновлять удобно через наши SSL-сертификаты.

global
  log stdout format raw local0
  master-worker
  nbthread 4
  stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
  lua-load /etc/haproxy/lua/reqid.lua
  tune.bufsize 16384
  tune.maxaccept 64
  tune.h2.max-concurrent-streams 100

defaults
  log global
  mode http
  option httplog
  option http-keep-alive
  option http-use-htx
  timeout connect 5s
  timeout client 1m
  timeout server 5m
  timeout http-request 10s
  http-reuse safe
  # Унифицированный формат логов с ALPN и корреляцией
  log-format "%ci:%cp [%t] %ft %b %ST alpn=%[ssl_fc_alpn] ct=%[req.hdr(content-type)] id=%[var(txn.req_id)] %r"

frontend fe_https
  bind :443 ssl crt /etc/haproxy/certs alpn h2,http/1.1 ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256 ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384 ssl-min-ver TLSv1.2
  # Генерация корреляционного ID и сквозная передача
  http-request lua.add_req_id
  http-response set-header X-Request-ID %[var(txn.req_id)]
  # Диагностика gRPC
  capture request header content-type len 64
  capture request header te len 16

  # ACL, определяющая gRPC-трафик
  acl is_grpc req.hdr(content-type) -m sub application/grpc
  acl is_trailers req.hdr(te) -i trailers

  use_backend be_grpc if is_grpc is_trailers
  default_backend be_web
FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Маршрутизация gRPC: почему content-type и te

gRPC использует HTTP/2 и идиоматично помечает запрос заголовком content-type: application/grpc, а также te: trailers. Этого набора обычно достаточно, чтобы с высокой точностью отличать gRPC от любого другого трафика HTTP/2. Проверка только ALPN не гарантирует gRPC, так как обычные сайты тоже работают по h2.

Такой фронтенд корректно «разруливает» ALPN на клиентской стороне и передаёт запросы дальше логикой ACL. Для статических сайтов и REST API пойдём в be_web, а gRPC — в be_grpc.

Маршрутизация по ALPN и заголовкам: как HAProxy отличает HTTP/2 и gRPC

Бэкенды: HTTP/1.1, HTTP/2 и gRPC одновременно

Если ваши веб‑приложения «за» балансировщиком умеют HTTP/2, имеет смысл говорить с ними по h2 и на серверной стороне (меньше overhead на коннекты и заголовки). Для gRPC это обязательно, так как протокол поверх HTTP/2. Если бэкенд не умеет TLS внутри сегмента — используйте proto h2 без ssl (h2c).

backend be_web
  balance roundrobin
  # Общие сайты и API; HAProxy -> backend по HTTP/2 поверх TLS
  server app1 10.0.0.11:8443 ssl alpn h2,http/1.1 check proto h2
  server app2 10.0.0.12:8443 ssl alpn h2,http/1.1 check proto h2

backend be_grpc
  mode http
  balance roundrobin
  # Для долгих стримов gRPC таймауты шире и включаем keepalive на TCP
  timeout server 10m
  option clitcpka
  option srvtcpka
  # gRPC бэкенды по HTTP/2; если внутри без TLS, уберите "ssl" и оставьте proto h2
  server svc1 10.0.1.21:50051 ssl alpn h2 check proto h2
  server svc2 10.0.1.22:50051 ssl alpn h2 check proto h2
  # Пример h2c (без TLS):
  # server svc3 10.0.1.23:50051 proto h2 check

Ключевой момент — proto h2 на серверной линии. Без него HAProxy будет говорить с бэкендом по HTTP/1.1, что сломает gRPC и лишит преимуществ HTTP/2 для веб‑сервисов. http-reuse safe в defaults разрешает безопасное переиспользование соединений к бэкенду и экономит establish‑overhead.

Health‑checks для HTTP/2 и gRPC

gRPC‑health‑check по протобуфу не так просто собрать силами HAProxy, поэтому есть три рабочих подхода:

  1. HTTP‑endpoint на сервисе (рекомендуется, когда возможно):
backend be_web
  option httpchk GET /healthz
  http-check expect status 200
  server app1 10.0.0.11:8443 ssl alpn h2 check proto h2
  1. TCP‑check для gRPC‑портов, если нет HTTP‑health:
backend be_grpc
  option tcp-check
  tcp-check connect
  server svc1 10.0.1.21:50051 ssl alpn h2 check proto h2
  1. Отдельный агент/проба, публикующая статус (agent‑check). Это гибко, но сложнее в поддержке.

Если сервисы поддерживают HTTP/2 и простой GET /healthz, используйте вариант №1: он точнее. Для чистого gRPC без HTTP‑эндпоинтов чаще всего хватает TCP‑check, а детальные проверки выполняются внешним мониторингом.

Lua‑фильтры: трассировка, санитаризация, A/B

Lua в HAProxy удобна для неблокирующей логики на границе: присвоение X‑Request‑ID, нормализация заголовков, лёгкая маршрутизация на основе заголовков/куков, защита от мусорных значений. Важно помнить: тело gRPC — бинарное и фреймится HTTP/2, поэтому его лучше не пытаться переписывать на ходу.

-- /etc/haproxy/lua/reqid.lua
core.register_action("add_req_id", { "http-req" }, function(txn)
  local id = string.format("%08x-%06x", core.now(), math.random(0, 0xffffff))
  txn:set_var("txn.req_id", id)
  -- Перепишем X-Request-ID, если пришёл от клиента
  txn.http:req_del_hdr("X-Request-ID")
  txn.http:req_add_header("X-Request-ID", id)
end)

В конфигурации мы уже подключили Lua через lua-load и добавили http-request lua.add_req_id. В ответе используем http-response set-header, чтобы сквозной ID дошёл до клиента. Дальше тот же ID подтягивайте в логи приложения — так получится end‑to‑end трассировка.

Практические идеи для Lua

  • Санитаризация User‑Agent, Forwarded/X‑Forwarded‑For, ограничение длины отдельных заголовков.
  • Маркировка запросов по куке/заголовку в var(txn.*) и маршрутизация в canary‑бэкенд.
  • Пополнение метрик через лог‑формат или stats socket (например, счётчик по ключам).

Не модифицируйте тело gRPC в Lua: это небезопасно и приводит к поломке фрейминга HTTP/2. Работайте только с заголовками и переменными транзакции.

Тюнинг HTTP/2: окна, буферы, коннекты

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

  • tune.h2.max-concurrent-streams: ограничьте количество одновременных потоков на соединение, если бэкенды тяжёлые (например, 100–200).
  • tune.bufsize: 16–32 КБ обычно достаточно; рост повышает расход RAM на сессию.
  • http-reuse: режим safe — хороший компромисс. always возможен для чистых API без авторизации на уровне заголовков, но используйте с осторожностью.
  • timeout server и option *tcpka: для gRPC‑стримов выделяйте минуты, включайте TCP keepalive и следите за системными sysctl для TCP‑KA.

Логи и отладка ALPN/gRPC

Собственный log-format с ssl_fc_alpn и заголовком content-type — простой способ увидеть реальное распределение трафика и ошибки клиентов. Для оперативной диагностики:

  • Проверка ALPN от клиента: openssl s_client -alpn h2 -connect YOUR_HOST:443
  • HTTP/2 нагрузка: h2load -n 10000 -c 100 https://YOUR_HOST/
  • gRPC вызов: grpcurl -insecure -d '{}' YOUR_HOST:443 your.Service/Method
  • Статистика сокета: echo "show info" | socat stdio /run/haproxy/admin.sock

Если в логах видите HTTP 502/503 на gRPC при долгих стримах — первым делом увеличьте timeout server и включите option clitcpka/option srvtcpka. Также проверьте, что бэкенд реально говорит по proto h2.

Отладка: логи HAProxy с ALPN и X‑Request‑ID

Частые проблемы и решения

  • 502 с gRPC при долгих вызовах: короткие таймауты на бэкенде, нет TCP keepalive. Лечится увеличением таймаутов и включением keepalive.
  • gRPC‑клиент сообщает об Unavailable или RST_STREAM: обычно закрытие канала при переключении сервера во время health‑check/деплоя. Проверьте balance, стратегию drain и время снятия из пулы.
  • Обычные сайты падают на HTTP/2 из‑за специфики бэкенда: временно отключите proto h2 для проблемного сервера (оставьте HTTP/1.1), либо обновите серверное ПО.
  • Маршрутизация «промахивается» мимо gRPC: проверьте заголовки content-type и te. Некоторые клиенты забывают te: trailers — добавьте fallback‑ACL только по content-type, если уверены.
  • gRPC‑Web — это не тот же протокол; ему нужен транскодер (например, Envoy). Подробности см. в материале gRPC‑Web и Envoy: как подружить браузер с gRPC.

Дополнительно: если нужен rate‑limit на уровне L7, используйте stick‑tables HAProxy. Мы разбирали подход в статье ограничение запросов через stick‑tables.

Распределение нагрузок и границы ответственности

Надёжный вариант — держать один фронтенд на 443 для всех клиентов, а разделение типов трафика выполнять по заголовкам/ALPN. Под капотом — два и больше бэкендов с изолированными таймаутами, проверками, стратегиями балансировки. Это позволяет независимо масштабировать веб и gRPC‑микросервисы, не мешая профилям нагрузки друг друга.

Чек‑лист внедрения

  • Обновите HAProxy до версии с поддержкой HTTP/2 на фронте и бэке, Lua включён.
  • Включите TLS+ALPN на фронтенде: h2,http/1.1, современные шифры и минимальную версию TLS.
  • Сделайте ACL для gRPC по content-type/te и разведите бэкенды.
  • На бэкендах gRPC и HTTP/2 поставьте proto h2, задайте таймауты под стримы и включите TCP keepalive.
  • Добавьте Lua‑фильтры для X‑Request‑ID и санитаризации заголовков.
  • Включите расширенный log-format, проверьте метрики и мониторинг сокета.
  • Проведите нагрузочный прогон h2/gRPC и калибруйте tune.h2.*, timeout *.

С такой конфигурацией один балансировщик уверенно тянет HTTP/2‑сайты и gRPC‑сервисы, остаётся прозрачным для трассировки и не накладывает лишних ограничений на разработку. Главное — дисциплина в таймаутах и аккуратность с Lua: делайте то, что безопасно на уровне заголовков, и не трогайте бинарное содержимое gRPC.

Поделиться статьей

Вам будет интересно

etcd на VDS: практический гайд по snapshot, defrag и restore (в т.ч. для Kubernetes) OpenAI Статья написана AI (GPT 5)

etcd на VDS: практический гайд по snapshot, defrag и restore (в т.ч. для Kubernetes)

Надёжный backup для etcd — основа живучести Kubernetes и сервисов конфигурации. Разбираем, как снимать snapshot, когда делать comp ...
NGINX OpenTelemetry: otel‑модуль и OTLP‑exporter для трассировок и метрик OpenAI Статья написана AI (GPT 5)

NGINX OpenTelemetry: otel‑модуль и OTLP‑exporter для трассировок и метрик

Разбираем, как подружить NGINX с OpenTelemetry на проде: варианты установки otel‑модуля, настройка OTLP exporter (gRPC и HTTP), ин ...
Tailscale на VDS: ACL, exit node и стабильный внешний IP OpenAI Статья написана AI (GPT 5)

Tailscale на VDS: ACL, exit node и стабильный внешний IP

Разворачиваем Tailscale на VDS и превращаем его в управляемый exit node со строгими ACL и стабильным внешним IP. Пошагово разберём ...