HTTPS Gratuito com Certbot, Let's Encrypt e NGINX
Do HTTP para HTTPS em produção: como TLS funciona, configuração manual do NGINX como reverse proxy, Certbot automatizando certificados, renovação automática e hardening de SSL com headers de segurança.
Uma API sem HTTPS é uma API com senhas, tokens JWT e dados pessoais dos seus usuários trafegando em texto puro pela internet — interceptáveis por qualquer pessoa na mesma rede (ataques Man-in-the-Middle, especialmente em Wi-Fi públicos). Desde 2018, o Chrome marca sites HTTP como "Não Seguro". Desde 2023, o Google penaliza HTTP no ranking de busca. HTTPS não é opcional.
O Let's Encrypt fornece certificados TLS gratuitos e o Certbot automatiza todo o processo — geração, validação de domínio e renovação. Neste artigo vamos configurar o stack completo: NGINX como reverse proxy com SSL termination, Certbot para o certificado, renovação automática e hardening com headers de segurança HTTP.
Como TLS Funciona (Resumo)
TLS (Transport Layer Security) estabelece um canal criptografado entre cliente e servidor via handshake:
- Client Hello — cliente informa versões de TLS suportadas e algoritmos de criptografia
- Server Hello — servidor escolhe o algoritmo e envia o certificado (chave pública + identidade assinada por uma CA)
- Validação — cliente verifica que o certificado foi assinado por uma CA confiável (Let's Encrypt está na lista padrão de todos os navegadores)
- Troca de chave — cliente e servidor geram uma chave de sessão simétrica usando Diffie-Hellman
- Comunicação cifrada — todo o tráfego é criptografado com a chave de sessão
SSL Termination no NGINX significa que o NGINX lida com toda essa complexidade de TLS. Sua aplicação Node.js recebe as requisições já descriptografadas em HTTP simples — sem precisar gerenciar certificados.
Configuração Inicial do NGINX como Reverse Proxy
Antes de instalar o Certbot, configure o NGINX para servir seu domínio em HTTP. O Certbot precisa disso para validar que você controla o domínio:
server {
listen 80;
server_name api.seudominio.com;
# Logs por servidor virtual
access_log /var/log/nginx/api.seudominio.com.access.log;
error_log /var/log/nginx/api.seudominio.com.error.log;
location / {
proxy_pass http://localhost:3333;
proxy_http_version 1.1;
# Necessário para WebSockets funcionar através do NGINX
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
# Repassa headers originais para a aplicação Node.js
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;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_cache_bypass $http_upgrade;
}
}# Ativa o site criando um symlink
sudo ln -s /etc/nginx/sites-available/api.seudominio.com \
/etc/nginx/sites-enabled/
# Testa a configuração antes de recarregar
sudo nginx -t
# Recarrega o NGINX
sudo systemctl reload nginxInstalando o Certbot e Obtendo o Certificado
# Ubuntu 22.04+ — instalação via snap (recomendada pelo Let's Encrypt)
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# Obtém e instala o certificado automaticamente no NGINX
# O Certbot lê os server_name do NGINX, valida o domínio via HTTP challenge
# e modifica o arquivo de configuração com os certificados
sudo certbot --nginx -d api.seudominio.com
# Para múltiplos domínios no mesmo certificado (SAN):
sudo certbot --nginx \
-d api.seudominio.com \
-d painel.seudominio.comApós a execução, o Certbot modifica automaticamente o arquivo de configuração do NGINX:
server {
listen 443 ssl; # managed by Certbot
server_name api.seudominio.com;
ssl_certificate /etc/letsencrypt/live/api.seudominio.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/api.seudominio.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
proxy_pass http://localhost:3333;
# ... resto da configuração
}
}
# Redireciona HTTP para HTTPS — Certbot adiciona isso automaticamente
server {
listen 80;
server_name api.seudominio.com;
return 301 https://$host$request_uri;
}Renovação Automática
Certificados Let's Encrypt expiram em 90 dias. O Certbot instala automaticamente um timer systemd que tenta renovar certificados que vencem em menos de 30 dias:
# Verifica se o timer de renovação está ativo
sudo systemctl status certbot.timer
# Testa a renovação sem aplicar (dry-run)
sudo certbot renew --dry-run
# Se o timer não estiver ativo, configure um cron job:
# Adicione ao crontab (sudo crontab -e):
# 0 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"
# Roda todo dia às 3h da manhã. --quiet suprime output quando não há renovação.
# --post-hook recarrega o NGINX apenas quando um certificado foi renovado.Hardening: Headers de Segurança HTTP
TLS protege o transporte, mas há headers HTTP adicionais que reforçam a segurança na camada de aplicação. Configure no bloco http ou server do NGINX:
# Força HTTPS por 2 anos, inclui subdomínios, habilita preload
# CUIDADO: difícil de reverter. Não use em desenvolvimento.
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Impede que navegadores antigos adivinhem o MIME type
add_header X-Content-Type-Options "nosniff" always;
# Controla como a página pode ser embutida em iframes
# DENY: nenhum iframe permitido
add_header X-Frame-Options "DENY" always;
# Proteção XSS legacy (navegadores mais antigos)
add_header X-XSS-Protection "1; mode=block" always;
# Controle de referrer: não vaza URL de origem em requests cross-origin
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Content Security Policy — restringe fontes de scripts, estilos, imagens
# Ajuste conforme os domínios que sua aplicação usa
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'" always;
# Permissions Policy — desabilita features do browser não usadas
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;server {
listen 443 ssl;
server_name api.seudominio.com;
# Include dos headers de segurança
include /etc/nginx/snippets/security-headers.conf;
# SSL gerenciado pelo Certbot...
location / {
proxy_pass http://localhost:3333;
}
}Teste a configuração de segurança do seu servidor em securityheaders.com e ssllabs.com/ssltest. O SSL Labs dá um score de A a F baseado na qualidade da sua configuração TLS (versões suportadas, ciphers, vulnerabilidades). Com a configuração do Certbot padrão + options-ssl-nginx.conf, você deve obter A ou A+.
Lendo o IP Real do Usuário no Node.js
Com o NGINX como proxy, req.ip no Express sempre retorna 127.0.0.1 (o IP do NGINX). Para obter o IP real, configure o Express para confiar no proxy:
const app = express();
// Confia no primeiro proxy (o NGINX)
// Isso faz req.ip usar o header X-Forwarded-For enviado pelo NGINX
app.set('trust proxy', 1);
// Agora req.ip retorna o IP real do cliente
// Usado em rate limiting, logs de acesso, geolocalizaçãoConclusão
HTTPS com Let's Encrypt + Certbot leva menos de 10 minutos para configurar e é completamente gratuito. A renovação automática via systemd timer remove qualquer esforço de manutenção. Com os headers de segurança HTTP adicionados, sua aplicação está protegida não só no transporte (TLS) mas também contra ataques de browser (XSS, clickjacking, MIME sniffing). Execute o SSL Labs test após a configuração para confirmar o score A+.