gRPC стабильно уходит в прод, а вместе с ним — потребность ставить реверс‑прокси перед backend’ами. Чаще всего это Nginx: он принимает TLS, держит единый вход, балансирует, пишет логи и режет всплески. Но gRPC — не обычный HTTP/1.1: он живет поверх HTTP/2, использует мультиплексные потоки, трейлеры и строгое поведение по таймаутам. В этой статье соберем рабочую конфигурацию grpc_pass, разберем таймауты, балансировку и типовые ошибки.
Что особенного в gRPC за Nginx
Ключевое отличие: gRPC требует HTTP/2 и бинарные протоколы поверх него. Для клиента и Nginx это значит ALPN с параметром h2 на TLS‑входе. Для связи Nginx → backend — тоже HTTP/2, но это уже забота модуля ngx_http_grpc_module. Поэтому конфигурация должна явно включать http2 на listen и использовать grpc_pass или grpcs к апстриму. Дополнительно освежить знания по HTTP/2 можно в материале про приоритеты и push в HTTP/2.
Если забыть
http2на фронте, первый запрос клиента будет содержать «PRI * HTTP/2.0», а Nginx ответит 400 или 421. Если промахнуться портом/протоколом до backend’а, получите 502 с сообщением в ошибках про «invalid HTTP/2 header» или «prematurely closed connection».
Минимальная конфигурация: TLS и один backend
Базовый вариант: принимаем TLS‑трафик по HTTP/2 и проксируем на локальный gRPC‑сервер. Для публичного периметра заранее позаботьтесь о валидных SSL-сертификатах.
http {
log_format grpc_access '$remote_addr - $host "$request" $status '
'grpc:$grpc_status $upstream_status '
'$upstream_response_time $request_time';
access_log /var/log/nginx/grpc_access.log grpc_access;
error_log /var/log/nginx/grpc_error.log warn;
upstream grpc_backend {
server 127.0.0.1:50051;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name example.org;
ssl_certificate /etc/ssl/example.crt;
ssl_certificate_key /etc/ssl/example.key;
# Важно для некоторых клиентов и прокси
location / {
grpc_set_header TE trailers;
grpc_pass grpc://grpc_backend;
# Таймауты к апстриму
grpc_connect_timeout 3s;
grpc_read_timeout 1m;
grpc_send_timeout 1m;
}
}
}
Пояснения:
listen ... http2— обязательно для клиентов gRPC поверх TLS.grpc_set_header TE trailers— безопасная совместимость с реализацией трейлеров. В HTTP/2 это формальность, но иногда спасает от «неожиданных» 415/мутных ошибок клиентов.keepaliveвupstream— сокращает накладные расходы на установку HTTP/2 сессий до backend’а.

h2c (без TLS) и внутренняя балансировка
Если фронт доступен только во внутренней сети, можно принимать HTTP/2 без TLS (h2c). Учтите: многие клиенты по умолчанию ожидают TLS и ALPN, поэтому h2c — это story для доверенных сетей и сервис‑to‑сервис.
server {
listen 80 http2;
server_name internal.example;
location / {
grpc_pass grpc://127.0.0.1:50051;
grpc_connect_timeout 1s;
grpc_read_timeout 5m;
grpc_send_timeout 5m;
}
}
Для балансировки:
upstream grpc_pool {
least_conn;
server 10.0.0.11:50051 max_fails=3 fail_timeout=10s;
server 10.0.0.12:50051 max_fails=3 fail_timeout=10s;
keepalive 64;
}
server {
listen 443 ssl http2;
server_name api.example.org;
ssl_certificate /etc/ssl/api.crt;
ssl_certificate_key /etc/ssl/api.key;
location / {
grpc_set_header TE trailers;
grpc_pass grpc://grpc_pool;
grpc_next_upstream error timeout http_502 http_504;
grpc_next_upstream_tries 3;
grpc_next_upstream_timeout 5s;
}
}
Здесь least_conn помогает при долгоживущих потоках (стримы, bidi RPC) равномернее распределять нагрузку.
TLS до backend’а: grpcs и доверие к сертификату
Если backend слушает поверх TLS, используйте grpcs:// и укажите доверенный корневой сертификат. При необходимости — SNI и имя сервера. Если вы переносите входной домен или настраиваете HSTS, пригодится обзор по миграции: переезд домена, 301 и HSTS.
upstream grpc_tls {
server backend.example.internal:443;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name edge.example.org;
ssl_certificate /etc/ssl/edge.crt;
ssl_certificate_key /etc/ssl/edge.key;
location / {
grpc_pass grpcs://grpc_tls;
grpc_ssl_name backend.example.internal;
grpc_ssl_server_name on;
grpc_ssl_trusted_certificate /etc/ssl/certs/ca-bundle.pem;
grpc_connect_timeout 2s;
grpc_read_timeout 2m;
grpc_send_timeout 2m;
}
}
Типичная ошибка при grpcs — 502 с сообщением о TLS‑рукопожатии. Проверяйте цепочку доверия, имя хоста и соответствие сертификата. Если фронт размещаете на отдельном узле, удобнее поднять Nginx на VDS, а публичную защищенную точку входа закрыть валидными SSL-сертификатами.
Таймауты: как не «убить» стримы и дедлайны
gRPC активно использует дедлайны, которые клиенты передают в заголовке gRPC-Timeout. Nginx сам по себе не интерпретирует этот дедлайн: он продолжит удерживать прокси‑соединение, пока не сработают собственные таймауты или backend не закроет поток. Потому важно настроить именно прокси‑таймауты.
grpc_connect_timeout— время на установление соединения с backend’ом. Короткое (1–3s) выявляет недоступные инстансы.grpc_read_timeout— время ожидания следующего байта от backend’а. Для потоковых RPC ставьте с запасом (минуты или часы), иначе ловите 504 в тишине.grpc_send_timeout— время на отправку данных backend’у. При медленном апстриме увеличивайте.
Практические пресеты:
- Синхронные короткие RPC:
connect=1s,read=10s,send=10s. - Генерация отчетов/долгие unary:
connect=2s,read=2m,send=1m. - Стримы/наблюдения:
connect=2s,read=1h,send=1m.
Отдельно про заголовки/метаданные: если получаете 431 на фронте, смотрите лимиты заголовков HTTP/2. Полезно увеличить http2_max_field_size и http2_max_header_size глобально, а также, при необходимости, large_client_header_buffers (хотя это больше про HTTP/1.1).
http {
http2_max_field_size 32k;
http2_max_header_size 128k;
}
Буферы и размеры сообщений
gRPC ограничивает размер сообщений на уровне приложения; Nginx не «склеивает» и не разрезает protobuf‑фреймы. Если backend или клиент жалуются на «message too large», ищите параметр максимального размера сообщения в сервере/клиенте gRPC. На стороне Nginx имеет смысл лишь отрегулировать grpc_buffer_size для сетевых операций и метаданных.
location / {
grpc_pass grpc://grpc_backend;
grpc_buffer_size 64k;
}
Помните: client_max_body_size на gRPC не влияет.
Логи и наблюдаемость gRPC за Nginx
Чтобы понимать, что произошло на уровне gRPC, включайте в формат логов переменную $grpc_status. Она содержит код статуса протокола (например, 0 OK, 4 DEADLINE_EXCEEDED, 14 UNAVAILABLE), который приходит в трейлерах. Параллельно полезны стандартные $status, $upstream_status, $upstream_response_time.
log_format grpc_json '{"ts":"$time_iso8601","remote":"$remote_addr",'
'"host":"$host","req":"$request",'
'"http":"$status","grpc":"$grpc_status",'
'"up":"$upstream_status",'
'"urt":"$upstream_response_time","rt":"$request_time"}';
access_log /var/log/nginx/grpc_access.json grpc_json;
Для «сложных» случаев на ограниченное время повышайте уровень error_log до info или debug и сузьте его до нужного server/location, чтобы не утонуть в объеме.

Типовые ошибки и как их лечить
502 Bad Gateway: upstream sent no valid HTTP/2 header
Чаще всего означает, что вы попали в HTTP/1.1 сервис либо в неверный порт. Проверьте порт backend’а, что там действительно gRPC, а не HTTP‑REST/сторонний демо‑сервер. Для grpcs — смотрите TLS/ALPN и цепочку доверия.
502 Bad Gateway: upstream prematurely closed connection
Backend закрыл соединение до того, как Nginx получил трейлеры/заголовки ответа. Причины: падение процесса, лимиты keepalive на сервере, агрессивный idle‑timeout на стороне backend’а, несовпадение протокола h2/h2c. Лечится увеличением таймаутов и проверкой логов сервиса.
504 Gateway Timeout
Сработал grpc_read_timeout или grpc_send_timeout. Если у вас стримы и могут быть длительные паузы, увеличьте read_timeout. Проверьте, что клиентский дедлайн не короче — иначе клиент оборвет поток раньше.
431 Request Header Fields Too Large
Метаданные gRPC распухли (корреляционные id, токены и пр.). Поднимите лимиты HTTP/2 заголовков в секции http и проверьте, что вы не передаете избыточные поля на каждый RPC.
400/421 на входе: PRI * HTTP/2.0
На фронте не включен http2 на listen, либо клиент пришел h2c на 443/TLS. В первом случае добавьте параметр http2, во втором — используйте 80 http2 (h2c) или заставьте клиента говорить TLS+ALPN.
415 Unsupported Media Type
Редко, но встречается при странной комбинации прокси/клиента. Убедитесь, что Content-Type — application/grpc, и добавьте grpc_set_header TE trailers на всякий случай.
Балансировка и устойчивость
gRPC‑соединения долгие, поэтому:
- Используйте
least_connвместоround_robin, чтобы не «забилдить» один инстанс длинными потоками. - Задайте
max_fails/fail_timeoutиgrpc_next_upstream, чтобы не ждать провалившийся backend дольше разумного. - Добавьте
keepaliveв апстрим, чтобы повторные RPC не тратили время на рукопожатия.
Если нужен стейт, который привязан к конкретному серверу (редко для gRPC, но бывает), можно рассмотреть ip_hash — однако это ухудшит распределение при больших диапазонах клиентов. В идеале — храните состояние вне процесса сервера или используйте токены сеансов.
gRPC‑Web — это другое
Браузерные клиенты часто используют gRPC‑Web (HTTP/1.1 или HTTP/2 с иными заголовками). Nginx не переводит gRPC‑Web в «настоящий» gRPC: для этого нужен отдельный шлюз. Если браузер — ваш основной клиент, убедитесь, что у вас есть совместимый гейтвей или сервер, умеющий оба протокола.
Контроль ресурсоемкости
gRPC поверх HTTP/2 активно мультиплексирует в одном TCP‑соединении много потоков. На фронте это означает:
worker_connectionsи лимиты файловых дескрипторов должны быть с запасом, особенно при тысячах клиентов с долгими стримами.keepalive_timeoutна фронте не стоит делать слишком коротким — иначе будете терять конвейеризацию и плодить handshakes.- Следите за CPU (шифрование TLS, HPACK компрессия заголовков) и памятью (буферы и окна потока). При необходимости масштабируйте фронты горизонтально.
Чек‑лист перед продом
- Nginx собран с
ngx_http_grpc_module, фронт слушаетlisten ... http2. - Путь до backend’а корректен:
grpc://илиgrpcs://, SNI и доверенный корень заданы при TLS. - Выставлены адекватные
grpc_connect_timeout/grpc_read_timeout/grpc_send_timeoutпод ваш профиль RPC. - Включены логи с
$grpc_statusи метриками апстрима. - Балансировка учитывает длительность потоков:
least_connиkeepaliveвupstream. - Лимиты HTTP/2 заголовков увеличены при необходимости (
http2_max_field_size,http2_max_header_size). - Проверены ошибки 502/504/431 на стенде и отработаны сценарии отказов (
grpc_next_upstream).
Итого
Настройка gRPC за Nginx упирается в три вещи: строго включенный HTTP/2 на фронте, корректный grpc_pass до backend’ов и таймауты, соответствующие профилю трафика. Добавьте к этому продуманную балансировку и наблюдаемость с $grpc_status — и у вас получится устойчивый и предсказуемый слой входа для gRPC‑сервисов. А дальше все как обычно: нагрузочные прогоны, проверки ошибок и мониторинг, чтобы поймать углы именно вашей продовой нагрузки.


