Como colocar seu site no ar com o Cloudflare Tunnel, sem servidor, sem IP fixo e sem abrir portas

Published on: 2026-07-09
Post image
pt cloudflare cloudflare-tunnel cloudflared devops self-hosting networking web python nodejs

Você está com um site ou API rodando em localhost (seja Node, Next.js, Python, PHP, Go, o que for) e quer mostrar para o mundo — sem contratar servidor, sem abrir porta no roteador, sem IP fixo. O Cloudflare Tunnel resolve isso: ele cria uma conexão de saída (outbound) do seu computador até a rede da Cloudflare, e é a Cloudflare que passa a servir o seu site na internet, com HTTPS automático.

Este guia cobre os dois modos, do mais simples ao definitivo: o modo quick (um comando, endereço temporário, ótimo para testar) e o modo serviço (seu domínio próprio, sempre no ar, iniciando sozinho). Tudo com os comandos reais, exemplos em vários frameworks, e as referências da documentação no fim.

Como o Cloudflare Tunnel funciona

Diagrama: navegador acessa a Cloudflare, que fala com o cloudflared via conexão de saída, que serve o app local — sem portas de entrada abertas
O tráfego chega pela Cloudflare; o cloudflared mantém uma conexão de saída até a borda. Nenhuma porta de entrada é aberta na sua máquina.

O segredo está na direção da conexão. Um pequeno programa chamado cloudflared (o conector) roda na sua máquina e disca para fora, abrindo um túnel até a borda da Cloudflare. Quando alguém acessa o seu domínio, a Cloudflare recebe a requisição e a envia por esse túnel até o seu app local. Isso traz três ganhos diretos:

  • Nenhuma porta de entrada aberta. Como a conexão é só de saída, você não expõe o roteador nem precisa de IP público — menos superfície de ataque.
  • HTTPS de graça. O certificado e a criptografia ficam por conta da Cloudflare; o seu app pode continuar em http no localhost.
  • Sem depender do IP de casa. Trocou de rede, caiu a luz, mudou o IP? O túnel reconecta e o domínio continua o mesmo.

Antes de começar: instale o cloudflared

O conector é um binário único. Instale conforme o seu sistema:

# macOS (Homebrew)
brew install cloudflared

# Linux (Debian/Ubuntu) — após adicionar o repositório oficial da Cloudflare
sudo apt-get update && sudo apt-get install cloudflared

# Windows (winget)
winget install --id Cloudflare.cloudflared

# confirme que instalou
cloudflared --version

Prepare seu app (qualquer framework)

O túnel só entrega o que já está rodando localmente — então tanto faz a linguagem. Suba o seu servidor numa porta conhecida (nos exemplos, ajuste para a porta do seu stack):

# Node / Next.js (porta 3000)
npm run dev

# Python — FastAPI (Uvicorn)
uvicorn main:app --host 127.0.0.1 --port 8000

# Python — Django
python manage.py runserver 127.0.0.1:8000

# PHP (servidor embutido)
php -S localhost:8000

Dica: para o túnel, basta o app responder em 127.0.0.1 (localhost). Você não precisa expô-lo em 0.0.0.0 — quem fala com a internet é o cloudflared, não o seu servidor.

Modo Quick: o jeito mais rápido de mostrar seu site

O Quick Tunnel (ou TryCloudflare) é literalmente um comando. Ele não exige conta nem domínio — a Cloudflare gera um endereço aleatório em trycloudflare.com na hora:

# expõe o que está em localhost:8000 num endereço público temporário
cloudflared tunnel --url http://localhost:8000

No terminal, o cloudflared imprime uma URL parecida com https://algo-aleatorio.trycloudflare.com. Abra no navegador (ou mande para um cliente) e pronto: seu site local está na web, com HTTPS.

Quando o Quick Tunnel brilha: demonstração rápida, testar um webhook (Stripe, WhatsApp, GitHub) contra a sua máquina, mostrar um trabalho para um cliente em minutos. O porém é importante: o endereço é temporário e muda a cada vez que você reinicia o comando. Para algo fixo e sério, use o modo serviço.

Modo Service: seu domínio próprio, sempre no ar

Para ter o seu domínio (ex.: app.seudominio.com) apontando sempre para o mesmo túnel, cria-se um tunnel nomeado e o cloudflared roda como serviço do sistema (inicia junto com a máquina). Requisito: ter um domínio na Cloudflare (a zona precisa estar na sua conta).

Há dois caminhos para chegar lá, e ambos terminam no mesmo lugar. Escolha um.

Caminho A: pelo painel (published application)

Roteamento: hostname público app.seudominio.com passa pela Cloudflare e chega ao Service URL https://localhost:8000
Uma published application liga um hostname público (app.seudominio.com) ao serviço local (localhost:8000). O DNS é configurado automaticamente.

É o caminho visual, gerenciado pela nuvem (remotely-managed). No Zero Trust Dashboard, em Networks → Tunnels:

  • clique em Create Tunnel, escolha o conector cloudflared e dê um nome (ex.: Personal);
  • o painel mostra o comando de instalação do conector com um token — guarde esse token;
  • na aba do túnel, clique em Add route e escolha Published application;
  • preencha o Hostname (Subdomain + Domain, ex.: app + seudominio.com) e o Service URL (ex.: https://localhost:8000 ou http://localhost:8000). O Path é opcional (aceita regex — deixe vazio para casar tudo).

O DNS é criado sozinho. Falta só deixar o conector rodando como serviço, usando o token do painel:

# instala o cloudflared como serviço, com o token gerado no painel
sudo cloudflared service install SEU_TOKEN_DO_TUNNEL

O token fica no próprio painel, em Networks → Tunnels → seu tunnel → Add a replica → macOS (ou o sistema que você usa). A partir daí, app.seudominio.com serve o seu app local.

Caminho B: pela linha de comando (locally-managed)

Se você prefere versionar tudo em arquivo e não depender do painel, use o túnel gerenciado localmente. São quatro comandos e um arquivo:

# 1) autentica o cloudflared na sua conta (abre o navegador)
cloudflared tunnel login

# 2) cria o tunnel nomeado (gera um UUID e um arquivo de credenciais .json)
cloudflared tunnel create meu-site

# 3) aponta o DNS do hostname para esse tunnel
cloudflared tunnel route dns meu-site app.seudominio.com

# 4) roda o tunnel lendo o config.yml
cloudflared tunnel run meu-site

O config.yml (por padrão em ~/.cloudflared/config.yml) diz qual túnel usar e para onde mandar cada hostname. A regra final http_status:404 é um “pega-tudo” obrigatório para o que não casar:

# ~/.cloudflared/config.yml
tunnel: meu-site
credentials-file: /Users/voce/.cloudflared/UUID_DO_TUNNEL.json

ingress:
  - hostname: app.seudominio.com
    service: http://localhost:8000
  - service: http_status:404

Rodando como serviço (inicia sozinho e reconecta)

Notebook aberto (online), fechado (offline) e aberto de novo (reconectado) mantendo o mesmo domínio
Como serviço, ao fechar e reabrir o notebook o cloudflared reconecta sozinho e mantém o mesmo domínio.

Rodar como serviço é o que faz o túnel iniciar junto com a máquina e reconectar automaticamente. Instale-o assim:

# macOS / Linux — locally-managed (usa o seu config.yml)
sudo cloudflared service install

# ou, para tunnel do painel (remotely-managed), passando o token
sudo cloudflared service install SEU_TOKEN_DO_TUNNEL

Para iniciar e conferir o estado do serviço:

# macOS (launchd)
sudo launchctl start com.cloudflare.cloudflared
sudo launchctl print system/com.cloudflare.cloudflared   # procure: state = running

# Linux (systemd)
sudo systemctl start cloudflared
sudo systemctl status cloudflared

Para acompanhar a conexão (e as reconexões), os logs:

# macOS — saída e erros do serviço
tail -f /Library/Logs/com.cloudflare.cloudflared.out.log
tail -f /Library/Logs/com.cloudflare.cloudflared.err.log

# Linux — via journald
journalctl -u cloudflared -f

Insight sobre notebook que dorme. Se você fecha a tampa do MacBook, o Mac entra em repouso e o túnel fica temporariamente offline. Ao reabrir, a rede volta e o cloudflared reconecta sozinho, mantendo o mesmo domínio. Mensagens como context canceled e Retrying connection nos logs não significam que o túnel foi apagado — são só a queda durante o sono e a tentativa de reconexão. Não é preciso caffeinate nem impedir o repouso: como serviço, ele se recupera ao acordar.

Ajustes de proxy que evitam dor de cabeça

Expor o app pela Cloudflare adiciona um proxy na frente dele. Seja qual for o framework, dois cuidados evitam a maioria dos erros — abaixo, os casos mais comuns (o conceito vale igual para Express, Rails, Laravel e afins).

Django recusa hosts que não conhece e precisa saber que a conexão original era HTTPS:

# settings.py
ALLOWED_HOSTS = ["app.seudominio.com"]
CSRF_TRUSTED_ORIGINS = ["https://app.seudominio.com"]
# a Cloudflare termina o HTTPS; o Django reconhece pelo cabeçalho encaminhado
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

FastAPI/Uvicorn deve confiar nos cabeçalhos de proxy para gerar URLs e detectar HTTPS corretamente:

uvicorn main:app --host 127.0.0.1 --port 8000 --proxy-headers --forwarded-allow-ips="*"

Sobre o Service URL: como o seu app roda em texto puro no localhost, o mais comum é apontar para http://localhost:8000. Use https://localhost:8000 apenas se o seu servidor realmente fala TLS localmente (aí talvez precise ignorar a verificação do certificado no lado do túnel).

Vários apps num túnel só (ingress e paths)

Um túnel atende vários hostnames. Basta empilhar regras no ingress — a Cloudflare escolhe pela primeira que casar, de cima para baixo:

ingress:
  - hostname: app.seudominio.com
    service: http://localhost:8000
  - hostname: api.seudominio.com
    service: http://localhost:9000
  - service: http_status:404

No painel, o mesmo se faz com várias published applications. O campo Path aceita regex: deixe vazio para casar tudo, use blog para casar em qualquer parte do caminho, ^/api para casar por prefixo, ou \.(jpg|png|css|js)$ para casar por extensão.

Quick vs Service: qual usar

Comparação: Quick (URL aleatória trycloudflare.com, temporário, sem domínio, para testes) vs Service (seu domínio, permanente, inicia sozinho)
Quick para testar rápido; Service para colocar no ar de verdade, com o seu domínio.
  • Quick: um comando, sem conta nem domínio, URL aleatória em trycloudflare.com que muda a cada execução. Ideal para testes, demos e webhooks.
  • Service: túnel nomeado com o seu domínio, roda como serviço, inicia sozinho e reconecta. É o modo para qualquer coisa que precise ficar no ar.

Problemas comuns (troubleshooting)

  • 502 Bad Gateway. O túnel está no ar, mas o app não respondeu. Confira se o servidor está rodando na porta certa e se o Service URL bate (http vs https, porta correta).
  • Django: DisallowedHost. Falta o domínio público em ALLOWED_HOSTS (e o CSRF_TRUSTED_ORIGINS para formulários).
  • A URL do quick mudou. Comportamento esperado do Quick Tunnel — para endereço fixo, use o modo serviço.
  • context canceled / Retrying connection. A conexão caiu (repouso, troca de rede) e o cloudflared está reconectando — não é erro fatal.
  • Redirecionamento infinito ou mixed content. Ajuste o SECURE_PROXY_SSL_HEADER (Django) ou os --proxy-headers (Uvicorn) para o app entender que a origem era HTTPS.

Boas práticas e insights

  • Trate o token e as credenciais como senha. Não suba o token do painel nem o arquivo .json de credenciais para o Git.
  • Precisou invalidar? Use o Rotate token no painel — isso exige reinstalar o conector com o token novo.
  • Alta disponibilidade. Dá para rodar réplicas do mesmo túnel em máquinas diferentes; a Cloudflare balanceia entre elas.
  • Produção de verdade não é no seu notebook. Para algo que não pode cair, rode o cloudflared num servidor/VPS sempre ligado — o notebook é ótimo para dev e demos.
  • Mantenha o cloudflared atualizado (o conector aparece com a versão no painel) para ter as correções de reconexão e desempenho.

Conclusão

O Cloudflare Tunnel derruba a maior barreira de quem quer publicar um projeto: não é preciso servidor exposto, IP fixo nem abrir portas. Para testar em segundos, o modo quick resolve. Para colocar seu site ou API no ar com o seu domínio, de forma estável e com HTTPS, o modo serviço com uma published application é o caminho. Comece pelo quick para sentir o fluxo e, quando gostar, promova para serviço. 🚀

Referências bibliográficas