Saudações.
Vou apresentar a vocês algumas experiências com o Squid Proxy em ambiente de containers.
Pré-requisitos:
- VM/VPS/Host com Docker (standalone ou Swarm);
- Internet no servidor (sua VPS ou host);
1 – Conceito de Proxy e software Squid
O Squid (https://www.squid-cache.org/) é um software escrito em C++ cujo objetivo é ser um framework supremo de Proxy.
Foi criado em 1996 e possui décadas de maturidade.
Ele consegue atuar de todas as formas possíveis dentro do escopo dos protocolos HTTP, HTTPs, FTP, ICP e alguns outros.
Principais recursos:
- Proxy direto: Atende clientes HTTP fornecendo Internet indiretamente;
- Proxy reverso: Recebe conexões em direção a um site e entrega ao servidor interno correto;
- Conexão de entrada HTTPs, conexão interna HTTP;
- Cache ajuda a aliviar a carga no fornecimento de arquivos e assets;
- Proxy transparente: Captura tráfego de rede e se passa pelo site acessado;
- Cache: Armazena arquivos e recursos em RAM e/ou disco para acelerar a Internet e economizar banda;
- Esse era sua principal função antes da migração em massa para HTTPs;
- Num mundo HTTPs o cache perdeu seu lugar e descontinou o Squid nos provedores;
- Autenticação: Permite discriminar usuários por login e senha e controlar quais recursos o usuário pode acessar e com quais caractarísticas técnicas (IP de origem, QoS, horário, etc);
- ACL: Permite discriminar IPs, domínios, usuários, cabeçalhos para decidir permitir, negar, redirecionar ou modificar os detalhes do acesso;
No Docker standalone (servidor solitário) ou no cluster Docker Swarm o Squid encontra a oportunidade de nos ajudar no ingress (conexões que vem da Internet em direção aos nossos serviços) atuando como Proxy Reverso ou no egress, fornecendo acesso controlado e auditado do que nossos containers estão indo buscar na Internet.
2 – Estudo do caso
Observe meu caso:
- Cluster de servidores Docker Swarm com workers distribuídos em vários datacenters;
- Containers que precisam acessar a Internet (bots, pesquisas, scrapping, tools de agentes);
- Cada container navegava com um IP diferente pelo NAT do Linux de cada servidor;
- Containers workers rodam:
- Web Scrapping: Transformam os sites acessados em documentos JSON e MarkDown;
- Web Search: Meus agentes de IA precisam navegar (Agent Tools) em vários sites para realizar pesquisas;
- API: Acesso a API de provedores de IA, APIs corporativas, scrapping remoto (firecrawl), etc;

Problemas que enfrentei:
- Problema 1 – leve: Sites modernos implementam limite de requisições por IP (RPM – Request per Minute) e limite de banda por IP (Traffic Shapping);
- Problema 2 – moderado: Sites protegidos por WAF (Web Application Firewall), o WAF aprende o padrão de repetição “like a bot” e bloqueiam o IP de origem;
- Problema 3 – grave: Alguns containers rodam em países diferentes, o bloqueio por GEOIP impede o funcionamento nesses servidores;
- Problema 4 – gravíssimo: Para cada IP bloqueado os containers que ainda conseguem navegar passam a fazer muitas requisições e os problemas anteriores se amplificam.
A solução parece óbvia: Precisamos contratar um proxy externo PAGO para balancear essa carga de saída entre milhares de IPs diferentes para que os bloqueios e limites sejam contornados.

Como muitas das minhas ferramentas precisam apenas de controle de uso mais do que volume, optei por usar o Squid como gateway dos meus containers, e no Squid eu implemento toda a lógica do negócio, usando IPs próprios balanceados ou entregando para provedores de Proxy quando necessário.
Fase 1 – No diagrama abaixo o problema parece se agravar, os containers que antes navegavam com os IPs de seus servidores agora navegam com o IP do Squid.

Fase 2 – O servidor Squid agora pode ser configurado com a lógica do nosso negócio, indo diretamente na Internet para os serviços menos burocráticos e delegando para provedores Proxy o acesso sensível a IPs de origem, observe:

Fase 3 – Quando a rede escala e você precisa balancear seus softwares para navegarem na Internet fazendo centenas a milhares de requisições por segundo:

3 – Clientes HTTP e Variáveis de Ambiente
Para que você não tenha que configurar cada software e cada navegador para usar o proxy, a industria facilitou com o uso de alguns variáveis de ambiente que se presentes, desviam o tráfego para o proxy.
3.1 – Variáveis de Ambiente
As principais variáveis são:
http_proxy: Endereço do servidor proxy para requisições do schema “http://“;https_proxy: Endereço do servidor proxy para requisições do schema “https://“;ftp_proxy: Endereço do servidor proxy para requisições do schema “ftp://“;socks_proxy: Endereço do servidor proxy para conexões SOCKS4/SOCKS5;no_proxy: Registro de excessões separadas por virgula, as excessões não usam proxy e vão direto para o site de destino;all_proxy: Funciona como fallback genérico. Se não houver uma variável específica para o schema do protocolo (HTTP, HTTPS, FTP, etc.), o cliente usa esse endereço;
Você quer cobrir a maioria dos cenários, configurar http_proxy, https_proxy, no_proxy e all_proxy.
3.2 – Declarações com case-sensitive
Infelizmente diferentes softwares e bibliotecas HTTP fazem a leitura nas versões upper-case (maiúsculas) dessas variáveis, assim, recomendo declarar nas duas formas, mesmo a lower-case (minúscula) seja a oficial.
| Variável padrão | Variável uper-case | Finalidade |
|---|---|---|
http_proxy | HTTP_PROXY | Proxy para http:// |
https_proxy | HTTPS_PROXY | Proxy para https:// |
ftp_proxy | FTP_PROXY | Proxy para ftp:// |
socks_proxy | SOCKS_PROXY | Proxy para socks |
no_proxy | NO_PROXY | Declaração de destinos sem proxy |
all_proxy | ALL_PROXY | Proxy fallback para todos os protocolos |
3.3 – Bibliotecas de cliente HTTP
Você precisará estudar o manual da biblioteca HTTP que seus programas utilizam para afinar a configuração de proxy. As principais bibliotecas são:
- Python: requests (a mais popular), urllib3 (baixo nível, avançada), httpx (moderna, HTTP/2), aiohttp (async nativa), pycurl (performance máxima, multi-protocolo), httplib2 (mais antiga, cache, HTTP/2), urllib (stdlib, nativa da linguagem);
- JavaScript: fetch API (nativa), axios (mais popular), node-fetch (versões antigas do Node), got (rica em funcionalidades), ky (wrapper leve), undici (alta performance), superagent (encadeável, tem plugins), needle (leve, suporta streaming);
- Go: net/http (stdlib, geral), resty (wrapper da net/http), heimdall (avançada), gentleman (baseado em plugins), grequests (inspirada na requests do Python), go-retryablehttp (HashiCorp, net/http com retries automáticos e backoff).
3.4 – Declarando e usando variáveis de proxy
Exemplos de como declarar variáveis de ambiente e seus efeitos.
Usando endereço de proxy universal para todos os protocolos:
# Usando all_proxy:
export all_proxy="http://proxy.empresa.com:3128"
unset ftp_proxy;
unset http_proxy;
unset https_proxy;
# Todas as requisicoes abaixo vao via HTTP até o proxy (sem criptografia)
curl http://api.ipify.org; echo; # Usa o proxy (http => proxy => http)
curl https://api.ipify.org; echo; # Usa o proxy (http => proxy => https)
curl ftp://api.ipify.org; echo; # Usa o proxy (http => proxy => ftp)
Proxy apenas para HTTP ou apenas para HTTPs:
# Apenas HTTP
# - Declarar proxy HTTP
export http_proxy="http://proxy0.empresa.com:3128";
# - Sem proxy HTTPs
export https_proxy=""; # declarar vazio, ou
unset https_proxy; # remover variavel de ambiente
# Requisicao HTTP => Proxy HTTP
curl http://api.ipify.org; echo; # Usar proxy na porta 3128 do proxy0
# Requisicao HTTPs => direto na Internet
curl https://api.ipify.org; echo; # Nao passa pelo proxy
# Apenas HTTPs
# - Sem proxy HTTP
export http_proxy=""; # declarar vazio, ou
unset http_proxy; # remover variavel de ambiente
# - Declarar proxy HTTPs
export https_proxy="https://proxy0.empresa.com:8443";
# Requisicao HTTP => direto na Internet
curl http://api.ipify.org; echo; # Nao passa pelo proxy
# Requisicao HTTPs => Proxy HTTPs
curl https://api.ipify.org; echo; # Usar proxy na porta 8443 do proxy0
CURL com proxy HTTP e HTTPs em endereços diferentes:
# Declarar enderecos dos servidores proxy:
# - Proxy HTTP
export http_proxy="http://proxy1.empresa.com:3128"
# - Proxy HTTPs
export https_proxy="http://proxy2.empresa.com:3129"
# Acessar sites:
curl http://api.ipify.org; echo; # Usa proxy na porta 3128 do proxy1
curl https://api.ipify.org; echo; # Usa proxy na porta 3129 do proxy2
# Ignora o uso de proxy:
curl --no-proxy http://api.ipify.org; echo; # Acesso direto na Internet sem proxy
curl --no-proxy https://api.ipify.org; echo; # Acesso direto na Internet sem proxy
CURL com proxy geral de fallback:
# Declarar enderecos dos servidores proxy:
# - Proxy HTTP, HTTPs, Sockets, FTP, ...
export all_proxy="http://proxy3.empresa.com:3128"
# Acessar sites:
curl http://api.ipify.org; echo; # Usa proxy na porta 3128 do proxy3
curl https://api.ipify.org; echo; # Usa proxy na porta 3128 do proxy3
CURL com proxy geral de fallback e HTTPs (mais específico vence):
# Declarar proxy de HTTPs:
export https_proxy="http://proxy4.empresa.com:8443";
# Declarar proxy geral:
export all_proxy="http://proxy5.empresa.com:3128";
# Acessar sites:
curl http://api.ipify.org; echo; # Usa proxy na porta 3128 do proxy5
curl https://api.ipify.org; echo; # Usa proxy na porta 8443 do proxy4
CURL especificando proxy na linha de comando (sem variável de ambiente):
# Proxy explicito, canal HTTP acessando site HTTP:
curl -m 5 -x http://proxy6.empresa.com:1080 http://api.ipify.org; echo;
# Proxy explicito, canal HTTP (insecuro) acessando site HTTPs:
curl -m 5 -x http://proxy7.empresa.com:3128 https://api.ipify.org; echo;
4 – Canais e segurança
Existem 3 canais (protocolos) para comunicação com um proxy:
- HTTP (RFC 2616): Transporta o protocolo em puro texto sobre TCP (padrão) ou UDP;
- HTTPs (RFC 2818): Transporta o protocolo HTTP dentro de uma conexão TCP protegida por TLS (padrão) ou SSL;
- Envolve o uso de certificados x509;
- Certificados auto-assinados não possuem reconhecimento dos clientes;
- Certificados assinados tem preço, os gratuitos possuem validade curta (3 meses);
- ICP (RFC 2186): Utiliza o Internet Cache Protocol como canal de comunicação, normalmente somente entre servidores proxy (essa adjacência se chama cache peer).
4.1 – Combinações de diferentes canais
O cliente pode se comunicar com o Proxy usando as seguintes combinações de protocolos cliente=>proxy=>site:
HTTPs fim-a-fim – Combinação perfeita: Cliente se conecta via HTTPs no Proxy, solicita método CONNECT e é conduzido de forma transparente até o site HTTPs. Apenas o IP é alterado (o site enxerga o IP do Proxy apenas).

HTTP até o Proxy: Cliente se conecta via HTTP com o Proxy, não há criptografia nesse canal. O proxy se conecta via HTTPs no site. Essa combinação é ideal apenas quando o Proxy está na rede privada com o cliente ou a comunicação entre o cliente e o proxy é protegida na camada inferior (VPN, IPSec, VXLAN+IPSec, Wireguard, OpenVPN, etc).
x
x
x
4.2 – Certificados x509
Conexões HTTPs (HTTP seguro) requer criptografia utilizando certificados x509. Esses certificados possuem atributos para tornar o uso exclusivo seu uso no recurso: IP ou nome de DNS (Common Name). Um certificado emitido para patrickbrandao.com não pode ser usado em um site como o ajustefino.com, cada site precisa do seu certificado.
O proxy, ao entrar no meio de uma conexão entre o cliente e o site, precisa:
- Ter seu próprio certificado, o proxy que serve ao cliente usando HTTPs deve possuir o certificado para seu nome de DNS (FQDN = x509 Common Name);
- Não se intrometer entre o cliente e o site HTTPs final, o Common Name do Proxy é diferente do Common Name do site.
x
5 – Squid no Docker
Para usar o Squid o processo é muito simples, você pode construir um container do zero. Você poderá incluir sua configuração personalizada e embutir sua regra de negócios nele.
Nesse capítulo vou demonstrar uma POC (prof of concept) de como rodar. Esse projetinho não é exatamente completo e perfeito mas serve para a didática da técnica.
Crie uma pasta para esse projeto, vou chamar de “squid-basic“. Na pasta coloque o arquivo Dockerfile:
# Container do Squid com base Alpine
FROM alpine:3.23.3
# Variaveis globais
ENV TZ=America/Sao_Paulo
ENV PS1='\u@\h:\w\$ '
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US.UTF-8
# Atualizar base
RUN apk update && apk upgrade
# Instalar pacotes
RUN apk add squid curl openssl
# Envs de proxy, ontainer usando o proprio squid como proxy
ENV http_proxy=http://localhost:1080/
# https requer projetar uso de certificados
#ENV https_proxy=https://localhost:443/
# Portas internas do Squid
EXPOSE 443/tcp
EXPOSE 1080/tcp
EXPOSE 8080/udp
EXPOSE 8443/tcp
# Processo do container
CMD [ "/usr/sbin/squid", \
"-n", \
"proxy", \
"-f", \
"/etc/squid/squid.conf", \
"--foreground" \
]
Dentro da pasta do projeto, construa a imagem “squid-basic” com tag padrão “latest“:
# Criar imagem squid-basic
docker build . \
--pull \
--no-cache \
-f Dockerfile \
-t squid-basic:latest;
A imagem está pronta para uso, mas infelizmente, usando a configuração padrão do squid em /etc/squid/squid.conf (caminho dentro do container).
Vamos criar um arquivo squid.conf na pasta do projeto para mapear como volume de arquivo dentro do container:
# Portas HTTP
http_port 1080
http_port 3128
http_port 8080
# Portas HTTPs, precisa projetar a forma de gerar e usar certificados
#https_port 8443 cert=/certs/fullchain.pem key=/certs/privkey.pem
#https_port 443 cert=/certs/fullchain.pem key=/certs/privkey.pem
# Lista de prefixos para controle de acesso
# - Localhost
acl LOCALHOSTv4 src 127.0.0.1/32
acl LOCALHOSTv6 src ::1/128
acl LOCALHOST src 127.0.0.1/32
acl LOCALHOST src ::1/128
# - Redes locais conhecidas
acl LOCALNETSv4 src 10.117.0.0/16
acl LOCALNETSv6 src 2001:db8:10:117::/64
acl LOCALNETSv6 src fe80::/64
# - Redes privadas (todas)
# - IPv4:
acl PRIVATESv4 src 10.0.0.0/8
acl PRIVATESv4 src 169.254.0.0/16
acl PRIVATESv4 src 172.16.0.0/12
acl PRIVATESv4 src 192.0.0.0/24
acl PRIVATESv4 src 192.0.2.0/24
acl PRIVATESv4 src 192.88.99.0/24
acl PRIVATESv4 src 192.168.0.0/16
acl PRIVATESv4 src 198.18.0.0/15
acl PRIVATESv4 src 198.51.100.0/24
acl PRIVATESv4 src 203.0.113.0/24
acl PRIVATESv4 src 224.0.0.0/4
acl PRIVATESv4 src 240.0.0.0/4
# - IPv6:
acl PRIVATESv6 src ::/3
acl PRIVATESv6 src 2001:db8::/32
acl PRIVATESv6 src 4000::/2
acl PRIVATESv6 src 8000::/1
# - Redes publicas confiaveis (seus servidores, VPs, VM)
# - IPv4
acl ALLOWED_NETWORKSv4 src 172.233.34.15
acl ALLOWED_NETWORKSv4 src 45.255.128.0/22
# - IPv4
acl ALLOWED_NETWORKSv6 src 2600:3c0d::f04d:a4ef:fc13:7cb8/128
acl ALLOWED_NETWORKSv6 src 2804:cafe::/32
# Controle de acesso
# - Sempre permitir localhost
http_access allow LOCALHOSTv4
http_access allow LOCALHOSTv6
# - Sempre permitir redes locais (docker networks)
http_access allow LOCALNETSv4
http_access allow LOCALNETSv6
# - Sempre permitir redes privadas
http_access allow PRIVATESv4
http_access allow PRIVATESv6
# - Sempre permitir IPs publicos conhecidos
http_access allow ALLOWED_NETWORKSv4
http_access allow ALLOWED_NETWORKSv6
# - NEGAR TODO O RESTO
http_access deny all
# Opcoes gerais
pid_filename /run/squid.pid
icon_directory /run
err_page_stylesheet none
# Ajustes de parametros
forward_max_tries 25
connect_timeout 2 minutes
read_timeout 15 minutes
request_timeout 5 minutes
shutdown_lifetime 30 seconds
# Arquivos de logs
access_log daemon:/data/logs/squid-access.log squid !LOCALHOST
cache_log /dev/null
cache_store_log none
logfile_rotate 10
# Cache
cache_replacement_policy heap GDSF
cache_mem 0 MB
maximum_object_size_in_memory 8 MB
minimum_object_size 0 KB
maximum_object_size 4 MB
# Modo oculto, nao encaminhar cabecalhos que revelam a existencia do proxy
# - Desativar cabecalhos nativos
via off
forwarded_for delete
follow_x_forwarded_for deny all
httpd_suppress_version_string on
visible_hostname localhost
strip_query_terms off
uri_whitespace strip
# - Retirar cabecalhos do Squid
reply_header_access X-Cache deny all
reply_header_access X-Cache-Lookup deny all
reply_header_access X-Squid-Error deny all
request_header_access X-xproxy-role deny all
request_header_access X-Forwarded-For deny all
request_header_access Forwarded deny all
request_header_access Proxy-Connection deny all
request_header_access Proxy-Authorization deny all
Agora vamos rodar o container. Na pasta do projeto onde está o squid.conf, execute:
# Rede de containers squid (ipv4 only)
docker network create proxynet \
-d bridge \
-o com.docker.network.bridge.name=br-proxynet \
-o com.docker.network.driver.mtu=1500 \
-o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected;
# Pasta do volume
# - Pasta principal
mkdir -p /storage/squid-basic;
# - Pasta para logs
mkdir -p /storage/squid-basic/logs;
chmod 777 /storage/squid-basic/logs;
# Renovar/rodar container squid-basic:
# Remover atual
docker rm -f squid-basic 2>/dev/null;
# Criar e rodar
docker run -d \
--restart=always \
--name=squid-basic \
--hostname squid-basic.intranet.br \
\
--user=root --cap-add=ALL --privileged \
\
--cpus=1 \
--memory 512m --memory-swap 512m --shm-size 512m \
\
--tmpfs /run:rw,size=8m \
-v /storage/squid-basic:/data \
-v ./squid.conf:/etc/squid/squid.conf \
\
--network proxynet \
\
-p 1080:1080 \
-p 3128:3128 \
\
squid-basic;
Container rodando, vamos entrar no shell do container:
# Entrar no shell ash do container:
docker exec -it squid-basic ash;
Testando proxy:
# Testar com proxy HTTP via variavel http_proxy
curl -v http://api.ipify.org; echo;
# * Uses proxy env variable http_proxy == 'http://localhost:1080/'
# * Host localhost:1080 was resolved.
# * IPv6: ::1
# * IPv4: 127.0.0.1
# * Trying [::1]:1080...
# * Established connection to localhost (::1 port 1080) from ::1 port 36930
# * using HTTP/1.x
# > GET http://api.ipify.org/ HTTP/1.1
# > Host: api.ipify.org
# > User-Agent: curl/8.17.0
# > Accept: */*
# > Proxy-Connection: Keep-Alive
# >
# * Request completely sent off
# < HTTP/1.1 200 OK
# < Date: Sun, 12 Apr 2026 15:15:07 GMT
# < Content-Type: text/plain
# < Content-Length: 14
# < Server: cloudflare
# < Vary: Origin
# < cf-cache-status: DYNAMIC
# < CF-RAY: 9eb32f424ab1c6ce-GRU
# < Cache-Status: localhost;detail=mismatch
# < Connection: keep-alive
# <
# * Connection #0 to host localhost:1080 left intact
# 45.255.128.158
Observe a primeira linha “http_proxy == ‘http://localhost:1080/’“.
Temos um proxy muito básico e funcional que infelizmente não atende HTTPs.
5 – Projeto Squid Gateway
Criei um projeto chamado “squid-gateway” capaz de prover um Squid pronto para produção e replicação e com suporte HTTPs com certificados do Traefik.
Pré-requisitos:
- Container do Traefik;
- Container do Traefik-Certs (minha autoria);
5.1 – Rede Docker
É necessário criar a rede Docker para definir como seu proxy irá lidar com o protocolo IP.
Rede somente IPv4 – Proxy não fará acessos em IPv6
# Rede de containers Squid - Somente IPv4
docker network create squidnet -d bridge \
-o com.docker.network.bridge.name=br-squidnet \
-o com.docker.network.driver.mtu=1500 \
-o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected;
Rede dual-stack – IPv4 e IPv6, o proxy escolherá por conveniência do DNS e rapidez
# Rede de containers Squid - Dual-stack IPv4 e IPv6
docker network create squidnet -d bridge --ipv6 \
-o com.docker.network.bridge.name=br-squidnet \
-o com.docker.network.driver.mtu=1500 \
-o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected;
5.2 – Certificado
x
x
(parei aqui, ainda estou escrevendo)
x
x
“Todos os meus movimentos
foram friamente calculados.“
Chapolim Colorado
Terminamos por hoje!
Patrick Brandão, patrickbrandao@gmail.com
