65 лет полету человека в космос! Хостинг и домены со скидкой
до 22.04.2026 Подробнее
Выберите продукт

HTTP/2 без TLS внутри периметра: h2c к upstream в Nginx и Envoy

HTTP/2 без TLS (h2c) полезен внутри доверенного сегмента: меньше накладных расходов и одна мультиплексируемая сессия вместо множества TCP. В материале — когда это оправдано, как включить h2c к upstream в Envoy, что реально умеет Nginx (gRPC), таймауты, проверки, тесты и метрики.
HTTP/2 без TLS внутри периметра: h2c к upstream в Nginx и Envoy

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» встречается часто.

Диаграмма потока: прокси говорит с upstream по h2c в режиме prior knowledge

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.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Производительность: когда есть профит

Переход на 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-соединений и более ровную латентность хвостов.

Сравнение: мультиплексирование HTTP/2 против множества соединений HTTP/1.1

Логи и метрики

  • В 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. Скомбинировав их, можно получить стабильный производительный тракт с минимальными накладными расходами и понятной операционкой.

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

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

Debian/Ubuntu: sudo: unable to change expired password при входе по SSH — как исправить OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: sudo: unable to change expired password при входе по SSH — как исправить

Если в Debian или Ubuntu при входе по SSH или запуске sudo появляется unable to change expired password, проблема обычно связана н ...
Debian/Ubuntu: как исправить send-packets: Broken pipe и write failed в SSH, SCP, SFTP и rsync OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить send-packets: Broken pipe и write failed в SSH, SCP, SFTP и rsync

Если SSH-сессия внезапно рвётся с ошибками send-packets: Broken pipe, write failed или client_loop: send disconnect: Broken pipe, ...
Debian/Ubuntu: Cannot allocate memory при fork и SSH — диагностика и исправление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: Cannot allocate memory при fork и SSH — диагностика и исправление

Ошибки Cannot allocate memory, fork cannot allocate memory и ssh cannot allocate memory в Debian/Ubuntu часто связаны не только с ...