Um upstream proxy é um servidor proxy para o qual outro servidor proxy encaminha as requisições do cliente, formando uma cadeia em que o primeiro proxy atua como cliente do upstream proxy.
O que é um upstream proxy?
Quando um cliente envia uma requisição para um servidor proxy, esse servidor proxy normalmente busca o recurso solicitado diretamente no servidor de origem na internet. No entanto, em muitos desenhos arquiteturais, o primeiro servidor proxy não entra em contato diretamente com a origem. Em vez disso, ele encaminha a requisição para outro servidor proxy, conhecido como upstream proxy. Esse segundo proxy então trata da requisição, seja atendendo-a a partir do seu cache, seja encaminhando-a para mais um upstream proxy, seja buscando-a no servidor de origem.
Os principais objetivos de utilizar um upstream proxy incluem:
- Segurança em camadas: adicionar uma camada extra de segurança e controle de acesso.
- Funções especializadas: delegar tarefas específicas como filtragem de conteúdo, varredura antivírus ou cache avançado a um proxy dedicado.
- Segmentação de rede: interligar diferentes segmentos de rede ou fornecer acesso controlado a redes externas.
- Anonimato e privacidade: ocultar o endereço IP do cliente de origem por meio de múltiplos saltos.
- Contornar restrições: rotear o tráfego por diferentes localizações geográficas ou redes para contornar geobloqueios ou restrições de rede.
- Balanceamento de carga: distribuir requisições entre vários upstream proxies ou servidores de origem.
O fluxo de uma requisição com um upstream proxy é: Client -> Proxy A -> Upstream Proxy B -> Origin Server. Nesse cenário, o Proxy A está configurado para usar o Proxy B como seu upstream.
Proxies em cascata explicados
Proxies em cascata, também conhecidos como encadeamento de proxies (proxy chaining), referem-se à arquitetura em que vários servidores proxy são organizados em sequência, com cada proxy encaminhando as requisições para o próximo da cadeia até que o proxy final entre em contato com o servidor de origem. Isso cria um caminho de múltiplos saltos para as requisições do cliente.
Vantagens dos proxies em cascata
- Segurança reforçada: cada proxy pode aplicar seu próprio conjunto de políticas de segurança, autenticação e controles de acesso.
- Arquitetura modular: proxies diferentes podem se especializar em funções diferentes (por exemplo, um para cache, outro para WAF, outro para controle de saída).
- Roteamento complexo: permite uma lógica de roteamento sofisticada, direcionando tipos específicos de tráfego por cadeias ou localizações geográficas diferentes.
- Maior anonimato: mais saltos tornam mais difícil rastrear o cliente original.
- Redundância de contorno: oferece caminhos alternativos caso um proxy da cadeia falhe ou seja bloqueado.
Desvantagens dos proxies em cascata
- Maior latência: cada salto adicional de proxy introduz atraso de processamento e latência de rede.
- Complexidade: a configuração e o gerenciamento ficam mais intrincados, especialmente para depuração e resolução de problemas.
- Pontos únicos de falha: se não houver redundância no projeto, a falha de qualquer proxy da cadeia pode interromper o serviço.
- Dificuldade de depuração: rastrear o caminho de uma requisição e identificar problemas pode ser difícil em vários servidores.
- Gestão de cabeçalhos: o tratamento correto de cabeçalhos como
X-Forwarded-ForeViaé essencial para o log e para o conhecimento do servidor de origem.
Configurando um upstream proxy
Exemplos de configuração para servidores proxy comuns, demonstrando como configurar um proxy para encaminhar requisições a um upstream.
Nginx (como reverse proxy para um upstream)
O Nginx normalmente atua como reverse proxy. Para configurar uma instância Nginx para encaminhar requisições a um upstream proxy, você define o endereço do upstream proxy na diretiva proxy_pass dentro de um bloco location.
# Configuração do Nginx (por exemplo, proxy.example.com)
# Esta instância Nginx atua como Proxy A, encaminhando para o Upstream Proxy B.
http {
upstream upstream_proxy_b {
# Endereço do seu upstream proxy (Proxy B)
server 192.168.1.100:3128; # Exemplo: IP e porta do Proxy B
# Opcional: adicione vários servidores para balanceamento de carga/failover se o Proxy B tiver várias instâncias
# server 192.168.1.101:3128;
}
server {
listen 80;
server_name proxy.example.com;
location / {
# Repassa as requisições para o upstream_proxy_b definido
proxy_pass http://upstream_proxy_b;
# Cabeçalhos recomendados para cadeias de proxy
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Via "1.1 $hostname"; # Adiciona o proxy atual ao cabeçalho Via
}
}
}
Squid (como forward proxy para um upstream)
O Squid é comumente usado como forward proxy. Para configurar o Squid para usar um upstream proxy, você utiliza a diretiva cache_peer.
# Configuração do Squid (por exemplo, proxy-a.conf)
# Esta instância Squid atua como Proxy A, encaminhando para o Upstream Proxy B.
# Define o upstream proxy (Proxy B)
# Sintaxe: cache_peer hostname type http_port icp_port [options]
# type: parent ou sibling (parent é mais comum para upstream)
# http_port: porta HTTP do upstream proxy
# icp_port: porta ICP (normalmente 0 se não for usada ou for desconhecida)
cache_peer 192.168.1.100 parent 3128 0 no-query default_parent
# Exemplo com vários upstream proxies (Proxy B e Proxy C)
# cache_peer 192.168.1.101 parent 3128 0 no-query round-robin
# cache_peer 192.168.1.102 parent 3128 0 no-query
# Controle de acesso para permitir que os clientes usem este proxy
acl localnet src 192.168.0.0/24 # Exemplo: a rede dos seus clientes
http_access allow localnet
http_access deny all
# Especifica a porta em que o Squid escuta as requisições dos clientes
http_port 3129 # O Proxy A escuta na 3129
# Opcional: adicionar cabeçalho Via
via off # O Squid adiciona cabeçalhos Via por padrão; 'off' significa que o Squid não adicionará seu próprio cabeçalho 'Via',
# mas encaminhará os já existentes. Para garantir que ele *adicione* o seu, remova esta linha ou defina como 'on'.
# Para cascata, normalmente se prefere 'via on' ou o comportamento padrão.
Nesta configuração do Squid, o proxy-a escuta na porta 3129 e encaminha todas as requisições para 192.168.1.100:3128 (Proxy B) por causa da opção default_parent.
Configurando proxies em cascata
Para montar proxies em cascata, você configura cada proxy da cadeia para apontar para o próximo.
Cenário: Client -> Proxy A -> Proxy B -> Internet
Esse cenário envolve dois proxies em cadeia.
Configuração do Proxy A (proxy de front-end)
O Proxy A é o primeiro ponto de contato para os clientes e encaminha as requisições para o Proxy B.
Nginx como Proxy A:
(Consulte o exemplo do Nginx em "Configurando um upstream proxy" acima. O bloco upstream_proxy_b e a diretiva proxy_pass http://upstream_proxy_b; configuram o Nginx para enviar as requisições ao Proxy B.)
Squid como Proxy A:
(Consulte o exemplo do Squid em "Configurando um upstream proxy" acima. A diretiva cache_peer 192.168.1.100 parent 3128 0 no-query default_parent configura o Squid para enviar as requisições ao Proxy B.)
Configuração do Proxy B (proxy intermediário/upstream)
O Proxy B recebe as requisições do Proxy A e depois as encaminha para a internet (ou para outro upstream proxy, se a cadeia for mais longa).
Nginx como Proxy B:
Se o Proxy B também for uma instância Nginx, ele normalmente seria configurado como um reverse proxy padrão que encaminha para o servidor de origem. Se estiver atuando apenas como ponto de saída ou como mais um proxy, sua configuração seria semelhante à do Proxy A, mas o destino do proxy_pass seria o próximo proxy ou a origem real.
# Configuração do Nginx para o Proxy B (192.168.1.100)
# Esta instância Nginx recebe requisições do Proxy A e encaminha para a internet.
http {
server {
listen 3128; # O Proxy B escuta na 3128 as requisições do Proxy A
server_name proxy-b.example.com; # Ou simplesmente escute no IP
location / {
# Aqui, o Proxy B poderia encaminhar diretamente para a origem com base na requisição original do cliente
# Ou poderia encaminhar para *outro* upstream, se a cadeia continuar.
# Por simplicidade, assumimos que ele encaminha para a internet com base na requisição original.
# O Nginx como forward proxy é mais complexo e geralmente envolve resolução dinâmica.
# Um cenário mais comum é o Nginx atuando como reverse proxy para um conjunto conhecido de origens,
# ou para um único proxy de "próximo salto".
# Exemplo: se o Proxy B encaminhar para uma origem específica conhecida
# proxy_pass http://www.example.com;
# Se o Proxy B tiver que atuar como forward proxy genérico para domínios arbitrários (menos comum no Nginx)
# Isso exige resolução dinâmica e normalmente é tratado por forward proxies especializados como o Squid.
# Para o Nginx funcionar como forward proxy genérico, muitas vezes é preciso scripting Lua customizado ou módulos.
# Um Proxy B em Nginx mais simples poderia apenas repassar para *outro* upstream fixo.
# Para uma saída de "internet" de verdade, geralmente se prefere o Squid.
# Se o Proxy B for apenas o ponto de saída e não souber a origem final (como o Squid)
# É aqui que as capacidades do Nginx como forward proxy de *uso geral* são limitadas.
# Se o Proxy B for um Nginx, é mais provável que ele seja um reverse proxy para serviços específicos
# ou um próximo salto em uma cadeia definida, em que o próximo salto também é fixo.
# Para efeito de cascata, se o Nginx for o Proxy B, ele normalmente seria configurado
# para repassar a um próximo salto *conhecido* ou a uma origem conhecida.
# Para uma saída para a "internet geral", o Squid é mais apropriado.
# Vamos assumir que o Proxy B encaminha para um upstream *final* conhecido, por exemplo, um proxy anonimizador
# ou um gateway de saída específico.
proxy_pass http://final_egress_proxy:8080; # Exemplo: encaminhando para um proxy de saída final
# Ou, se for o último salto antes da origem e o Nginx estiver configurado para resolução dinâmica de upstream:
# proxy_pass $scheme://$host$request_uri; # Requer configuração customizada para forward proxy dinâmico
# Por simplicidade, vamos assumir que o Proxy B é um proxy Squid para acesso geral à internet.
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Via "1.1 $hostname";
}
}
}
Squid como Proxy B:
O Proxy B recebe as requisições do Proxy A e é configurado para buscar diretamente na internet ou encaminhar para mais um upstream. Se for o último proxy antes da internet, ele não precisa de uma diretiva cache_peer apontando para outro proxy (a menos que seja para domínios específicos ou failover).
# Configuração do Squid para o Proxy B (192.168.1.100)
# Esta instância Squid recebe requisições do Proxy A e busca na internet.
# O Proxy B escuta na 3128 as requisições do Proxy A
http_port 3128
# Opcional: se o Proxy B também tiver seu próprio upstream (por exemplo, um proxy do ISP ou outro proxy específico)
# cache_peer upstream.isp.com parent 8080 0 no-query default_parent
# Controle de acesso para permitir que o Proxy A (e outros clientes autorizados) se conectem
acl proxy_a_network src 192.168.1.0/24 # Exemplo: rede onde o Proxy A está
http_access allow proxy_a_network
http_access deny all
# Configure cache, logs etc. conforme necessário para o Proxy B
Cascata avançada: upstreams condicionais
Para roteamentos mais complexos, você pode querer enviar requisições de domínios ou caminhos específicos para upstream proxies diferentes.
Upstreams condicionais no Nginx:
http {
# Grupo de upstream para o tráfego geral
upstream general_upstream {
server 192.168.1.100:3128; # Proxy B
}
# Grupo de upstream para tráfego sensível específico
upstream secure_upstream {
server 192.168.2.200:4444; # Proxy C seguro
}
server {
listen 80;
server_name proxy.example.com;
location /secure/ {
# As requisições para /secure/ vão para o Proxy C seguro
proxy_pass http://secure_upstream;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
# Todas as demais requisições vão para o Proxy B
proxy_pass http://general_upstream;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
Upstreams condicionais no Squid:
# Define vários cache_peers
cache_peer 192.168.1.100 parent 3128 0 no-query name=general_proxy
cache_peer 192.168.2.200 parent 4444 0 no-query name=secure_proxy
# ACLs para identificar tráfego específico
acl secure_domains dstdomain .secure.example.com
acl secure_urls url_regex ^https://secure\.
# Direciona as requisições com base nas ACLs
cache_peer_access secure_proxy allow secure_domains
cache_peer_access secure_proxy allow secure_urls
cache_peer_access general_proxy allow all
# Garanta que o tráfego que não corresponder a uma regra explícita de acesso a peer vá direto ou para o default_parent
# se nenhum default_parent estiver definido, as requisições podem falhar ou ir direto conforme 'never_direct'/'always_direct'
# Normalmente é melhor ter um default_parent ou um 'cache_peer_access' final para capturar tudo.
Considerações essenciais para proxies em cascata
Latência e desempenho
Cada proxy da cadeia adiciona tempo de processamento e latência de rede. Minimizar o número de saltos e garantir proxies e links de rede de alto desempenho é fundamental. Monitore a latência ponta a ponta para identificar gargalos.
Segurança e autenticação
- Autenticação entre proxies: implemente autenticação (por exemplo, whitelist de IP, segredos compartilhados, certificados de cliente) entre os proxies para impedir acesso não autorizado aos proxies intermediários.
- Terminação SSL/TLS: decida onde ocorre a terminação SSL/TLS. Se os proxies descriptografam o tráfego, garanta a gestão adequada dos certificados e a recriptografia para os saltos seguintes.
- Controle de acesso: configure listas de controle de acesso (ACLs) rigorosas em cada proxy para permitir tráfego apenas de proxies upstream/downstream ou clientes autorizados.
Depuração e resolução de problemas
Rastrear requisições através de vários proxies pode ser complexo.
* Cabeçalho X-Forwarded-For: este cabeçalho registra o endereço IP original do cliente e os IPs dos proxies subsequentes da cadeia. Garanta que ele seja corretamente acrescentado em cada salto ($proxy_add_x_forwarded_for no Nginx).
* Cabeçalho Via: o cabeçalho Via indica os proxies intermediários pelos quais a requisição passou. Cada proxy deve acrescentar seu identificador a esse cabeçalho.
* Logging: logs centralizados e IDs de correlação são essenciais para rastrear requisições ao longo de toda a cadeia de proxies.
Balanceamento de carga e failover
Para garantir alta disponibilidade e distribuir o tráfego, configure o balanceamento de carga para os upstream proxies.
* Nginx: use o bloco upstream com várias diretivas server e opções como least_conn, round_robin, backup, down.
nginx
upstream proxy_b_cluster {
server 192.168.1.100:3128 weight=5; # Proxy B primário
server 192.168.1.101:3128 backup; # Proxy B de backup
server 192.168.1.102:3128; # Outro Proxy B primário
least_conn; # Usa o método de menos conexões
}
# Depois proxy_pass http://proxy_b_cluster;
* Squid: use várias diretivas cache_peer com opções como round-robin, weighted-round-robin, failover e no-query.
squid
cache_peer 192.168.1.100 parent 3128 0 no-query weight=10
cache_peer 192.168.1.101 parent 3128 0 no-query weight=5
cache_peer 192.168.1.102 parent 3128 0 no-query round-robin
Gestão de cabeçalhos
A gestão cuidadosa dos cabeçalhos HTTP é crítica. Além de X-Forwarded-For e Via, considere o Proxy-Authorization para autenticar junto aos upstream proxies e garanta que os demais cabeçalhos relevantes sejam encaminhados ou removidos conforme a política.
Comparação: upstream único vs. upstreams em cascata
| Recurso / Aspecto | Upstream proxy único | Upstream proxies em cascata |
|---|---|---|
| Complexidade | Baixa; configuração e gerenciamento mais simples. | Alta; configuração, gerenciamento e depuração intrincados em vários servidores. |
| Latência | Sobrecarga mínima; um salto de rede adicional. | Sobrecarga maior; múltiplos saltos de rede e atrasos de processamento por proxy. |
| Flexibilidade | Limitada às capacidades de um único proxy. | Alta; permite funções especializadas em cada etapa e roteamento complexo. |
| Camadas de segurança | Camada única de segurança e controle de acesso. | Segurança em várias camadas; cada proxy pode aplicar políticas distintas. |
| Anonimato | Oferece anonimato básico perante a origem. | Anonimato reforçado; mais difícil rastrear o cliente original por vários saltos. |
| Depuração | Relativamente direta. | Desafiadora; exige gestão cuidadosa de cabeçalhos (X-Forwarded-For, Via) e de logs. |
| Impacto de falha | A falha do único upstream interrompe todo o tráfego. | A falha de qualquer proxy da cadeia pode interromper o serviço se não houver failover. |
| Casos de uso | Filtragem de conteúdo básica, cache, controle de acesso simples. | Segurança avançada, compliance, geo-roteamento, serviços especializados, alta necessidade de anonimato. |
