Caddy 2026: Reverse Proxy Automático com HTTPS para PME
O Caddy é o único servidor web que obtém e renova certificados TLS automaticamente via Let’s Encrypt sem configuração manual. Para uma PME portuguesa que precisa de expor vários serviços internos (Grafana, Nextcloud, API própria) num único servidor com HTTPS válido, o Caddy reduz a complexidade de Nginx + Certbot para um ficheiro de 10 linhas. Este artigo mostra como configurar reverse proxy, múltiplos domínios, rate limiting e boas práticas de segurança — tudo com configuração copy-paste (Caddy docs).
Neste artigo
- Entender o Caddy e o Reverse Proxy
- Pré-requisitos e Instalação
- Passo 1 — Configurar Caddy como Reverse Proxy Simples
- Passo 2 — Múltiplos Domínios e Subdomínios
- Passo 3 — HTTPS Automático com Let’s Encrypt
- Passo 4 — Rate Limiting e Protecção contra Abuso
- Passo 5 — Headers de Segurança e CORS
- Passo 6 — Logging e Monitorização
- Caddy vs Nginx — Quando Escolher Qual
- Erros Comuns
- Checklist Rápido de Verificação
1. Entender o Caddy e o Reverse Proxy
Um reverse proxy é um intermediário entre o utilizador (browser) e os serviços internos. Em vez de cada serviço ter a sua própria porta exposta (porta 3000 para Grafana, porta 8080 para API, porta 9000 para PHP), o reverse proxy recebe todo o tráfego na porta 443 (HTTPS) e encaminha para o serviço correcto baseado no domínio.
Analogia: um reverse proxy é como um porteiro de um edifício de escritórios. O visitante chega à porta principal (porta 443), diz para quem vai (“grafana.empresa.pt”), e o porteiro encaminha-o para a sala certa (porta 3000) sem o visitante saber onde fica a sala.
O Caddy diferencia-se do Nginx por automatizar completamente os certificados TLS. Com Nginx precisas de Certbot + cron + renovação manual. Com Caddy, escreves grafana.empresa.pt no ficheiro de configuração e ele obtém o certificado automaticamente (Caddy automatic HTTPS).
| Feature | Caddy 2 | Nginx + Certbot | Traefik |
|---|---|---|---|
| HTTPS automático | Nativo (Let’s Encrypt + ZeroSSL) | Requer Certbot + cron | Nativo |
| Configuração | Caddyfile (simples) | nginx.conf (complexo) | YAML/TOML (médio) |
| Performance | Alta (Go) | Muito alta (C) | Alta (Go) |
| API dinâmica | Sim (admin API) | Não (reload manual) | Sim |
| Tamanho binário | ~30 MB | ~5 MB | ~100 MB |
| Ideal para | PME, simples, HTTPS auto | Alto tráfego, tuning fino | Docker/K8s |
2. Pré-requisitos e Instalação
| Requisito | Detalhe |
|---|---|
| Servidor Linux | Ubuntu 22.04+, Debian 12+, RHEL 9+ |
| IP público | Necessário para HTTPS automático (Let’s Encrypt valida via HTTP-01) |
| Domínio configurado | Registo A a apontar para o IP do servidor |
| Portas 80 + 443 abertas | Let’s Encrypt usa a porta 80 para validação |
| RAM mínima | 256 MB (Caddy é leve) |
Instalar o Caddy nas principais distribuições:
Ubuntu/Debian:
curl -1sLf ‘https://dl.cloudsmith.io/public/caddy/stable/gpg.key’ | sudo gpg –dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf ‘https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt’ | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
O que cada linha faz:
debian-keyring+apt-transport-https— pré-requisitos para repositórios seguroscurl ... gpg.key— adiciona a chave GPG do repositório Caddy para verificar autenticidade dos pacotescurl ... debian.deb.txt— adiciona o repositório Caddy à lista de fontes do aptapt install caddy— instala o Caddy e regista o serviço systemd
Fedora/RHEL:
sudo dnf copr enable @caddy/caddy
sudo dnf install caddy
Arch Linux:
ℹ️ Nota: Se não tiveres curl instalado, usar wget -qO- URL como alternativa. Em sistemas minimalistas, apt install curl primeiro.
3. Passo 1 — Configurar Caddy como Reverse Proxy Simples
O Caddyfile é o ficheiro de configuração principal do Caddy. Fica em /etc/caddy/Caddyfile (Linux). A sintaxe é deliberadamente simples — cada bloco é um domínio.
Cenário: uma PME tem o Grafana a correr na porta 3000 e quer expô-lo em grafana.empresa.pt com HTTPS automático.
O que cada linha faz:
grafana.empresa.pt— domínio que o Caddy vai servir. Ao detectar um domínio válido, o Caddy obtém automaticamente o certificado TLSreverse_proxy localhost:3000— encaminha todo o tráfego recebido para o Grafana na porta 3000
Reiniciar o Caddy para aplicar a configuração:
sudo systemctl status caddy
Depois de reiniciar, abrir https://grafana.empresa.pt no browser. O Caddy já obteve o certificado e o Grafana está acessível com HTTPS válido — sem Certbot, sem cron, sem configuração manual de certificados.
4. Passo 2 — Múltiplos Domínios e Subdomínios
Uma PME típica tem vários serviços. Em vez de um servidor por serviço, o Caddy encaminha múltiplos domínios num único servidor.
O que cada bloco faz:
grafana.empresa.pt— encaminha para Grafana na porta 3000nextcloud.empresa.pt— encaminha para Nextcloud na porta 8080api.empresa.pt— encaminha para a API na porta 9000, injectando headersX-Real-IPeX-Forwarded-Forpara a API saber o IP real do cliente (não o IP do Caddy)empresa.pt— site principal na porta 80, com redireccionamento de/blog/*parablog.empresa.pt
Recarregar a configuração sem reiniciar o serviço (hot reload):
O reload aplica a nova configuração sem cortar ligações existentes — útil em produção.
5. Passo 3 — HTTPS Automático com Let’s Encrypt
O Caddy obtém certificados automaticamente quando detecta um domínio válido no Caddyfile. Por defeito usa Let’s Encrypt e ZeroSSL como autoridades certificadoras. Não precisa de Certbot.
Para forçar apenas Let’s Encrypt ou configurar email para notificações de expiração:
O que cada linha faz:
admin off— desliga a API admin do Caddy (boa prática de segurança em produção)email [email protected]— email registado com Let’s Encrypt para receber notificações de expiração- O bloco global
{ }no topo aplica configurações a todos os domínios
⚠️ Atenção
Se o domínio não estiver a apontar para o IP público do servidor, a validação HTTP-01 do Let’s Encrypt vai falhar e o Caddy não obtém o certificado. Verificar com dig grafana.empresa.pt antes de aplicar a configuração.
Usar o modo DNS-01 para validação
Se o servidor não tiver a porta 80 acessível (firewall restritivo), o Caddy pode validar via DNS-01 usando um plugin. Para Cloudflare:
xcaddy build –with github.com/caddy-dns/cloudflare
Depois no Caddyfile:
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
reverse_proxy localhost:3000
}
O dns cloudflare usa a API da Cloudflare para criar o registo TXT de validação automaticamente. Necessita de um API token da Cloudflare na variável de ambiente CLOUDFLARE_API_TOKEN (Cloudflare API tokens).
6. Passo 4 — Rate Limiting e Protecção contra Abuso
Para proteger serviços backend de sobrecarga, o Caddy suporta rate limiting via módulo nativo (Caddy 2.7+):
rate_limit {
zone api {
key {remote_host}
events 100
window 1m
}
}
reverse_proxy localhost:9000
}
O que cada parâmetro faz:
zone api— nome da zona de rate limiting (pode haver várias zonas)key {remote_host}— limita por IP do cliente. Alternativas:{http.request.header.Authorization}para limitar por tokenevents 100— máximo 100 pedidos por janelawindow 1m— janela de 1 minuto. Quando o cliente excede, recebe HTTP 429 (Too Many Requests)
Para bloquear IPs específicos ou path patterns suspeitos:
@blocked remote_ip 10.0.0.50 10.0.0.51
abort @blocked
@suspicious path /wp-admin* /xmlrpc.php /.env
respond @suspicious 403
reverse_proxy localhost:9000
}
@blocked— matcher que identifica IPs bloqueadosabort @blocked— fecha a ligação imediatamente (não envia resposta)@suspicious— matcher para paths conhecidos de probes/scannersrespond @suspicious 403— responde com 403 Forbidden
7. Passo 5 — Headers de Segurança e CORS
O Caddy pode injectar headers HTTP de segurança em todas as respostas:
header {
Strict-Transport-Security “max-age=31536000; includeSubDomains; preload”
X-Content-Type-Options “nosniff”
X-Frame-Options “SAMEORIGIN”
Referrer-Policy “strict-origin-when-cross-origin”
Permissions-Policy “geolocation=(), microphone=(), camera=()”
}
reverse_proxy localhost:3000
}
O que cada header faz:
Strict-Transport-Security— força o browser a usar HTTPS durante 1 ano. Previne downgrade attacksX-Content-Type-Options nosniff— impede o browser de adivinhar o MIME type (previne XSS via upload de ficheiros)X-Frame-Options SAMEORIGIN— impede que a página seja embebida num iframe de outro domínio (previne clickjacking)Referrer-Policy— controla quanto do Referer header é enviado para sites externosPermissions-Policy— desactiva APIs do browser que a aplicação não usa
Para configurar CORS numa API:
@cors header Origin api.empresa.pt
header @cors Access-Control-Allow-Origin “https://app.empresa.pt”
header @cors Access-Control-Allow-Methods “GET, POST, PUT, DELETE, OPTIONS”
header @cors Access-Control-Allow-Headers “Authorization, Content-Type”
@options method OPTIONS
respond @options 204
reverse_proxy localhost:9000
}
@cors— matcher que detecta o header OriginAccess-Control-Allow-Origin— permite apenas o domínio da aplicação frontendrespond @options 204— responde a preflight requests com 204 No Content
8. Passo 6 — Logging e Monitorização
O Caddy pode logar em JSON estruturado para integração com ELK, Loki ou Grafana:
logging {
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 10
roll_keep_for 720h
}
format json
}
}
grafana.empresa.pt {
log
reverse_proxy localhost:3000
}
O que cada parâmetro faz:
output file /var/log/caddy/access.log— escreve logs para ficheiroroll_size 100mb— rota o ficheiro quando atinge 100 MBroll_keep 10— mantém 10 ficheiros antigosroll_keep_for 720h— mantém ficheiros por 30 dias (720 horas)format json— logs em JSON para fácil parsinglog— ativa logging para o domínio (sem argumentos usa a config global)
Para ver logs em tempo real:
Para métricas do Caddy (Prometheus), ativar a API admin (remover admin off) e expor /metrics:
admin :2019
}
grafana.empresa.pt {
reverse_proxy localhost:3000
}
metrics.empresa.pt {
reverse_proxy localhost:2019
}
Depois configurar Prometheus para fazer scrape de https://metrics.empresa.pt/metrics (Caddy metrics).
9. Caddy vs Nginx — Quando Escolher Qual
| Critério | Caddy | Nginx |
|---|---|---|
| Simplicidade | Caddyfile de 5 linhas | nginx.conf de 50+ linhas |
| HTTPS auto | Nativo, zero config | Requer Certbot + cron |
| Performance | Alta (suficiente para PME) | Muito alta (tuning fino) |
| Comunidade | Crescente, menor | Enorme, documentação extensa |
| Módulos | Compile-time (xcaddy) | Dinâmicos |
| Ideal para | PME, protótipos, HTTPS sem dor | Alto tráfego, hosting, tuning |
| Configuração dinâmica | API REST | Reload manual |
| Suporte HTTP/3 | Nativo | Requer build especial |
Para uma PME com 5-10 serviços internos que precisa de HTTPS sem gerir certificados, Caddy é a escolha óbvia. Para um hoster com 1000+ domínios e necessidades de tuning fino de performance, Nginx continua a ser a referência (comparação Caddy vs Nginx).
10. Erros Comuns
| Problema | Causa | Solução |
|---|---|---|
| HTTPS não funciona, certificado não obtido | Domínio não aponta para o IP público | Verificar dig dominio.pt — o registo A tem de apontar para o servidor |
| Erro “too many redirects” | Backend já força HTTPS e o Caddy envia HTTPS | Adicionar header_up X-Forwarded-Proto https no reverse_proxy |
| WebSocket não funciona | Caddy não faz upgrade do protocolo por defeito | Adicionar reverse_proxy localhost:PORT { header_up Host {host} } — o Caddy 2.6+ faz auto-WebSocket |
| Porta 80 bloqueada pelo firewall | Let’s Encrypt não consegue validar HTTP-01 | Usar validação DNS-01 ou abrir porta 80 apenas para validação |
| Rate limit não funciona | Módulo rate_limit não incluído no binário | Compilar com xcaddy build --with github.com/caddyserver/caddy-ratelimit |
| Logs não aparecem | log não declarado no bloco do domínio |
Adicionar log dentro do bloco do domínio (não apenas no global) |
| Caddy não arranca após reload | Erro de sintaxe no Caddyfile | Correr caddy validate --config /etc/caddy/Caddyfile antes de reload |
| Certificado expirado | Caddy não consegue renovar (firewall/DNS) | Verificar journalctl -u caddy — procurar erros ACME. Renovar manualmente com caddy reload |
11. Checklist Rápido de Verificação
- [ ] Caddy instalado e a correr (
systemctl status caddy) - [ ] Caddyfile válido (
caddy validate --config /etc/caddy/Caddyfile) - [ ] Domínios a apontar para o IP público (
dig dominio.pt) - [ ] Portas 80 e 443 abertas no firewall
- [ ] HTTPS funciona no browser (cadeado verde)
- [ ] Headers de segurança presentes (ver com
curl -I https://dominio.pt) - [ ] Logs a escrever em
/var/log/caddy/access.log - [ ] Rate limiting configurado em APIs expostas
- [ ] Reload testado sem cortar ligações (
caddy reload) - [ ] Reinício do servidor — Caddy arranca automaticamente (
systemctl enable caddy)
Artigos Relacionados
- Tailscale vs WireGuard vs OpenVPN: Qual a Melhor VPN para PME em 2026 — VPN para acesso remoto aos serviços atrás do Caddy
- Nginx Reverse Proxy 2026 — Alternativa Nginx ao Caddy para alto tráfego
- Cloudflare Tunnel Zero Trust 2026 — Expor serviços sem IP público usando Cloudflare Tunnel
- Ransomware 2026: Backup Imutável 3-2-1 — Proteger os dados atrás do reverse proxy
- Zero Trust para PMEs 2026 — Modelo de segurança complementar ao reverse proxy
