HTTP/2 без TLS — это не хакинг и не грязный лайфхак, а стандартный режим, который в спецификациях называется h2c (HTTP/2 cleartext). Он не шифрует трафик, но даёт преимущества HTTP/2: мультиплексирование запросов в одном TCP-соединении, приоритизацию и более экономную работу с заголовками. Внутри периметра, где уже есть сетевой контроль и сегментация, это снижает накладные расходы, упрощает трассировку и снимает часть TLS-ритуалов, если они не нужны именно на этом плече.
Однако у h2c есть практические ограничения: поддержка со стороны прокси и бэкендов, различия между режимами «prior knowledge» и «Upgrade», и нюансы совместимости. В этой статье разберём, где h2c уместен, как его включить в Envoy для обычных HTTP/2-бэкендов, что умеет Nginx (спойлер: общий HTTP/2 к upstream пока не поддерживает, но для gRPC — да), и как всё это корректно тестировать и мониторить.
Зачем h2c внутри периметра
Основные плюсы h2c на внутреннем плече между прокси и приложением:
- Меньше соединений: десятки одновременных запросов идут по одному TCP, что упрощает планирование ресурсов, уменьшает контекстные переключения и нагрузку на accept-пути.
- Отсутствие TLS-накладных расходов: не тратим CPU на шифрование/рукопожатия, если шифрование уже обеспечено другими средствами или не требуется внутри доверенного сегмента.
- Стабильная латентность под нагрузкой: мультиплексирование устраняет head-of-line blocking на уровне «соединение на запрос», присущий HTTP/1.1.
- Экономия на заголовках: HPACK уменьшает объём повторяющихся заголовков между запросами.
Где уместно:
- Сервисная mesh/микросервисы в одном сегменте/узле.
- Связка «edge-прокси → приложенческий шлюз/шина → сервисы».
- Высокочастотные API с множеством мелких запросов.
Где нет особого выигрыша или есть риски:
- Большие потоки ответа (медиасервинг, архивы): выигрыша от HPACK почти нет, а узкие места чаще в диске/сети.
- Недоверенные сети: без TLS трафик видим. Там лучше TLS или mTLS.
- Смешанная совместимость: если часть бэкендов «умеет» только HTTP/1.1.
Как работает h2c: prior knowledge и Upgrade
Есть два режима переговоров при h2c:
- Prior knowledge: клиент сразу начинает диалог с HTTP/2 преамбулой. Это самый простой и предсказуемый режим для прокси, обычно его и используют внутри периметра.
- Upgrade: клиент стартует с HTTP/1.1, отправляет заголовок
Upgrade: h2cи специальныйHTTP2-Settings, затем сервер переключается на HTTP/2. Это полезно для обратной совместимости, но поддерживается не всеми прокси одинаково надёжно.
Практический совет: если контролируете обе стороны (прокси и приложение), включайте именно prior knowledge. Меньше точек несовместимости, проще отладка.
Nginx: что реально умеет на стороне upstream
На клиентской стороне Nginx давно поддерживает HTTP/2, но для общего проксирования к upstream в режиме HTTP/2 (включая h2c) в open-source версии Nginx на момент написания нет поддержки. То есть привычный proxy_pass умеет HTTP/1.0/1.1, а не HTTP/2. Это важно учитывать при проектировании трактов.
Исключение — gRPC. Модуль ngx_http_grpc_module использует HTTP/2 для связи с бэкендом и поддерживает как TLS-вариант (grpcs://), так и h2c (grpc://). Если ваш upstream — gRPC-сервис, то Nginx может ходить к нему по h2c напрямую. Если работаете с браузерным gRPC-Web, пригодится подробный обзор: gRPC‑Web через Envoy: разбор и примеры.
Nginx и gRPC по h2c (пример)
server {
listen 80;
# Клиентам можно выдавать HTTP/1.1 или HTTP/2 поверх TLS на фронте — это отдельная история.
location /my.Greeter/ {
# h2c к gRPC-бэкенду (без TLS):
grpc_pass grpc://127.0.0.1:50051;
# Заголовки/таймауты под вашу нагрузку:
grpc_set_header X-Request-ID $request_id;
grpc_read_timeout 30s;
grpc_send_timeout 10s;
}
}
Если backend слушает TLS (HTTP/2 поверх TLS), используйте grpcs:// и включайте верификацию сертификата по CA. Для чистого h2c — grpc://, как в примере выше.
Почему нельзя «обычный» HTTP/2 к upstream
У Nginx нет механизма proxy_http_version 2 и аналогов для генерика HTTP/2 к upstream. Это архитектурное решение: модуль proxy работает поверх HTTP/1.x. Если вам нужен именно HTTP/2 к обычным HTTP-приложениям (REST, не gRPC), используйте дополнительный прокси, который умеет h2c на upstream, например Envoy. Схема «Nginx на фронте → Envoy внутрь → приложение по h2c» встречается часто.

Envoy: h2c к обычным HTTP/2-бэкендам
Envoy умеет говорить HTTP/2 к upstream, включая cleartext (h2c) в режиме prior knowledge. Для этого в кластере включают http2_protocol_options. Ниже — минимальный рабочий пример.
Минимальный конфиг Envoy для h2c к upstream
static_resources:
listeners:
- name: http_listener
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: app
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: app_h2c
http_filters:
- name: envoy.filters.http.router
clusters:
- name: app_h2c
type: STATIC
connect_timeout: 0.5s
load_assignment:
cluster_name: app_h2c
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: 10.0.0.12, port_value: 9000 }
http2_protocol_options: {}
# h2c: cleartext, поэтому raw_buffer (без TLS)
transport_socket:
name: envoy.transport_sockets.raw_buffer
В этом примере Envoy слушает на 8080 и проксирует на 10.0.0.12:9000, разговаривая с бэкендом по HTTP/2 без TLS (h2c). Режим — prior knowledge: Envoy сразу шлёт преамбулу HTTP/2.
Активные проверки и таймауты
clusters:
- name: app_h2c
type: STRICT_DNS
connect_timeout: 0.5s
dns_lookup_family: V4_ONLY
load_assignment:
cluster_name: app_h2c
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: app.internal.local, port_value: 9000 }
http2_protocol_options:
max_concurrent_streams: 1000
initial_stream_window_size: 65536
initial_connection_window_size: 1048576
health_checks:
- timeout: 1s
interval: 5s
unhealthy_threshold: 3
healthy_threshold: 2
http_health_check:
path: /healthz
circuit_breakers:
thresholds:
- max_connections: 10000
max_pending_requests: 0
max_requests: 20000
max_retries: 3
Параметры max_concurrent_streams и window-size влияют на степень параллелизма и поведение флоу-контроля. Значения подбирайте под реальные паттерны запросов/ответов.
Prior knowledge vs Upgrade
Бóльшая часть продакшен-сервисов, которые «умеют» HTTP/2 без TLS, поддерживает prior knowledge. Если ваш бэкенд требует Upgrade, проверьте документацию и совместимость: для Envoy такой сценарий значительно менее типичен и зависит от стека на стороне приложения.
Комбинации: Nginx на краю, Envoy внутри
Распространённая схема: Nginx остаётся внешним фронтом (TLS, виртуальные хосты, сжатие, кэширование), а внутри — Envoy, который ходит к приложениям по h2c. Между Nginx и Envoy можно оставить HTTP/1.1 — это локальный короткий hop, а выигрыши даёт уже Envoy↔приложение.
На границе держите TLS-терминацию и политику HTTPS/HSTS. Если как раз готовите переход на защищённый периметр, посмотрите практический материал: миграция на HTTPS, 301 и HSTS. Для подключения сертификатов подойдёт наш сервис SSL-сертификаты.
Пример: Nginx фронт → Envoy egress → приложение h2c
# Nginx (фронт)
server {
listen 80;
location /api/ {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Request-ID $request_id;
proxy_read_timeout 30s;
proxy_send_timeout 10s;
proxy_pass http://127.0.0.1:8080;
}
}
# Envoy (локально)
# Слушает 8080 и ходит к upstream по h2c — см. предыдущий конфиг кластера app_h2c
Связку Nginx+Envoy удобно разворачивать на управляемых виртуальных серверах. Если нужен изолированный инстанс с рут-доступом и гибкой маршрутизацией, подойдёт VDS.
Производительность: когда есть профит
Переход на h2c внутри периметра ощутимее всего на API с большим количеством мелких запросов и повторяющимися заголовками. Мультиплексирование снижает накладные расходы, а HPACK экономит трафик на заголовках. Если ответы «тяжёлые» (мегабайты и более), узкие места обычно в диске/сети, и разница между 1.1 и h2c минимальна.
Ещё один фактор — латентность и потери: на «длинных» каналах преимущества HTTP/2 раскрываются сильнее благодаря эффективному использованию окна и управлению потоками. На «коротких» и стабильных линках (тот же хост или один L2-домен) разница будет заметна главным образом на пиках QPS.
Практика показывает, что замена связки «много HTTP/1.1 keepalive-соединений» на «одно h2c-соединение» упрощает троттлинг и даёт более предсказуемые хвосты латентности под нагрузкой. Но итог зависит от приложения: если оно синхронно блокируется на каждую операцию, одна соединёнка HTTP/2 может сама стать точкой конкуренции. Тогда помогает увеличение max_concurrent_streams и расширение пулов соединений у прокси.
Тесты и отладка
Проверка h2c бэкенда напрямую
# prior knowledge к приложению (если оно напрямую слушает на 9000)
curl --http2-prior-knowledge -s -D - http://10.0.0.12:9000/healthz
# удобна и утилита nghttp (из пакета nghttp2)
nghttp -v http://10.0.0.12:9000/healthz
В ответах смотрим префиксы/заголовки и статус. Для nghttp будет явно видно установление HTTP/2-сессии. Для curl используйте ключ --http2-prior-knowledge, чтобы избежать попыток обычного HTTP/1.1.
Нагрузка через h2load
# нагрузим Envoy, который ходит к приложению по h2c
h2load -n 10000 -c 100 -m 100 http://127.0.0.1:8080/api/ping
Ключ -m задаёт максимальное число параллельных потоков на соединение. Смотрите распределения TTFB/Latency, ошибки и RPS. Сопоставьте с графиками CPU/сокетов на стороне бэкенда: при удачной настройке увидите меньше активных TCP-соединений и более ровную латентность хвостов.

Логи и метрики
- В Envoy включайте метрики по HTTP/2: количество соединений, активные потоки, ошибки протокола, reset-ы.
- Логи Envoy с полями
%PROTOCOL%,%REQ(X-Request-ID)%помогают коррелировать запросы с трассировкой. - В Nginx прокидывайте
X-Request-IDи, при необходимости,X-Forwarded-Proto/Forwarded. Для h2c к upstream внутри это не обязательно, но часто удобно в цепочке.
Таймауты, очереди и backpressure
У HTTP/2 легко «перебрать» параллелизм потоков, если приложение обрабатывает запросы медленнее, чем прокси их в него впрыскивает. За это отвечают:
max_concurrent_streamsв Envoy-кластере — ограничивает одновременные потоки на соединение.- Окна flow-control — не держите слишком маленькими при крупных ответах, иначе получите лишние паузы.
- Таймауты
connect_timeout,request_timeout(илиtimeoutв маршруте) и перезапуски по ретраям — защищают от зависаний. - Очереди и circuit breakers — не позволяйте бесконечно копить запросы при деградации бэкенда.
Отдельно проверьте лимиты ОС: nofile, сетевые буферы и параметры TCP. При переходе на h2c обычно число соединений падает, но общий поток данных и параллелизм внутри них растёт.
Безопасность и границы ответственности
h2c не шифрует трафик и не даёт аутентификации уровня канала. Включать его стоит только:
- В сегментах, где трафик недоступен третьим лицам (L2/L3 изоляция, приватные VLAN/VPC, межсетевые экраны).
- С чётким разграничением доступа между зонами (например, отдельная DMZ с TLS, а внутри приложения — h2c).
- С мониторингом аномалий и оповещениями по объёму/схемам трафика.
Если требуется защита уровня канала внутри, используйте TLS/mTLS; h2c здесь не альтернатива, а инструмент оптимизации там, где шифрование уже обеспечено другими слоями (частный overlay, зашифрованные туннели) или не требуется.
Чек-лист внедрения h2c
- Подтвердить поддержку HTTP/2 на стороне приложения (prior knowledge предпочтительнее).
- Выбрать прокси с поддержкой HTTP/2 к upstream: для обычного HTTP — Envoy; для gRPC подойдёт Nginx.
- Задать лимиты:
max_concurrent_streams, окна, таймауты, circuit breakers. - Включить health-check и алерты по отказам/таймаутам.
- Провести нагрузочные тесты с
h2loadи сравнить с HTTP/1.1. - В логах и трассировке проставить идентификаторы запросов.
- Пересмотреть сетевые ACLs/маршрутизацию: h2c доступен только нужным хостам и портам.
FAQ и типовые проблемы
Можно ли в Nginx включить HTTP/2 к обычному upstream?
В open-source Nginx — нет. Поддержка HTTP/2 к upstream есть для gRPC через grpc_pass (включая h2c). Для REST/HTTP используйте прокси, которые умеют HTTP/2 к upstream, например Envoy.
Нужен ли Upgrade для h2c?
Почти никогда в современных внутренних сценариях. Prior knowledge проще и поддерживается устойчивее. Используйте Upgrade только если так требует конкретный сервер и вы уверены в совместимости.
Что с приоритизацией потоков в HTTP/2?
Реальная польза зависит от реализации в приложении и прокси. Часто важнее корректно ограничить параллелизм и настроить окна, чем пытаться «идеально» расставить приоритеты.
Будет ли быстрее, чем HTTP/1.1 keepalive?
На API с множеством мелких запросов — обычно да. На крупных скачиваниях — не обязательно. Измеряйте под свою нагрузку.
Как понять, что трафик действительно идёт по h2c?
Смотрите дебаг-логи Envoy, поля протокола в access log, используйте nghttp -v к upstream, и проверяйте, что при прямом подключении работает --http2-prior-knowledge.
Итого: h2c — полезный инструмент оптимизации внутри периметра. Envoy даёт простой и надёжный способ разговаривать с HTTP/2-бэкендами без TLS, Nginx закрывает фронтовые задачи и умеет h2c к gRPC. Скомбинировав их, можно получить стабильный производительный тракт с минимальными накладными расходами и понятной операционкой.


