O IP de origem atrás do Cloudflare vaza pelo subdomínio deploy — três repos, catorze segundos, tudo consertado de uma vez
Naquela tarde fiquei olhando o GitHub por um tempo. Três repos fecharam PRs às 16:20:31, 16:20:38 e 16:20:45 — catorze segundos de diferença.
smarts #38: deploy.smarts.md → deploy.smartshow2claude #13: deploy.how2claude.com → deploy.how2claudepickful #118: deploy.pickful.ai / deploy.pickful.xyz → deploy.pickful / deploy.pickful-alphaOs três fixes eram da mesma classe de bug. Eu estava conversando com o Claude sobre um detalhe de deploy não relacionado em how2claude. Ele deu uma olhada de passagem em config/deploy.yml e me disse que o IP de origem daquela máquina estava à mostra no DNS público.
Todos os meus projetos estão atrás do Cloudflare. Aquela nuvenzinha laranja no painel do Cloudflare significa "registro proxiado" — as requisições HTTP chegam primeiro num nó edge do Cloudflare, e dali para a minha origem. O IP de origem nunca aparece nas respostas DNS; o que o DNS retorna é um IP anycast do Cloudflare. Essa parte estava certa.
Mas eu deploy com Kamal. Kamal faz SSH no servidor para rodar docker. SSH não passa por proxy HTTP, então eu precisava de um hostname não proxiado pelo Cloudflare para fazer SSH. Minha config era:
# config/deploy.yml
servers:
web:
- deploy.how2claude.com # ← registro A direto pro IP de origem, nuvem cinza (DNS only)
No Cloudflare, how2claude.com e www.how2claude.com estavam em laranja. deploy.how2claude.com estava em cinza. Tinha que estar em cinza, senão o SSH não chegava na máquina.
Cinza significa DNS público. Qualquer um pode rodar:
$ dig deploy.how2claude.com +short
<meu IP de origem>
E a convenção de nomes deploy.<domínio> por si só já é uma pista — varra o subdomínio deploy.* numa lista de domínios SaaS comuns e você tem uma colheita de IPs de origem que deveriam estar escondidos atrás do Cloudflare.
Pula o WAF do Cloudflare, pula rate limiting, pula proteção DDoS. Tudo a um dig de distância.
A gente estava falando de outra coisa. Pedi pra ele revisar um doc de deploy que eu tinha acabado de escrever; ele abriu config/deploy.yml pra cruzar referências, chegou na linha 7 — - deploy.how2claude.com — pausou, e disse mais ou menos isso:
Esse hostname resolve por DNS público, certo? Ou seja, qualquer um com uma query DNS consegue esse IP de origem, e o proxy edge do Cloudflare é contornado.
Travei por um segundo. Eu deveria ter visto isso — bastava ter olhado duas vezes pro ícone de nuvem cinza ao configurar o Cloudflare e perguntado o que ele significava — mas não vi. Eu tratava aquele hostname como algo "interno", apenas porque o prefixo era deploy.. Meu cérebro silenciosamente concedeu a ele uma privacidade que nunca existiu.
O Claude não compartilha esse viés. Ele lê uma string num campo yaml e faz a pergunta mecânica: como essa string vira um IP? Resposta: DNS público. Conclusão: o IP de origem é público.
/etc/hostsO fix acabou sendo embaraçosamente simples. O Kamal pede ao cliente SSH local pra resolver o hostname, então o hostname só precisa resolver na minha máquina — não na internet inteira.
Encurta o hostname no yaml:
servers:
web:
- deploy.how2claude # ← repare: sem .com
Depois adiciona uma linha no meu /etc/hosts:
198.51.100.42 deploy.how2claude
Os runners de CI que fazem deploy precisam da mesma linha (variável de ambiente, ou direto echo >> /etc/hosts no workflow).
Resultado:
deploy.how2claude.* existe no DNS público em lugar nenhumkamal deploy / app exec / app logs continua funcionando, porque /etc/hosts é consultado antes do DNSO accessory do banco precisa da mesma mudança:
accessories:
db:
image: postgres:17
host: deploy.how2claude # ← mesmo hostname
Essa é a parte que eu queria registrar.
Quando terminamos o fix do how2claude, eu ia trocar de contexto. O Claude me parou: "Você também usa Kamal em smarts e pickful, né? Deixa eu conferir aqueles."
Conferiu.
deploy.smarts.md — mesmo problema, registro A públicodeploy.pickful.ai (production), deploy.pickful.xyz (alpha), mais um deploy-test1.pickful.ai morto há muito tempo e um deploy.staging.yml apontando pra um domínio aposentado, blockgeek.comPickful era o mais bagunçado dos três porque tinha múltiplos destinations (production / alpha / test2) e bagagem histórica. O Claude varreu de passagem os destinations mortos de staging e test1 — não tinham mais razão de existir, eram só ruído.
Commits finais:
smarts 6482472 2026-04-27 16:20:31 Use private deploy.smarts alias instead of public deploy.smarts.md (#38)
how2claude ccc0344 2026-04-27 16:20:38 Use private deploy.how2claude alias instead of public deploy.how2claude.com (#13)
pickful e6bf9af 2026-04-27 16:20:45 Deploy config hygiene + privatize hostnames (#118)
Catorze segundos. Claro, isso é só o GitHub esvaziando uma fila de merge — o trabalho real ficou espalhado nas duas horas anteriores. Mas a forma efetiva foi: um achado, três repos consertados.
Se eu tivesse trabalhado sozinho, a versão realista é: conserto em how2claude, escrevo um TODO com "fazer smarts e pickful também", e vejo aquele TODO deitado na lista por três meses. Vivi exatamente essa sequência várias vezes.
Se você deploya com Kamal, Capistrano, ou qualquer ferramenta baseada em SSH:
config/deploy*.yml e dê grep em host: e servers:. Liste todos os hostnames que aparecem.dig +short em cada um. Qualquer um que retornar um IP de origem em vez de nada está vazando.deploy.<project>), e coloque o IP no /etc/hosts.echo "$IP deploy.<project>" | sudo tee -a /etc/hosts.Se seu time gerencia vários projetos com o mesmo padrão de infra, escreva um grep one-liner que varra todo deploy*.yml em todos os repos, em vez de checar um por um.
O Cloudflare não falhou. O Kamal não falhou. As duas ferramentas estavam fazendo exatamente o que tinham que fazer.
A lição é: valores padrão te enganam em silêncio. deploy.<seu-domínio>.com soa como um nome interno, mas o DNS não tem o conceito de "interno" — um registro A é um registro A, e uma vez publicado, ele é público. Um nome pode te dar a ilusão de privacidade, e aquele iconezinho de nuvem cinza no Cloudflare é só a versão visual da mesma ilusão: senta lá quietinho, sem aviso vermelho, mas o que ele tá te dizendo é "esse registro não passa por mim".
Deixe o Claude ler sua config de deploy uma vez. Ele não compartilha a ilusão.