Balanceadores de carga e proxies reversos

Requisitos e recomendações para configuração de balanceadores de carga, proxies reversos e demais intermediadores de rede utilizados com o sistema.

Este manual descreve os requisitos e as recomendações de configuração para balanceadores de carga, proxies reversos, firewalls e quaisquer outros intermediadores de rede posicionados entre os navegadores ou os Engines clientes e os servidores de aplicação.

Requisitos gerais

As configurações abaixo se aplicam a qualquer solução intermediadora de rede utilizada no tráfego do sistema.

Preservação de conexões longas e inativas

O sistema pode manter conexões HTTP ativas por longos períodos, pois requisições originadas dos navegadores ou de Engines clientes podem permanecer abertas durante a execução de rotinas de processamento demoradas. Durante esses processamentos, a conexão fica temporariamente inativa sem que isso represente uma falha.

Por esse motivo, proxies reversos, balanceadores de carga, firewalls e quaisquer outros intermediadores de rede não devem encerrar conexões por inatividade. É recomendado configurar o timeout de inatividade para o maior valor suportado. Se possível, configure com um timeout de 864000 segundos (10 dias).

Intervalo de keep alive

Os probes de keep alive devem ser enviados em frequência suficientemente alta para manter os pontos intermediários de rede ativos durante conexões longas. Como o volume de requisições do sistema não costuma ser alto, recomenda-se configurar o intervalo de envio dos probes de keep alive para 60 segundos.

Afinidade de sessão

As sessões HTTP da interface Web do sistema são stateful, que significa que o estado da sessão é mantido no servidor que a iniciou. Por isso, todas as requisições de um mesmo usuário devem ser encaminhadas sempre para o mesmo servidor de aplicação, conceito chamado de afinidade ou persistência de sessão pelos balanceadores de carga.

O sistema define o cookie serverId com o objetivo de auxiliar o balanceador de carga a estabelecer essa afinidade. O uso desse cookie não é obrigatório, podendo ser utilizadas outras estratégias de afinidade, como o IP de origem ou cookies gerados pelo próprio balanceador de carga.

Quando a afinidade for controlada por cookie:

  • o cookie deve ser preservado pelo balanceador por tempo indeterminado;
  • o tempo de vida do cookie deve ser configurado como cookie de sessão (timeout 0), garantindo que ele seja descartado pelo navegador ao final da sessão do usuário.

Quando a afinidade for controlada por IP de origem:

  • a duração da afinidade deve ser configurada com o mesmo valor do timeout de inatividade das conexões;
  • essa opção pode não ser adequada quando o tráfego é originado por computadores em redes que utilizam NAT e que são identificadas por um único IP de Internet válido.

Preservação dos cabeçalhos HTTP

O balanceador de carga ou proxy reverso deve repassar ao cliente todos os cabeçalhos HTTP enviados pelo Engine sem remoção ou alteração indevida. Em particular, o cabeçalho Server não deve ser sobrescrito, permitindo que os Engines clientes identifiquem corretamente a versão do servidor.

Cabeçalhos X-Forwarded-*

Quando o intermediador realizar terminação TLS e encaminhar a requisição ao Engine via HTTP, ele deve informar o protocolo, o endereço e a porta originais por meio dos cabeçalhos X-Forwarded-*. O Engine utiliza essas informações para gerar URLs corretas nas respostas e para identificar o protocolo de acesso do cliente.

Os seguintes cabeçalhos devem ser encaminhados:

Cabeçalho Conteúdo
X-Forwarded-Proto Protocolo da requisição original (http ou https)
X-Forwarded-Host Host informado pelo cliente na requisição original
X-Forwarded-For Cadeia de endereços IP de origem da requisição
X-Forwarded-Port Porta de acesso original do cliente

Atualização do sistema em ambientes com balanceamento

No início do processo de atualização do sistema, o Engine que receberá a atualização precisa ser reiniciado para efetivar a nova versão. Se a atualização for iniciada por um endereço balanceado, não há garantia de que todas as requisições do fluxo de atualização serão encaminhadas para o mesmo Engine.

Por esse motivo, a atualização do sistema sempre deve ser executada utilizando um endereço vinculado diretamente a uma única instância de Engine, sem passar pelo balanceador de carga. Também é importante que o Engine que receba a atualização tenha acesso às demais instâncias, permitindo que ele possa atualizar e reiniciar essas instâncias.

Soluções compatíveis com o sistema

A princípio, qualquer balanceador de carga ou proxy reverso que implemente os requisitos descritos neste manual pode ser utilizado para distribuir o tráfego do sistema. Abaixo, são relacionados sistemas de balanceamento de carga e proxies reversos conhecidos por serem compatíveis com o sistema, juntamente com recomendações de configuração específicas para cada um deles. Os nomes dos parâmetros podem variar entre versões e edições, portanto, a documentação oficial deve ser consultada.

Google Cloud Load Balancing

Documentação de referência:

Configurações recomendadas no serviço de back-end:

  • Timeout de conexão: configurar com o maior valor suportado.
  • Afinidade de sessão: ativar com a opção “Cookie gerado” e configurar o TTL do cookie com 0 (cookie de sessão não permanente).
  • Cabeçalhos X-Forwarded-*: o serviço encaminha automaticamente X-Forwarded-For e X-Forwarded-Proto.

HAProxy

Documentação de referência:

Configurações recomendadas:

  • Timeouts: configurar timeout client, timeout server e timeout tunnel para suportar conexões longas. Para o timeout tunnel o valor recomendado é 864000s (10 dias). Os timeouts client e server se aplicam enquanto há dados trafegando; utilizar o timeout tunnel para o período de inatividade em conexões HTTP estabelecidas.
  • Afinidade de sessão: utilizar cookie no bloco backend para persistência baseada em cookie, utilizando as opções indirect e preserve caso utilize o cookie serverId gerado pelo Engine.
  • Cabeçalhos X-Forwarded-*: a diretiva option forwardfor preenche automaticamente X-Forwarded-For. Os demais cabeçalhos devem ser adicionados explicitamente no bloco frontend ou backend com diretivas http-request set-header:
    option forwardfor
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    http-request set-header X-Forwarded-Proto http  if !{ ssl_fc }
    http-request set-header X-Forwarded-Host  %[req.hdr(host)]
    http-request set-header X-Forwarded-Port  %[dst_port]
    
    Não utilizar regras que removam ou sobrescrevam o cabeçalho Server nas respostas.

Nginx

Documentação de referência:

Configurações recomendadas:

  • Timeouts: configurar proxy_read_timeout e proxy_send_timeout para 864000 segundos. Habilitar keepalive no bloco upstream para manter conexões persistentes com os servidores de back-end.
  • Afinidade de sessão: utilizar o módulo sticky do Nginx Plus ou o módulo de terceiros nginx-sticky-module para afinidade por cookie. Para afinidade por IP, utilizar a diretiva ip_hash no bloco upstream.
  • Cabeçalhos X-Forwarded-*: configurar as diretivas abaixo no bloco location:
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-Port  $server_port;
    
  • Cabeçalho Server: utilizar proxy_pass_header Server para garantir que o cabeçalho Server do Engine seja repassado ao cliente sem alteração.

F5 BIG-IP

Documentação de referência:

Configurações recomendadas:

  • Timeouts: no perfil TCP do virtual server, configurar idle-timeout para 864000 segundos. Ajustar também os timeouts do perfil HTTP conforme necessário.
  • Keep alive: configurar o intervalo de keep alive para 60 segundos no perfil TCP.
  • Afinidade de sessão: criar um perfil de persistência do tipo Cookie com as seguintes configurações e associá-lo ao virtual server:
    • Cookie Method: Passive. O BIG-IP lê o cookie serverId já inserido pelo Engine na resposta HTTP e o utiliza para encaminhar as requisições subsequentes ao mesmo servidor, sem inserir um cookie adicional.
    • Cookie Name: serverId. Deve corresponder exatamente ao nome do cookie definido pelo sistema.
    • Expiration: Session (equivalente a TTL 0). O cookie é descartado pelo navegador ao final da sessão, sem persistir entre sessões distintas do usuário.
  • Cabeçalhos X-Forwarded-*: o cabeçalho X-Forwarded-For pode ser habilitado diretamente no perfil HTTP, ativando a opção Insert X-Forwarded-For. Os demais cabeçalhos devem ser inseridos por meio de uma iRule associada ao virtual server:
    when HTTP_REQUEST {
        HTTP::header insert X-Forwarded-Proto [expr { [SSL::is_ssl] ? "https" : "http" }]
        HTTP::header insert X-Forwarded-Host  [HTTP::host]
        HTTP::header insert X-Forwarded-Port  [TCP::local_port]
    }
    
    Verificar também se há iRules ou perfis existentes que removam ou sobrescrevam o cabeçalho Server nas respostas e removê-los ou desativá-los.

Fortigate

Documentação de referência:

Configurações recomendadas:

  • persistence: utilizar http-cookie.
  • http-cookie-age: configurar com valor 0, garantindo que o cookie seja preservado até o final da sessão do usuário.
  • client-timeout e server-timeout: configurar para 864000 segundos (10 dias) no virtual server de balanceamento, evitando que conexões longas e inativas sejam encerradas.
  • Cabeçalhos X-Forwarded-* (somente quando o Fortigate realizar terminação TLS): habilitar a opção x-forwarded-for no perfil do virtual server para que o endereço IP original do cliente seja inserido no cabeçalho X-Forwarded-For. Os demais cabeçalhos (X-Forwarded-Proto, X-Forwarded-Host e X-Forwarded-Port) devem ser verificados e, caso não sejam inseridos automaticamente pela versão do firmware em uso, configurar via regras de manipulação de cabeçalho HTTP disponíveis no perfil de virtual server.

Por ser uma solução integrada, é importante desativar as regras de firewall e proxy que possam interferir no tráfego nos endereços e portas utilizadas pelo sistema. O proxy é particularmente desnecessário, pois os dados gerados pelo sistema são majoritariamente dinâmicos e o seu uso é conhecido por restringir as requisições chunked originadas pelos Engines clientes.