CTO no Integrar Plus • Publicado em 05 de October de 2026
Toda vez que uma equipe decide parar de pagar por serviços como ngrok ou Cloudflare Tunnels para expor ambientes locais, alguém sugere a mesma receita. A fórmula parece limpa: você pega uma VPS barata com IP público, coloca o Nginx na frente recebendo HTTPS e usa o comando ssh -R para encaminhar o tráfego direto para a porta do seu framework de desenvolvimento.
A ideia voltou ao debate público recentemente a partir de um artigo de Vincent Bernat sobre túneis HTTP usando ferramentas padrão do sistema operacional. Imediatamente a comunidade se dividiu em dois extremos previsíveis.
De um lado estão os puristas das redes domésticas que acham qualquer camada de túnel um exagero desnecessário. O argumento deles é que basta abrir portas 80 e 443 no roteador de casa, apontar um DNS dinâmico para o IP residencial e servir os arquivos diretamente. Do outro lado estão os defensores da infraestrutura moderna que sugerem adotar daemons especializados em túneis, como o projeto sish, ou protocolos experimentais ponto a ponto baseados em relays criptografados.
Eu discordo do primeiro grupo com veemência. Encaminhar portas no roteador de casa até a sua máquina de trabalho ignora a realidade de quem programa: redes com CGNAT onde você sequer recebe um IPv4 público válido, provedores que bloqueiam tráfego de entrada em portas baixas e a imprudência de colocar a máquina que contém suas chaves privadas e credenciais pessoais direto na linha de tiro da internet pública.
Ao mesmo tempo, instalar mais um binário intermediário em Go ou Rust na sua VPS apenas para gerenciar túneis adiciona dependência operacional que a maioria das equipes pequenas não quer manter. A abordagem de usar SSH e Nginx puros faz sentido na teoria, mas ela esconde armadilhas graves na implementação prática.
A configuração ingênua de um túnel SSH reverso com Nginx costuma mapear um subdomínio dinâmico para uma porta local na VPS. O Nginx faz o proxy reverso para 127.0.0.1:$porta, enquanto o desenvolvedor roda na sua máquina pessoal algo como:
ssh -N -R 8080:localhost:3000 [email protected]
O problema começa quando o Nginx aceita qualquer valor arbitrário de porta via cabeçalho ou subdomínio, ou quando a configuração do proxy encaminha requisições indiscriminadamente para o loopback da VPS. Se você tem um PostgreSQL ouvindo em 127.0.0.1:5432, um Redis em 127.0.0.1:6379 ou um daemon de monitoramento sem autenticação ouvindo em portas internas, um usuário externo mal-intencionado consegue varrer a sua VPS por dentro.
O túnel, criado para receber webhooks do Stripe ou testar uma tela no celular, transforma o Nginx em uma ferramenta de exploração interna. O tráfego externo ultrapassa qualquer firewall UFW ou regras de iptables configuradas para bloquear conexões vindas da interface pública, porque para o sistema operacional a requisição nasce dentro do próprio host.
Para evitar isso, o Nginx não pode permitir mapeamentos dinâmicos livres. Cada porta de túnel precisa de um bloco de servidor rígido ou de uma validação estrita com mapa explícito:
map $http_x_tunnel_token $backend_port {
default 0;
"dev-pedro-auth-9812" 8081;
"dev-ana-auth-4321" 8082;
}
server {
server_name ~^(?<subdomain>.+)\.tunnel\.seudominio\.com$;
location / {
if ($backend_port = 0) {
return 403;
}
proxy_pass http://127.0.0.1:$backend_port;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
}
Isso impede que alguém alterne portas para descobrir serviços internos rodando no servidor. Se a porta não estiver na lista permitida, a requisição é descartada antes de encostar na pilha TCP interna.
Outra fragilidade operacional comum é o ciclo de vida da conexão. Quando o desenvolvedor fecha a tampa do notebook ou cai o sinal de Wi-Fi, o processo do OpenSSH na VPS muitas vezes não encerra a conexão de imediato. A porta permanece presa no loopback do servidor por minutos até que os timeouts de keepalive identifiquem a perda de pacotes.
Se você tenta reconectar, o SSH falha com erro de porta já em uso. Pior ainda: se outra pessoa conectar logo em seguida com permissão de alocação de porta, ela pode herdar ou colidir com o túnel anterior, gerando roteamento incorreto de tráfego confidencial.
No arquivo /etc/ssh/sshd_config da VPS, ajustes agressivos de detecção de clientes mortos e restrições de permissão são indispensáveis:
Match Group devtunnels
AllowTcpForwarding remote
GatewayPorts no
X11Forwarding no
AllowAgentForwarding no
PermitTTY no
ForceCommand /bin/false
ClientAliveInterval 10
ClientAliveCountMax 3
A linha GatewayPorts no impede que o usuário force o SSH a escutar em interfaces públicas como 0.0.0.0, garantindo que o binding fique restrito a 127.0.0.1. A combinação de ClientAliveInterval 10 com ClientAliveCountMax 3 derruba sessões zumbis em trinta segundos após a queda de rede do desenvolvedor, liberando a porta sem exigir reinicialização manual de serviços.
Montar essa estrutura atende perfeitamente à demanda de testar webhooks locais, integrar APIs de pagamento em desenvolvimento ou demonstrar uma funcionalidade temporária para colegas sem pagar mensalidade em dólar. Eu utilizo esse padrão para testes rápidos com aplicações Rails, mantendo o controle das chaves e do domínio.
Ainda assim, existem limites técnicos claros. Essa solução não oferece console web com replay de requisições HTTP, que ferramentas proprietárias entregam prontas. Se o seu fluxo de depuração depende de inspecionar payloads brutos de webhooks com interface gráfica e reenviar requisições com um clique, você terá que implementar o log no próprio Nginx ou usar middlewares na aplicação de desenvolvimento.
A manutenção manual do mapeamento de portas e chaves públicas também se torna insustentável quando o time cresce além de três ou quatro engenheiros. Nesse estágio, o tempo gasto gerenciando arquivos de configuração do Nginx e atribuindo portas não compensa a economia da assinatura de um serviço gerenciado.
A solução própria com SSH e Nginx é barata e funciona com utilitários estáveis que já existem no Linux há décadas. Ela só deixa de ser vantajosa quando o desenvolvedor a trata como mero truque de linha de comando, esquecendo que expor tráfego externo para a memória local de uma máquina é uma decisão de segurança de rede.
CTO e arquiteto full stack especializado em Ruby on Rails, Vue.js, sistemas multi-tenant e infraestrutura distribuída.