Containers Docker normalmente não lidam com SSL diretamente — um reverse proxy na frente encerra o TLS e encaminha o tráfego descriptografado para o container. Este guia cobre as três abordagens mais comuns.
Abordagem 1: Nginx reverse proxy com certificado manual
A abordagem mais simples para pequenos deployments. Obtenha um certificado do GetHTTPS e monte-o em um container Nginx.
docker-compose.yml
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./certs/fullchain.pem:/etc/ssl/fullchain.pem:ro
- ./certs/privkey.pem:/etc/ssl/privkey.pem:ro
depends_on:
- app
app:
image: your-app:latest
expose:
- "3000"
nginx.conf
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/ssl/fullchain.pem;
ssl_certificate_key /etc/ssl/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://app:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
Para renovar: Substitua os arquivos em ./certs/ com os novos do GetHTTPS, depois docker compose exec nginx nginx -s reload.
Abordagem 2: Traefik com Let’s Encrypt automático
O Traefik é um reverse proxy construído para containers. Ele pode obter e renovar automaticamente certificados Let’s Encrypt.
docker-compose.yml
services:
traefik:
image: traefik:v3.0
command:
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.email=you@example.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/acme/acme.json"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik-acme:/acme
app:
image: your-app:latest
labels:
- "traefik.http.routers.app.rule=Host(`yourdomain.com`)"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
- "traefik.http.services.app.loadbalancer.server.port=3000"
volumes:
traefik-acme:
O Traefik cuida de tudo: emissão do certificado, renovação e terminação HTTPS. Sem necessidade de gerenciamento manual de certificados.
Abordagem 3: Caddy (HTTPS com zero configuração)
O Caddy obtém e renova automaticamente certificados Let’s Encrypt com zero configuração.
docker-compose.yml
services:
caddy:
image: caddy:2
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
depends_on:
- app
app:
image: your-app:latest
expose:
- "3000"
volumes:
caddy-data:
Caddyfile
yourdomain.com {
reverse_proxy app:3000
}
Essa é toda a configuração. O Caddy obtém um certificado Let’s Encrypt e o renova automaticamente.
Qual abordagem escolher?
| Nginx + certificado manual | Traefik | Caddy | |
|---|---|---|---|
| Configuração | Média (config + arquivos de cert) | Média (labels) | Mínima |
| Renovação automática | ❌ (manual) | ✅ | ✅ |
| Flexibilidade | Alta | Alta | Média |
| Curva de aprendizado | Baixa (familiar) | Média | Baixa |
| Melhor para | Pequenos deployments, controle total | Containers dinâmicos, microsserviços | Sites simples, configuração mínima |
Renovando certificados no Docker
Abordagem 1 (Nginx + manual):
# Substitua os arquivos de cert no seu diretório local ./certs/
cp new-fullchain.pem ./certs/fullchain.pem
cp new-privkey.pem ./certs/privkey.pem
# Recarregue o Nginx dentro do container (sem necessidade de restart)
docker compose exec nginx nginx -s reload
Abordagem 2 (Traefik) e 3 (Caddy):
Automático — eles lidam com a renovação internamente. Os certificados são armazenados em volumes Docker (traefik-acme ou caddy-data) e persistem entre reinícios do container.
Docker Swarm: usando secrets
Para deployments em Docker Swarm, use Docker secrets em vez de bind-mounting dos arquivos de certificado:
# Criar secrets a partir dos seus arquivos de cert
docker secret create ssl_cert fullchain.pem
docker secret create ssl_key privkey.pem
# No docker-compose.yml (modo deploy)
services:
nginx:
image: nginx:alpine
secrets:
- ssl_cert
- ssl_key
configs:
- source: nginx_conf
target: /etc/nginx/conf.d/default.conf
secrets:
ssl_cert:
external: true
ssl_key:
external: true
Os secrets são montados em /run/secrets/ssl_cert e /run/secrets/ssl_key dentro do container — criptografados em repouso e em trânsito.
Erros comuns
Incorporar certificados em imagens Docker
# ❌ NUNCA faça isso
COPY fullchain.pem /etc/ssl/fullchain.pem
COPY privkey.pem /etc/ssl/privkey.pem
Certificados expiram a cada 90 dias. Incorporá-los na imagem significa reconstruir e reimplantar a cada 60 dias. Sempre monte certificados como volumes ou secrets.
Esquecer de expor a porta 80
A porta 80 é necessária para:
- Redirecionamento HTTP → HTTPS
- Challenge HTTP-01 do Let’s Encrypt (para renovação automática do Traefik/Caddy)
ports:
- "80:80" # Não esqueça disso
- "443:443"
Não persistir os dados ACME
Traefik e Caddy armazenam seus certificados Let’s Encrypt e chaves de conta em volumes. Sem persistência, eles solicitam novamente os certificados a cada reinício do container — e atingirão os limites de taxa:
volumes:
traefik-acme: # DEVE ser um volume nomeado, não anônimo
caddy-data:
Perguntas frequentes
Meu container de aplicação pode lidar com SSL diretamente?
Pode, mas não é recomendado. O padrão de reverse proxy (encerrar TLS na borda, encaminhar HTTP puro internamente) é padrão porque: a aplicação não precisa saber sobre certificados, a renovação não requer reinício da aplicação e você centraliza a configuração TLS.
Como lidar com SSL para múltiplos containers?
Com Traefik ou Caddy, adicione labels/config para cada serviço — eles obterão automaticamente certificados separados. Com Nginx, adicione múltiplos blocos server na configuração.
Devo usar GetHTTPS ou o ACME embutido do Traefik?
Use o ACME embutido do Traefik/Caddy para produção — ele lida com a renovação automaticamente. Use GetHTTPS quando você precisa de um certificado para a abordagem de Nginx reverse proxy (Abordagem 1) ou para ambientes onde o container não tem acesso direto à internet para challenges ACME.
Como montar certificados de forma segura no Docker?
Monte como somente leitura (:ro), use Docker secrets para a chave privada em modo Swarm e garanta que apenas o container do reverse proxy tenha acesso aos arquivos de certificado. Nunca incorpore certificados em uma imagem Docker — eles expirarão e você precisaria reconstruir.
Posso usar certificados GetHTTPS com Kubernetes?
Sim. Crie um Kubernetes TLS secret a partir dos seus arquivos de certificado GetHTTPS:
kubectl create secret tls my-tls-cert --cert=fullchain.pem --key=privkey.pem
Depois referencie-o no seu recurso Ingress. Para renovação automatizada no Kubernetes, considere o cert-manager com um ClusterIssuer Let’s Encrypt.