Alguém aponta um host HAProxy público para uma aplicação interna e pergunta por que o navegador não consegue seguir. O proxy chega à app pela sua VPN, o redirecionamento devolve um cabeçalho Location, e o navegador tenta então um endereço que só existe dentro do túnel. De fora, a página simplesmente fica pendurada. A decisão é sobre qual parte abre a segunda conexão, e é isso que separa um redirecionamento de um backend.

Dois caminhos que parecem iguais na configuração

Um redirecionamento termina a troca com uma resposta. O cliente lê Location e inicia um novo pedido de onde estiver, ou seja, a rede que você nunca controlou. O proxy já não participa. Tudo o que vem depois depende do DNS, da rota e da confiança do próprio cliente, por isso o resultado varia conforme onde o utilizador abriu o navegador:

GET /app        client -> proxy
302 Location    proxy  -> client   (http://10.40.0.20:8080/)
GET /app        client -> 10.40.0.20:8080   client network, no route

Um backend do proxy mantém a segunda etapa do lado do servidor. O proxy abre-a pelo caminho que já tem, e o cliente continua a falar com um único nome público. Se o túnel cair, o cliente recebe um erro em vez de um URL que não consegue seguir. Essa diferença é também o que torna a avaria diagnosticável, porque o erro aparece onde estão os registos:

GET /app        client -> proxy
GET /app        proxy  -> 10.40.0.20:8080   over the VPN
response        proxy  -> client

A documentação de redirecionamentos do HAProxy traça exatamente essa linha: responder ao cliente com um redirecionamento é uma ação diferente de encaminhar o pedido para um backend. As duas diretivas ficam a poucas linhas de distância num ficheiro de configuração e comportam-se de forma totalmente diferente. Uma termina o pedido, a outra começa um segundo que pertence ao proxy.

O que o navegador precisa e a VPN do servidor não lhe dá

O pedido do próprio navegador precisa de quatro coisas que pode não ter: uma resposta DNS para o nome privado, uma rota até esse endereço, permissão para alcançar o serviço que escuta, e confiança no certificado que esse serviço apresenta. O host do proxy tem as quatro através do seu túnel. Nenhuma delas passa para um cliente que nunca esteve nesse túnel, porque o túnel é uma propriedade do host, não do URL.

Essa lacuna explica o sintoma de quase-funciona. O primeiro pedido tem sucesso, a barra de endereços muda, e a conexão fica pendurada ou falha enquanto o proxy está saudável o tempo todo. Na configuração do proxy nada está quebrado, e ajustá-la não ajuda um cliente que não tem caminho até 10.40.0.20. Ou o cliente obtém uma rota, ou o proxy tem de fazer a conexão em seu nome.

Quando só o proxy consegue chegar à app

Remova a ação de redirecionamento e envie esses pedidos para um backend que aponta para o endereço privado. O frontend mantém o seu nome público enquanto o backend decide para onde o pedido vai realmente. Nada no caminho do cliente muda, porque o proxy deixa de descrever um destino e passa a ser um. Para uma aplicação que escuta deliberadamente na porta interna 8080, o bloco de servidor é curto:

backend private_app
    mode http
    option httpchk GET /health
    server app1 10.40.0.20:8080 check

Leia esse bloco como uma afirmação sobre a tabela de rotas do proxy: 10.40.0.20 tem de ser alcançável a partir do próprio host do proxy, o que aqui significa pela interface VPN e não pela rota predefinida. A palavra-chave check só relata o que essa rota faz, e o caminho de saúde tem de existir na aplicação, senão cada verificação marca o servidor como em baixo. Uma verificação bem-sucedida não prova nada sobre o cliente e não substitui a política que decide quem pode usar o backend.

O fragmento não é um frontend completo. Mantenha o ouvinte, a autenticação, a seleção de host e caminho permitidos e a regra que decide quem pode sequer chegar à aplicação. Alinhe também o protocolo do backend, porque um backend HTTPS exige verificação de certificado e uma configuração de identidade do servidor, e saltar essa verificação transforma uma ligação privada numa não verificada.

Confirme o caminho de volta nos dois sentidos antes de declarar vitória. A aplicação vê agora uma conexão vinda do proxy, por isso os seus registos e quaisquer metadados do endereço do cliente descrevem o proxy, a menos que organize de outra forma. Decida como são tratados a identidade e os endereços encaminhados, e teste a decisão em vez de a assumir.

Os redirecionamentos do próprio app continuam a apontar para dentro

Encaminhar o primeiro pedido é apenas metade da integração. A aplicação pode emitir redirecionamentos absolutos, URL de recursos codificados à mão ou cookies limitados ao nome que conhece internamente, e cada um deles devolve o navegador a um endereço que não consegue alcançar. Um cabeçalho Location que aponta para o nome interno parece idêntico ao problema original, e por isso é mal diagnosticado como falha do proxy.

Defina o URL externo documentado da aplicação e as suas opções de proxy, e depois faça o cabeçalho Host coincidir com o host virtual e com as expectativas do certificado. Um cookie limitado ao nome interno não volta pelo nome público, e o ciclo de início de sessão que se segue lê-se como um erro de autenticação. Mude primeiro o URL externo, teste de novo a partir de um perfil de navegador limpo, e conte com uma configuração meio migrada a produzir um início de sessão que funciona e uma sessão que morre de imediato.

Confie nos metadados encaminhados apenas do proxy designado. Um cabeçalho que qualquer cliente pode definir nunca deve tornar-se um valor de autorização, ou o proxy transforma-se numa forma de quem chama reclamar a identidade de outra pessoa. Essa regra é independente da questão do redirecionamento e sobrevive a qualquer redesenho posterior.

Decida qual desenho tem na realidade

Se cada utilizador já tem acesso VPN autorizado, um redirecionamento para um URL privado pode ser um desenho deliberado. Confirme esse requisito explicitamente em vez de o assumir, porque os dois desenhos servem populações completamente diferentes. Um deles não funciona de todo a partir de uma rede de hotel, e o outro expõe a aplicação a qualquer pessoa que consiga carregar o URL público. Essa distinção pertence à nota de desenho.

Execute a verificação a partir de uma máquina na rede dos utilizadores e siga cada salto que o navegador faz, não apenas a primeira resposta. Vigie a barra de endereços e cada pedido seguinte, porque um único URL absoluto numa etiqueta de recurso basta para quebrar um fluxo que o primeiro salto passou. O início de sessão tem de funcionar pelo nome público, e os recursos que devem ser negados têm de continuar negados.

Publicar um proxy inverso é uma decisão de acesso separada, não uma extensão transparente da VPN do próprio proxy a qualquer pessoa que consiga carregar o seu URL público. Os dois parecem-se num diagrama, e diferem em quem tem permissão para entrar. Decidir essa questão depois da implementação é como uma aplicação interna se torna pública por acidente.

Anote qual dos dois construiu e porquê. A pessoa seguinte que tocar na configuração vai assumir o outro. Um único redirecionamento acrescentado por conveniência basta para recriar a falha original, e o sintoma vai parecer exatamente o que acabou de corrigir.

Artigos relacionados