Conteúdos

Cloudflared Tunnel: publicar containers na internet sem uma VPS

Publicar uma aplicação na internet costumava significar contratar uma VPS, configurar um endereço IP, abrir as portas 80 e 443, instalar um proxy reverso e cuidar dos certificados. Esse modelo continua sendo válido, mas nem sempre faz sentido pagar por um servidor separado quando já tenho uma máquina própria capaz de executar os containers.

O Cloudflare Tunnel, executado pelo cloudflared, oferece outro caminho. Um agente instalado no meu servidor cria conexões de saída para a rede da Cloudflare e encaminha as requisições para uma aplicação local. Assim, consigo publicar um serviço usando meus próprios recursos, sem expor diretamente o endereço do servidor e sem abrir portas de entrada no firewall.

Como o Tunnel funciona

O cloudflared inicia o túnel a partir da rede onde a aplicação está executando. Do lado público, um hostname como app.exemplo.com é associado ao túnel. Quando alguém acessa esse endereço, a requisição chega à Cloudflare e é encaminhada pela conexão já estabelecida até o serviço local.

O servidor não precisa aceitar uma conexão nova da internet na porta 443. O processo do túnel faz conexões de saída, e o firewall pode continuar bloqueando o tráfego de entrada que não for necessário.

O caminho fica parecido com isto:

usuário -> Cloudflare -> túnel de saída -> cloudflared -> container

O container não precisa ser publicado com -p 8080:8080 no host. Se o cloudflared estiver na mesma rede Docker, ele pode acessar o serviço pelo nome do container ou do serviço no Compose.

Isso reduz a quantidade de componentes que preciso administrar. Ainda existe uma aplicação, um servidor, um container e um agente para atualizar, mas não preciso criar uma VPS apenas para ser a porta de entrada do serviço.

Quick Tunnel e túnel nomeado

Para um teste rápido, o cloudflared pode criar um endereço temporário:

cloudflared tunnel --url http://localhost:8080

Esse recurso é útil para uma demonstração ou para testar uma integração que precisa de uma URL pública. O endereço é temporário e não deve ser tratado como a forma de publicar um serviço de produção.

Para um serviço permanente, uso um túnel nomeado associado a um domínio sob administração da Cloudflare. O fluxo inclui autenticar a conta, criar o túnel e apontar o DNS:

cloudflared tunnel login
cloudflared tunnel create minha-aplicacao
cloudflared tunnel route dns minha-aplicacao app.exemplo.com

A configuração pode ser gerenciada pela conta ou por um arquivo local com as credenciais do túnel. Em ambos os casos, não versiono tokens, certificados ou arquivos de credenciais junto com o código da aplicação.

Publicando um container

Uma forma prática de manter o agente junto da aplicação é colocá-lo no mesmo docker compose. O serviço da aplicação fica acessível somente na rede interna, enquanto o cloudflared faz o encaminhamento:

services:
  app:
    build: .
    expose:
      - "8080"
    networks:
      - app-net

  cloudflared:
    image: cloudflare/cloudflared:latest
    restart: unless-stopped
    command: tunnel --no-autoupdate run --token ${CLOUDFLARED_TUNNEL_TOKEN}
    depends_on:
      - app
    networks:
      - app-net

networks:
  app-net:

Nesse exemplo, a aplicação precisa escutar em 0.0.0.0:8080 dentro do container, e o túnel deve apontar para http://app:8080. A diretiva expose documenta a porta para a rede interna sem publicá-la na interface do host.

O token vem de uma variável protegida, por exemplo em um arquivo .env que não entra no Git:

CLOUDFLARED_TUNNEL_TOKEN=token-fornecido-pelo-tunnel

Em produção, prefiro usar um gerenciador de segredos ou o mecanismo de credenciais da plataforma. O arquivo não deve ser incluído em uma imagem, em um log de CI ou em um exemplo público.

Para um arquivo de configuração local, o encaminhamento pode ser descrito assim:

tunnel: ID_DO_TUNNEL
credentials-file: /etc/cloudflared/ID_DO_TUNNEL.json

ingress:
  - hostname: app.exemplo.com
    service: http://app:8080
  - service: http_status:404

A regra final com 404 é importante. Ela evita que uma requisição para um hostname não previsto seja encaminhada por acidente para o primeiro serviço da configuração.

Por que fica mais barato

O Tunnel pode reduzir bastante o custo de publicar pequenos serviços porque aproveita um servidor que já existe. Não preciso contratar uma VPS para cada aplicação, reservar um IP público, manter um proxy reverso separado ou administrar certificados diretamente no host.

Também consigo publicar um painel interno, uma aplicação de homologação ou um serviço pessoal sem mover os dados para outra máquina. O deploy continua acontecendo no meu ambiente, com os volumes e os recursos que já administro.

Isso não significa custo zero em qualquer cenário. Ainda posso precisar de um domínio, de recursos de processamento e armazenamento, de backups e de um plano ou recurso específico conforme o uso. A Cloudflare também impõe limites e políticas que devem ser conferidos para cada aplicação. A economia vem principalmente de evitar uma infraestrutura pública adicional quando o servidor próprio já atende à demanda.

Segurança sem abrir mão da praticidade

A ausência de portas de entrada reduz a superfície de exposição, mas não substitui a segurança da aplicação. Um serviço publicado pelo Tunnel continua acessível pela internet e precisa ter autenticação, autorização, validação de entrada e atualizações.

Algumas medidas que considero essenciais são:

  • Não publicar portas do container no host quando o cloudflared pode usar a rede interna.
  • Permitir no firewall somente as conexões de saída necessárias ao túnel.
  • Usar HTTPS no hostname público e revisar a política de origem.
  • Proteger painéis administrativos com autenticação da aplicação e, quando possível, Cloudflare Access.
  • Guardar o token ou as credenciais do túnel fora do repositório.
  • Restringir a rede Docker do cloudflared aos serviços que ele realmente precisa alcançar.
  • Fixar versões de imagens e atualizar o agente de forma planejada.
  • Monitorar logs, disponibilidade, consumo e tentativas de acesso.
  • Fazer backup dos dados e ter um procedimento para recriar o túnel.

Eu também separo serviços públicos de interfaces administrativas. O fato de o agente conseguir chegar à aplicação não significa que ele deva conseguir alcançar todo o restante da rede ou todos os containers do servidor.

Deploy e manutenção

O Tunnel combina bem com um fluxo de deploy baseado em containers. A pipeline pode construir uma nova imagem, enviar o artefato ao servidor e reiniciar somente o serviço da aplicação. O cloudflared permanece conectado à rede interna e continua encaminhando para o nome do serviço.

Antes de trocar a versão, verifico se a aplicação responde localmente:

docker compose up -d app cloudflared
curl http://localhost:8080/health
docker compose logs --tail=100 cloudflared

Se a porta não for publicada no host, o teste local deve ser feito de dentro da rede do Compose ou por um endpoint de saúde apropriado. O importante é separar uma falha da aplicação de uma falha do túnel.

Também não uso latest como estratégia de atualização automática sem controle. Posso começar com essa referência para um exemplo, mas em produção prefiro fixar uma versão conhecida, testar a atualização e manter uma forma simples de voltar à imagem anterior.

Limitações e escolhas

O Tunnel não é a resposta para todos os serviços. Aplicações com requisitos específicos de latência, grande volume de tráfego, uploads pesados ou regras de compliance precisam ser avaliadas com mais cuidado. A requisição passa por uma camada adicional, e isso pode influenciar observabilidade, custos e comportamento.

Também continuo dependendo do servidor próprio. Se o host perder energia, o acesso à aplicação cai; se o link de internet ficar indisponível, o túnel não consegue sair. Por isso, backups, monitoramento e redundância continuam importantes mesmo quando não existe uma VPS.

Para testes, um Quick Tunnel é suficiente. Para produção, uso um túnel nomeado, domínio próprio, regras explícitas e um plano de atualização. Essa distinção evita transformar uma ferramenta excelente para experimentar em uma configuração frágil para manter um serviço importante.

Minha conclusão

O cloudflared Tunnel facilita publicar containers na internet usando servidores que já possuo. Em vez de contratar uma VPS para cada aplicação e abrir portas de entrada no firewall, mantenho o serviço na minha infraestrutura e estabeleço uma conexão de saída controlada.

Isso torna pequenos deploys mais simples e baratos. Consigo disponibilizar uma aplicação, um ambiente de homologação ou um serviço pessoal sem montar toda a infraestrutura pública que antes parecia obrigatória.

A economia só vale a pena quando vem acompanhada de segurança. Tokens protegidos, containers isolados, autenticação, atualizações, logs e backups continuam sendo responsabilidade minha. O Tunnel reduz a complexidade de publicar; ele não remove a necessidade de operar o serviço com cuidado.