Voltar ao blog

gRPC através de proxy na arquitetura de microsserviços: guia completo para configuração de tunelamento HTTP/2

Guia detalhado para configurar o tráfego gRPC através de proxies em uma arquitetura de microsserviços - desde o tunelamento HTTP/2 até balanceamento de carga e terminação TLS.

📅7 de agosto de 2026
```html

gRPC é um framework RPC de alto desempenho do Google que opera sobre HTTP/2 e se torna o padrão de fato para a interação entre serviços. Mas assim que você tenta passar o tráfego gRPC através de um proxy, surgem problemas: a maioria dos proxies clássicos não consegue lidar com HTTP/2 e conexões de streaming de longa duração. Neste artigo, vamos discutir como configurar corretamente o gRPC através de um proxy — desde a escolha da arquitetura até configurações específicas do Nginx, Envoy e HAProxy.

Por que o gRPC não funciona bem com proxies comuns

Para entender o problema, é necessário compreender como o gRPC funciona por trás das cenas. O protocolo utiliza HTTP/2 como camada de transporte, o que o diferencia radicalmente do REST convencional sobre HTTP/1.1. A maioria dos proxies corporativos, firewalls e balanceadores de carga foram projetados na era do HTTP/1.1 e simplesmente não conseguem lidar com streams multiplexados de HTTP/2.

Aqui estão alguns problemas específicos que você encontrará ao tentar passar gRPC através de um proxy HTTP clássico:

  • Downgrade para HTTP/1.1. Muitos proxies automaticamente rebaixam a versão do protocolo. O gRPC requer HTTP/2 — sem isso, a conexão simplesmente não será estabelecida, e o cliente receberá um erro UNAVAILABLE.
  • Interrupção de conexões de longa duração. O gRPC utiliza ativamente streaming bidirecional e do servidor. Proxies com timeouts agressivos (especialmente AWS ELB Classic, algumas versões do Squid) interrompem conexões que não transmitem dados por mais de 60 segundos.
  • Problemas com Content-Type. O gRPC utiliza o cabeçalho Content-Type: application/grpc. Proxies que não conhecem esse tipo podem rejeitar a solicitação ou bufferizar o corpo de forma inadequada.
  • Trailers. O gRPC utiliza trailers HTTP/2 para transmitir o status de conclusão da chamada. Proxies HTTP/1.1 não suportam trailers — a informação de status será perdida.
  • Bufferização do corpo. Alguns proxies bufferizam todo o corpo da resposta antes de enviá-lo ao cliente. Para chamadas gRPC de streaming, isso significa que o cliente não receberá nenhuma mensagem até que o stream seja concluído.

Conclusão chave:

Para que o gRPC funcione através de um proxy, é necessário um proxy que suporte HTTP/2 de ponta a ponta ou um modo especial de tunelamento. Um proxy HTTP clássico sem ajustes na configuração não servirá.

Tunelamento HTTP/2: como funciona

Existem duas abordagens fundamentalmente diferentes para o proxy de tráfego gRPC, e é importante entender a diferença entre elas para escolher a solução correta para sua arquitetura.

Abordagem 1: HTTP/2 de ponta a ponta (recomendada)

O proxy entende HTTP/2 e estabelece uma conexão HTTP/2 tanto com o cliente quanto com o backend. Ele pode analisar streams individuais, aplicar balanceamento no nível de solicitações, adicionar cabeçalhos e realizar terminação TLS. Esta é a opção mais funcional — assim funcionam o Envoy, Nginx (a partir da versão 1.13.10) e balanceadores de carga cientes de gRPC em provedores de nuvem.

Abordagem 2: Tunelamento TCP (CONNECT)

O proxy não analisa o tráfego HTTP/2, mas simplesmente cria um túnel TCP transparente através do método CONNECT. O cliente estabelece uma conexão TLS diretamente com o backend através do túnel. O proxy vê apenas um fluxo de bytes criptografados. Este método é mais simples de configurar, mas o priva das capacidades de balanceamento no nível de solicitações gRPC e adição de cabeçalhos.

Característica HTTP/2 de ponta a ponta Túnel TCP CONNECT
Balanceamento por solicitações ✅ Sim ❌ Não (apenas por TCP)
Terminação TLS no proxy ✅ Sim ❌ Não
Adição de cabeçalhos ✅ Sim ❌ Não
Dificuldade de configuração Média Baixa
Suporte a streaming ✅ Completo ✅ Completo
Observabilidade (métricas) ✅ Detalhada ❌ Apenas TCP

Configurando o Nginx como um proxy gRPC

O Nginx suporta o proxy de gRPC a partir da versão 1.13.10 (fevereiro de 2018). Para funcionar, é necessário o módulo ngx_http_grpc_module, que está incluído na compilação padrão. Importante: o Nginx suporta HTTP/2 no lado do cliente (frontend), mas no lado do backend utiliza HTTP/2 apenas para gRPC — upstream HTTP comum opera sobre HTTP/1.1.

Configuração básica do proxy gRPC no Nginx

server {
    listen 443 ssl http2;
    server_name grpc.example.com;

    # Certificados TLS
    ssl_certificate     /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    # Parâmetros TLS modernos
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        # Diretiva grpc_pass em vez de proxy_pass
        grpc_pass grpc://grpc_backend;

        # Timeouts para streams de longa duração
        grpc_read_timeout  3600s;
        grpc_send_timeout  3600s;
        grpc_connect_timeout 5s;

        # Passando o IP real do cliente
        grpc_set_header X-Real-IP $remote_addr;
        grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

upstream grpc_backend {
    server backend-1:50051;
    server backend-2:50051;
    server backend-3:50051;

    # Keepalive para conexões HTTP/2
    keepalive 32;
}

Preste atenção em alguns detalhes críticos. Primeiro, a diretiva grpc_pass é usada em vez de proxy_pass — são módulos diferentes com comportamentos distintos. Em segundo lugar, os timeouts grpc_read_timeout e grpc_send_timeout estão definidos para 3600 segundos (1 hora) — isso é importante para streams de servidor que podem operar por longos períodos sem transmitir dados. Em terceiro lugar, keepalive 32 no upstream permite reutilizar conexões HTTP/2 com os backends.

Configuração para gRPC não criptografado (grpc://)

server {
    listen 80 http2;
    server_name grpc-internal.example.com;

    location / {
        grpc_pass grpc://127.0.0.1:50051;

        # Tratamento de erros gRPC
        error_page 502 = /error502grpc;
    }

    location = /error502grpc {
        internal;
        default_type application/grpc;
        add_header grpc-status 14;
        add_header content-length 0;
        return 204;
    }
}

O bloco error502grpc é um detalhe importante: quando o backend não está acessível, ele retorna o status gRPC correto UNAVAILABLE (14) em vez do HTTP 502, que o cliente gRPC não conseguirá processar corretamente.

Envoy Proxy: a melhor escolha para gRPC em microsserviços

O Envoy foi criado pela Lyft especificamente para arquitetura de microsserviços, e o suporte ao gRPC é implementado em um nível muito profundo. Ele entende Protocol Buffers, pode transcodificar gRPC em REST, coleta métricas detalhadas para cada método RPC e é a base para soluções de service mesh — Istio, AWS App Mesh e outras. Se você está construindo uma arquitetura de microsserviços séria, o Envoy é o padrão da indústria.

Configuração básica do Envoy para gRPC

static_resources:
  listeners:
  - name: grpc_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: grpc_proxy
          codec_type: HTTP2
          route_config:
            name: grpc_routes
            virtual_hosts:
            - name: grpc_services
              domains: ["*"]
              routes:
              - match:
                  prefix: "/com.example.UserService"
                route:
                  cluster: user_service
                  timeout: 30s
                  retry_policy:
                    retry_on: "reset,connect-failure,retriable-status-codes"
                    num_retries: 3
                    retriable_status_codes: [14]
              - match:
                  prefix: "/com.example.OrderService"
                route:
                  cluster: order_service
                  timeout: 60s
          http_filters:
          - name: envoy.filters.http.grpc_stats
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig
              emit_filter_state: true
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
  - name: user_service
    connect_timeout: 5s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    load_assignment:
      cluster_name: user_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: user-service
                port_value: 50051

As principais vantagens desta configuração incluem: roteamento por serviços gRPC (o prefixo do caminho corresponde ao nome completo do serviço no formato package.ServiceName), tentativas automáticas em caso de status UNAVAILABLE e coleta de métricas gRPC através do filtro grpc_stats.

Transcodificação gRPC-Web no Envoy

Uma das características mais atraentes do Envoy é o transcodificador gRPC-Web embutido. Os navegadores não suportam gRPC diretamente (devido a limitações da Fetch API em relação a trailers HTTP/2), portanto, o protocolo gRPC-Web é utilizado. O Envoy pode automaticamente converter solicitações gRPC-Web do navegador em gRPC normal para o backend:

http_filters:
- name: envoy.filters.http.grpc_web
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
- name: envoy.filters.http.cors
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy
- name: envoy.filters.http.router
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

HAProxy e gRPC: configuração com balanceamento de carga

O HAProxy suporta gRPC a partir da versão 1.9.2. Ele opera no nível TCP ou HTTP/2, consegue balancear tráfego gRPC e realizar health checks. O HAProxy é uma boa escolha se você já o utiliza na infraestrutura e deseja adicionar suporte a gRPC sem introduzir um novo componente.

global
    maxconn 50000
    log stdout format raw local0

defaults
    log global
    timeout connect 5s
    timeout client  3600s
    timeout server  3600s

frontend grpc_frontend
    bind *:443 ssl crt /etc/haproxy/certs/server.pem alpn h2,http/1.1
    mode http
    option http-use-htx
    default_backend grpc_servers

backend grpc_servers
    mode http
    balance leastconn
    option http-use-htx

    # Health check via gRPC Health Checking Protocol
    option httpchk GET /grpc.health.v1.Health/Check
    http-check expect status 200

    server grpc1 10.0.0.1:50051 check ssl verify none
    server grpc2 10.0.0.2:50051 check ssl verify none
    server grpc3 10.0.0.3:50051 check ssl verify none

Preste atenção em algumas configurações importantes. alpn h2,http/1.1 na diretiva bind indica que o HAProxy aceita conexões tanto HTTP/2 quanto HTTP/1.1 através da negociação ALPN TLS. timeout client 3600s e timeout server 3600s são parâmetros críticos para streams gRPC de longa duração. O algoritmo leastconn é preferível ao roundrobin para gRPC, pois conexões de streaming podem ser de longa duração e sobrecarregar desigualmente os backends.

Terminação TLS e criptografia de ponta a ponta para gRPC

O gRPC, por padrão, presume o uso de TLS — isso faz parte da especificação. Na prática, na arquitetura de microsserviços, surge a questão: onde realizar a terminação TLS e como organizar a criptografia entre os componentes? Existem três padrões principais.

Padrão 1: Terminação TLS no proxy (Edge TLS)

O proxy aceita tráfego criptografado dos clientes, descriptografa e o transmite para os backends através de um canal não criptografado (ou com TLS separado). Esta é a abordagem mais comum em redes corporativas. Os backends podem usar grpc.Insecure() para simplificar a configuração.

Padrão 2: Criptografia de ponta a ponta (mTLS)

O Mutual TLS (mTLS) é o padrão para service mesh. Cada serviço possui seu próprio certificado, e em cada conexão ambas as partes verificam os certificados uma da outra. Isso garante a autenticação dos serviços e a criptografia do tráfego dentro do cluster. É assim que o Istio funciona com o proxy sidecar do Envoy.

# Go: servidor gRPC com mTLS
import (
    "crypto/tls"
    "crypto/x509"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
)

func createMTLSCredentials() credentials.TransportCredentials {
    cert, _ := tls.LoadX509KeyPair("server.crt", "server.key")
    
    caCert, _ := os.ReadFile("ca.crt")
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)
    
    tlsConfig := &tls.Config{
        Certificates: []tls.Certificate{cert},
        ClientAuth:   tls.RequireAndVerifyClientCert,
        ClientCAs:    caCertPool,
    }
    
    return credentials.NewTLS(tlsConfig)
}

// Criando o servidor com mTLS
creds := createMTLSCredentials()
server := grpc.NewServer(grpc.Creds(creds))

Padrão 3: TLS Passthrough

O proxy opera no nível TCP e não descriptografa o tráfego — simplesmente redireciona os bytes criptografados para o backend. Esta é a opção mais simples do ponto de vista do proxy, mas priva a capacidade de analisar o tráfego gRPC, adicionar cabeçalhos ou realizar balanceamento no nível de solicitações.

Balanceamento de carga para streams gRPC: características e soluções

O balanceamento de carga para gRPC é uma tarefa não trivial, e aqui está o porquê. No HTTP/1.1, cada solicitação é uma conexão TCP separada (ou uma conexão de um pool), e o balanceador distribui facilmente as solicitações entre os backends. No HTTP/2, uma única conexão TCP multiplexa múltiplos streams — se o balanceador opera no nível TCP, todos os streams de uma conexão irão para um único backend.

Para o gRPC, isso significa que se um cliente estabeleceu uma única conexão HTTP/2 e envia 100 solicitações RPC através dela, com balanceamento TCP, todas as 100 solicitações serão processadas por uma instância do backend. Os outros backends ficarão ociosos. A solução é o balanceamento no nível de streams HTTP/2 (balanceamento L7).

Algoritmos de balanceamento para gRPC

Algoritmo Adequado para gRPC Comentário
Round Robin ✅ Sim Bom para RPC unários com tempos de processamento aproximadamente iguais
Least Connection ✅ Melhor escolha Considera streams ativos, distribui a carga uniformemente
Random ⚠️ Condicional Funciona bem com um grande número de solicitações, mas é desigual com um pequeno
IP Hash ❌ Ruim Vincula o cliente a um único backend, não faz sentido em L7
Pick First (gRPC embutido) ❌ Não para produção Todas as solicitações vão para o primeiro servidor disponível

Balanceamento de cliente em gRPC

O gRPC suporta balanceamento de carga no cliente — o cliente decide para qual servidor enviar a solicitação. Isso permite contornar o problema de multiplexação TCP. Para descoberta de serviços, utiliza-se DNS com vários registros A ou resolvers especiais (Consul, etcd). Exemplo de configuração de balanceamento de cliente em Go:

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/balancer/roundrobin"
)

// Cliente com balanceamento round-robin via DNS
conn, err := grpc.Dial(
    "dns:///grpc-service.internal:50051",
    grpc.WithDefaultServiceConfig(
        `{"loadBalancingConfig": [{"round_robin":{}}]}`
    ),
    grpc.WithTransportCredentials(creds),
)

// Cliente com least-connection (disponível no gRPC >= 1.58)
conn, err := grpc.Dial(
    "dns:///grpc-service.internal:50051",
    grpc.WithDefaultServiceConfig(
        `{"loadBalancingConfig": [{"least_request":{}}]}`
    ),
    grpc.WithTransportCredentials(creds),
)

Proxies externos para gRPC: quando e por que são necessários em microsserviços

Além dos componentes de proxy internos (Nginx, Envoy, HAProxy), na arquitetura de microsserviços às vezes surge a necessidade de usar servidores proxy externos — por exemplo, para roteamento de tráfego através de regiões específicas, contornar restrições de rede ou isolar conexões de saída. Vamos considerar os principais cenários.

Cenário 1: Microsserviços geograficamente distribuídos

Se seus microsserviços estão localizados em diferentes regiões (por exemplo, parte na Europa, parte nos EUA), e você precisa controlar através de qual endereço IP as conexões gRPC são estabelecidas entre as regiões, proxies externos podem ajudar a organizar o roteamento previsível. Para tais tarefas, proxies de data center são adequados — eles fornecem endereços IP estáveis e alta velocidade de conexão, o que é crítico para gRPC devido à sua sensibilidade a latências.

Cenário 2: Isolamento do tráfego de saída

Em alguns ambientes corporativos, todo o tráfego de saída deve passar por um proxy corporativo. Para clientes gRPC que precisam se conectar a serviços gRPC externos (por exemplo, Google Cloud APIs que usam gRPC), isso cria dificuldades. A solução é configurar um túnel CONNECT através do proxy corporativo.

Exemplo de configuração de um cliente gRPC para operar através de um proxy HTTP CONNECT em Go:

import (
    "net"
    "net/http"
    "golang.org/x/net/proxy"
    "google.golang.org/grpc"
)

// Usando um proxy SOCKS5 para gRPC
proxyDialer, _ := proxy.SOCKS5(
    "tcp",
    "proxy.example.com:1080",
    &proxy.Auth{User: "user", Password: "pass"},
    proxy.Direct,
)

conn, err := grpc.Dial(
    "grpc-service.example.com:443",
    grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) {
        return proxyDialer.Dial("tcp", addr)
    }),
    grpc.WithTransportCredentials(creds),
)

Cenário 3: Testes e desenvolvimento

Ao desenvolver microsserviços, muitas vezes é necessário testar o comportamento dos serviços a partir de diferentes ambientes de rede — verificar como o serviço responde a altas latências ou testar a lógica dependente de geolocalização. Para tais tarefas, proxies residenciais são convenientes, pois permitem simular solicitações de regiões específicas com endereços IP reais de usuários domésticos.

Erros comuns ao configurar gRPC através de proxy e suas soluções

Vamos discutir os problemas mais frequentes que os desenvolvedores enfrentam ao configurar gRPC através de proxies e as maneiras específicas de resolvê-los.

Erro 1: "transport: received the unexpected content-type"

Sintoma:

O cliente recebe o erro transport: received the unexpected content-type "text/html; charset=utf-8"

Causa: O proxy retornou uma página HTML de erro (por exemplo, 502 Bad Gateway) em vez da resposta gRPC. O cliente gRPC não consegue processar HTML e gera esse erro.
Solução: Verifique se o backend está acessível. Adicione tratamento de erros gRPC no nível do proxy (como mostrado no exemplo do Nginx acima com o bloco error502grpc).

Erro 2: Conexão é encerrada após 60-120 segundos

Sintoma:

As conexões de streaming gRPC são encerradas inesperadamente com o erro UNAVAILABLE: transport is closing após um intervalo de tempo aproximadamente igual.

Causa: O proxy encerra conexões ociosas após um timeout. Valores clássicos: AWS ELB — 60 segundos, Nginx por padrão — 60 segundos.
Solução 1: Aumente os timeouts no proxy (como mostrado nos exemplos acima).
Solução 2: Configure keepalive no lado do cliente gRPC:

import "google.golang.org/grpc/keepalive"

kaParams := keepalive.ClientParameters{
    Time:                30 * time.Second, // Ping a cada 30 segundos
    Timeout:             10 * time.Second, // Aguardar resposta por 10 segundos
    PermitWithoutStream: true,             // Ping mesmo sem RPCs ativas
}

conn, err := grpc.Dial(
    "grpc-service:50051",
    grpc.WithKeepaliveParams(kaParams),
    grpc.WithTransportCredentials(creds),
)

Erro 3: HTTP/2 não se negocia (falha ALPN)

Sintoma:

Erro transport: failed to dial: context deadline exceeded ou no application protocol

Causa: O proxy ou equipamento intermediário não suporta ALPN (Application-Layer Protocol Negotiation) ou o h2 não está incluído na lista de protocolos suportados.
Solução: Verifique se na configuração TLS do proxy o protocolo h2 está explicitamente especificado: alpn h2,http/1.1 (HAProxy) ou listen 443 ssl http2 (Nginx).

Erro 4: Streaming trava — dados não chegam

Sintoma:

O stream do servidor está funcionando no backend (visível nos logs), mas o cliente não recebe mensagens até que o stream seja concluído.

Causa: O proxy bufferiza a resposta e a envia ao cliente apenas após a conclusão. Um problema típico para proxies configurados com proxy_buffering on.
Solução para Nginx:

location / {
    grpc_pass grpc://backend;
    
    # Desativar bufferização para streams gRPC
    grpc_buffer_size 0;
    
    # Ou para proxy_pass comum:
    proxy_buffering off;
    proxy_cache off;
}

Checklist de diagnóstico gRPC através de proxy

✅ Checklist: diagnóstico de proxy gRPC

  • O proxy suporta HTTP/2 (verifique com curl --http2 -v)
  • ALPN h2 está habilitado nas configurações TLS do proxy
  • Os timeouts do cliente e do servidor estão definidos para pelo menos 300 segundos
  • A bufferização das respostas está desativada para endpoints gRPC
  • O keepalive gRPC está configurado no cliente (Time: 30s, Timeout: 10s)
  • Os erros do backend são retornados como status gRPC, e não códigos HTTP
  • O health check utiliza o gRPC Health Checking Protocol
  • O balanceamento opera em L7 (streams HTTP/2), e não em L4 (TCP)

Conclusão

Configurar gRPC através de um proxy requer compreensão das principais diferenças entre HTTP/2 e HTTP/1.1: multiplexação de streams, conexões de longa duração, trailers HTTP/2 e negociação ALPN. Proxies HTTP clássicos sem configuração especial não funcionam com gRPC — é necessário um proxy L7 que suporte HTTP/2 (Nginx 1.13.10+, Envoy, HAProxy 1.9.2+) ou tunelamento TCP CONNECT.

Para ambientes de produção, o Envoy é recomendado — ele foi projetado especificamente para arquitetura de microsserviços, possui suporte nativo a gRPC, pode coletar métricas detalhadas para cada método RPC e é a base da maioria das soluções de service mesh. O Nginx é uma boa escolha se você já o utiliza como API Gateway e deseja adicionar suporte a gRPC sem introduzir um novo componente. O HAProxy é adequado se a performance é crítica e você já está familiarizado com sua configuração.

Independentemente do proxy escolhido, três regras permanecem inalteradas: aumente os timeouts para streams de longa duração, desative a bufferização das respostas e configure o keepalive no cliente. Essas três configurações resolvem 80% dos problemas com gRPC através de proxies.

Se na sua arquitetura os serviços gRPC devem interagir através de redes externas ou você precisa de roteamento de tráfego através de regiões específicas, considere usar proxies de data center — eles fornecem endereços IP estáveis, baixa latência e alta largura de banda, o que é especialmente importante para gRPC com seu protocolo binário e sensibilidade à latência.

```