NoctisNode
← GuiasSelf-hosting2026-10-239 min

Caddy como reverse proxy no Docker: configuração com Compose e HTTPS automático

Rode o Caddy como reverse proxy no Docker: uma stack compose, uma rede compartilhada, reverse_proxy para os nomes dos serviços e HTTPS automático, além de quando as labels do caddy-docker-proxy ajudam.

Resposta curta: rode o Caddy num container próprio que publica as portas 80 e 443, conecte-o e os containers dos seus apps a uma rede Docker compartilhada e aponte `reverse_proxy` para o nome de cada serviço e sua porta interna (por exemplo `reverse_proxy app:3000`). O Caddy resolve o nome pelo DNS embutido do Docker e obtém automaticamente um certificado TLS para cada endereço de site.

Este guia mostra primeiro a abordagem com Caddyfile simples, depois a variante caddy-docker-proxy baseada em labels, e explica quando cada uma faz sentido num único VPS. Se você roda o Caddy direto no host em vez de no Docker, veja o guia básico de reverse proxy com Caddy.

Como as peças se encaixam

Só o container do Caddy publica portas para o mundo externo. Todo container de backend entra numa rede bridge definida pelo usuário (aqui chamada `web`) e expõe sua porta apenas nessa rede. O servidor DNS embutido do Docker, disponível em redes definidas pelo usuário, permite que o Caddy alcance `app:3000` pelo nome do serviço ou do container, então você nunca precisa fixar no código IPs de containers que mudam a cada recriação.

Manter os backends sem portas publicadas importa mais do que parece: o Docker escreve as próprias regras de iptables, então uma porta publicada com `ports:` pode ficar acessível pela internet mesmo quando o ufw diz que ela está bloqueada. Use `expose:` ou nenhum mapeamento de porta para tudo o que deve ficar atrás do proxy.

ComponenteFunçãoPublicado no host?
container caddyTerminação TLS, roteamento por hostname, redirecionamento de HTTP para HTTPSSim: 80/tcp, 443/tcp, 443/udp
rede webRede bridge compartilhada com DNS embutido para nomes de serviçoNão
containers dos appsSeus serviços (apps web, APIs, dashboards)Não, acessíveis só via Caddy
volume caddy_dataCertificados, chaves privadas, conta ACMENão, mas precisa persistir

Passo a passo: Caddyfile simples com docker compose

  1. 01.Aponte um registro A (e um AAAA, se você usa IPv6) de cada hostname para o VPS antes de iniciar o Caddy, ou a emissão do certificado vai falhar.
  2. 02.Crie a rede compartilhada uma vez: `docker network create web`.
  3. 03.Crie `/opt/proxy/compose.yaml` e `/opt/proxy/Caddyfile` como mostrado abaixo e rode `docker compose up -d` em `/opt/proxy`.
  4. 04.Conecte cada stack de app à rede externa `web` e inicie-a com `docker compose up -d`.
  5. 05.Acompanhe a emissão do primeiro certificado com `docker compose logs -f caddy` em `/opt/proxy`.
  6. 06.Depois de editar o Caddyfile, recarregue sem downtime: `docker compose exec -w /etc/caddy caddy caddy reload`.
# /opt/proxy/compose.yaml
services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"   # HTTP/3
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data      # certificates and ACME account keys
      - caddy_config:/config
    networks:
      - web

volumes:
  caddy_data:
  caddy_config:

networks:
  web:
    external: true

Conecte um app e escreva o Caddyfile

Cada stack de aplicação declara a mesma rede externa. O nome do serviço vira o hostname que o Caddy chama. O volume `caddy_data` é o que você nunca pode perder: apagá-lo obriga o Caddy a pedir todos os certificados de novo, o que pode esbarrar nos rate limits do ACME.

# /opt/app/compose.yaml
services:
  app:
    image: ghcr.io/example/app:latest
    restart: unless-stopped
    expose:
      - "3000"        # reachable on the network, NOT published on the host
    networks:
      - web

networks:
  web:
    external: true

# /opt/proxy/Caddyfile
{
	email [email protected]
}

app.example.com {
	reverse_proxy app:3000
}

grafana.example.com {
	reverse_proxy grafana:3000
}

api.example.com {
	reverse_proxy api-1:8080 api-2:8080 {
		lb_policy round_robin
		health_uri /healthz
		health_interval 10s
	}
}

Backends no Caddy: upstreams, balanceamento de carga e health checks

Na terminologia do Caddy, um backend é um upstream de `reverse_proxy`. Você pode listar vários upstreams numa só diretiva, escolher uma `lb_policy` como `round_robin`, `least_conn` ou `ip_hash` e adicionar health checks ativos com `health_uri` para que containers com falha saiam da rotação. Checks passivos (`fail_duration`, `max_fails`) também são úteis quando o app não tem endpoint de saúde.

Por padrão, o Caddy define `X-Forwarded-For`, `X-Forwarded-Proto` e `X-Forwarded-Host` nas requisições encaminhadas. Configure seu app para confiar na faixa de rede do proxy, para que ele veja o IP real do cliente e gere links `https://`. WebSockets e gRPC funcionam pelo `reverse_proxy` sem configuração extra; para gRPC em texto claro, use `reverse_proxy h2c://service:50051`.

Labels em vez de Caddyfile: caddy-docker-proxy

Quem procura um "Caddy proxy manager" geralmente quer o que o Nginx Proxy Manager oferece: adicionar um container e ganhar um hostname e um certificado sem editar um arquivo central. O Caddy não tem GUI oficial, mas o projeto comunitário caddy-docker-proxy (github.com/lucaslorentz/caddy-docker-proxy) gera o Caddyfile a partir das labels dos containers e recarrega o Caddy quando containers iniciam ou param.

Ele precisa de acesso de leitura ao socket do Docker, o que na prática equivale a root no host. Monte-o como somente leitura, mantenha a imagem do proxy atualizada e prefira o Caddyfile simples se você roda apenas alguns serviços.

services:
  caddy:
    image: lucaslorentz/caddy-docker-proxy:ci-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    environment:
      - CADDY_INGRESS_NETWORKS=web
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - caddy_data:/data
    networks:
      - web

  whoami:
    image: traefik/whoami
    networks:
      - web
    labels:
      caddy: whoami.example.com
      caddy.reverse_proxy: "{{upstreams 80}}"

volumes:
  caddy_data:

networks:
  web:
    external: true

Caddyfile simples vs caddy-docker-proxy

Caddyfile simplesLabels do caddy-docker-proxy
A configuração fica emUm único arquivo versionado no gitLabels espalhadas pelos arquivos compose
Acesso ao socket do DockerNão é necessárioObrigatório (sensível em segurança)
Novo serviçoEditar o Caddyfile, rodar `caddy reload`Adicionar labels, iniciar o container
Imagem`caddy:2` oficialImagem da comunidade baseada no Caddy
DepuraçãoLer o arquivo diretamenteInspecionar a configuração gerada nos logs
Ideal paraSetups de VPS pequenos e estáveisMuitos serviços efêmeros ou alterados com frequência

Rodando num VPS

Num VPS KVM da NoctisNode você tem root completo e um IPv4 dedicado, então publicar 80 e 443 a partir de um container Caddy e esconder todo o resto é simples. Um Wisp (1 vCPU, 1 GB de RAM) basta para o Caddy e alguns containers leves; stacks mais pesadas cabem no Pulse ou no Umbra. Os detalhes da emissão de certificados e os modos de falha estão em como funciona o HTTPS automático do Caddy, e o encaminhamento de TCP bruto ou SSH está em proxy TCP e SSH com Caddy. Proteja o SSH do host com o guia de hardening de SSH.

Perguntas frequentes

QComo faço o Caddy servir de reverse proxy para um container Docker?

AColoque o Caddy e o container na mesma rede Docker definida pelo usuário e use `reverse_proxy service-name:port` no Caddyfile. Não use `localhost`, porque dentro do container do Caddy ele se refere ao próprio Caddy.

QPor que o Caddy retorna 502 Bad Gateway para o meu container?

AGeralmente os containers não estão numa rede compartilhada, a porta está errada (use a porta interna do container, não uma porta publicada no host) ou o app escuta só em 127.0.0.1 dentro do container. Faça o app escutar em 0.0.0.0 e confira `docker network inspect web`.

QO caddy-docker-proxy é seguro?

AFunciona bem, mas exige o socket do Docker, que concede controle equivalente a root sobre o host. Monte-o como somente leitura, mantenha a imagem atualizada e evite expor o endpoint de administração do Caddy.

QOnde o Caddy guarda os certificados no Docker?

AEm `/data` dentro da imagem oficial, então monte um volume nomeado ali. Perdê-lo significa reemitir todos os certificados e possivelmente atingir os rate limits do ACME.

QExiste um Caddy proxy manager com interface web?

AO Caddy em si não tem interface web oficial; ele é configurado com Caddyfile, JSON ou pela API de administração. Ferramentas baseadas em labels, como o caddy-docker-proxy, oferecem um fluxo parecido de adicionar um container e pronto.

Caddy como reverse proxy no Docker: configuração com Compose e HTTPS automático · NoctisNode