Servir um site sobre HTTP simples deixou de ser uma opção em 2026. Os navegadores marcam qualquer página sem cadeado como “Não seguro”, o Google penaliza no ranking e qualquer pessoa na mesma rede consegue ler o tráfego em texto claro. A boa notícia: configurar HTTPS no Nginx com certificados gratuitos da Let’s Encrypt demora menos de 30 minutos e, feito corretamente, dá-lhe uma nota A+ no SSL Labs com TLS 1.3, HSTS e cabeçalhos de segurança modernos.
Este tutorial leva-o do servidor vazio até uma configuração de produção endurecida em 12 passos, com blocos de código prontos a copiar, exemplos de saída reais, armadilhas comuns e um guia de resolução de problemas. No fim tem um ficheiro de configuração completo do Nginx e ainda mostramos como ativar a troca de chaves pós-quântica que o Chrome e o Firefox já usam por predefinição.
Porque configurar HTTPS no Nginx em 2026
O HTTPS protege três coisas ao mesmo tempo: a confidencialidade (ninguém lê os dados), a integridade (ninguém os altera em trânsito) e a autenticidade (o utilizador sabe que fala com o servidor certo). Sem TLS, uma palavra-passe escrita num formulário viaja em texto claro por todos os routers entre o cliente e o servidor. Com TLS 1.3, esse mesmo tráfego fica cifrado com cifras autenticadas como a AES-256-GCM ou a ChaCha20-Poly1305.
A Let’s Encrypt mudou o jogo ao emitir certificados gratuitos e automatizados. A autoridade de certificação já passou a marca de vários milhares de milhões de certificados emitidos e, em 2025, anunciou duas alterações importantes: o fim das mensagens de aviso de expiração por email e o fim do suporte a OCSP, com migração para listas de revogação (CRL). Para si, isto significa uma coisa simples: automatize a renovação e não dependa de OCSP stapling como rede de segurança.
Os certificados da Let’s Encrypt são válidos por 90 dias. Esse prazo curto é intencional: limita a janela de exposição se uma chave for comprometida e obriga a automatizar. O certbot, o cliente oficial mantido pela EFF, trata da emissão e da renovação sem intervenção manual. Em 2025 a Let’s Encrypt começou também a oferecer certificados de vida curta (6 dias) e certificados para endereços IP, mas para a maioria dos sites o ciclo clássico de 90 dias com renovação automática continua a ser o caminho recomendado.
O Nginx é o servidor web ideal para este trabalho. É leve, rápido e processa milhares de ligações em simultâneo com baixo consumo de memória. Combinado com o TLS 1.3 (definido no RFC 8446), o aperto de mão (handshake) precisa de apenas uma ida e volta na rede, cortando a latência face ao TLS 1.2. O resultado é um site mais seguro e, ao mesmo tempo, mais rápido.
Como funciona o aperto de mão TLS 1.3
Perceber o que acontece nos bastidores ajuda a depurar quando algo falha. Quando um navegador abre https://exemplo.pt, cliente e servidor executam um aperto de mão (handshake) antes de trocar qualquer byte de conteúdo. No TLS 1.3, esse processo foi simplificado de forma radical face às versões anteriores e precisa de uma única ida e volta na rede (1-RTT), com suporte opcional a 0-RTT para sessões retomadas.
O cliente envia um ClientHello que já inclui a sua parte da troca de chaves de curva elíptica (key share), as cifras que suporta e a extensão SNI (Server Name Indication) a indicar qual o domínio pretendido. O SNI é importante quando vários sites partilham o mesmo IP: é assim que o Nginx sabe qual o certificado a apresentar. O servidor responde com o ServerHello, a sua key share, o certificado e uma assinatura que prova que detém a chave privada correspondente.
A partir das duas key shares, ambos derivam o mesmo segredo partilhado através de Diffie-Hellman de curva elíptica efémera (ECDHE). A palavra “efémera” é a chave da confidencialidade futura (forward secrecy): como cada sessão usa um par de chaves novo e descartável, comprometer a chave privada do servidor hoje não permite decifrar tráfego capturado no passado. É por isso que as cifras recomendadas começam todas por ECDHE. O TLS 1.2 também suporta ECDHE, mas o TLS 1.3 torna-o obrigatório e elimina as antigas trocas de chaves estáticas RSA, que não ofereciam forward secrecy.
Depois de derivado o segredo, todo o tráfego seguinte, incluindo o resto do próprio aperto de mão, fica cifrado. No TLS 1.3 isto significa que o certificado do servidor já viaja cifrado, melhorando a privacidade. O resultado prático é um aperto de mão mais rápido e mais privado, e uma das razões pelas quais migrar para HTTPS moderno no Nginx melhora o desempenho em vez de o degradar.
Pré-requisitos e versões necessárias
Antes de começar, confirme que tem os componentes abaixo. As versões indicadas são as referências estáveis para 2026; quando estiver na dúvida, instale a versão mais recente disponível no repositório da sua distribuição.
| Componente | Versão mínima | Para que serve |
|---|---|---|
| Servidor Linux | Ubuntu 24.04 LTS ou Debian 12 | Sistema base com systemd |
| Nginx | 1.26 ou superior | Servidor web e terminação TLS |
| OpenSSL | 3.0 ou superior | Biblioteca criptográfica (TLS 1.3) |
| Certbot | versão mais recente (via snap) | Cliente ACME da Let’s Encrypt |
| Nome de domínio | com registo DNS A/AAAA | Validação do certificado |
| Acesso root/sudo | obrigatório | Editar configurações e portas |
| Portas 80 e 443 | abertas na firewall | HTTP-01 e tráfego HTTPS |
Um requisito frequentemente esquecido: o seu domínio tem de apontar para o IP público do servidor antes de pedir o certificado. A Let’s Encrypt usa o desafio HTTP-01, que coloca um ficheiro temporário em /.well-known/acme-challenge/ e verifica-o através do seu domínio. Se o DNS ainda não propagou, a emissão falha. Verifique a resolução com dig +short exemplo.pt e confirme que devolve o IP correto.
Confirme também a versão do Nginx e do OpenSSL antes de avançar. O TLS 1.3 só funciona com OpenSSL 1.1.1 ou superior; com OpenSSL 3.x ganha acesso às cifras mais recentes e à troca de chaves híbrida pós-quântica que abordamos no fim.
nginx -v
# nginx version: nginx/1.26.2
openssl version
# OpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13)
dig +short exemplo.pt
# 203.0.113.10
Passo 1: Atualizar o sistema e instalar o Nginx
Comece sempre por atualizar os pacotes. Um sistema desatualizado é a forma mais comum de deixar uma porta aberta sem perceber. Em Ubuntu ou Debian, execute:
sudo apt update && sudo apt upgrade -y
sudo apt install nginx -y
Depois da instalação, o Nginx arranca automaticamente. Verifique o estado do serviço para confirmar que está ativo e a escutar na porta 80:
sudo systemctl status nginx
# ● nginx.service - A high performance web server and a reverse proxy server
# Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
# Active: active (running) since Sat 2026-03-14 10:22:01 WET; 5s ago
Abra o IP do servidor no navegador. Deve ver a página predefinida “Welcome to nginx!”. Se não vir, o problema está quase sempre na firewall (Passo 2) ou no facto de outro serviço já ocupar a porta 80. Use sudo ss -tlnp | grep ':80' para confirmar qual o processo que está a escutar nessa porta. Garanta ainda que o serviço arranca no boot com sudo systemctl enable nginx, embora os pacotes de Ubuntu e Debian já o façam por predefinição.
Passo 2: Configurar a firewall com ufw
O TLS não serve de nada se a porta 443 estiver fechada. Em Ubuntu, a forma mais simples de gerir a firewall é o ufw. O pacote do Nginx regista perfis prontos a usar. Ative a porta de SSH primeiro (caso contrário arrisca-se a perder o acesso ao servidor) e só depois o tráfego web.
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status
O perfil “Nginx Full” abre as portas 80 (HTTP) e 443 (HTTPS). Precisa das duas: a 80 serve para o desafio HTTP-01 da Let’s Encrypt e para o redirecionamento para HTTPS, e a 443 serve o tráfego cifrado. A saída esperada do comando de estado é:
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
Nginx Full ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Nginx Full (v6) ALLOW Anywhere (v6)
Se usar um fornecedor de nuvem como a OVH, a Hetzner ou a AWS, lembre-se de que existe muitas vezes uma firewall externa (security group) além do ufw. Tem de abrir as portas 80 e 443 nos dois sítios. Esta dupla camada é uma fonte clássica de frustração: o ufw diz que está tudo aberto, mas a ligação continua a falhar porque o grupo de segurança da nuvem bloqueia o tráfego.
Passo 3: Criar o server block do domínio
Antes de pedir o certificado, o Nginx tem de saber responder pelo seu domínio. Crie um ficheiro de configuração dedicado em /etc/nginx/sites-available/. Esta separação por ficheiros facilita a gestão de vários sites no mesmo servidor.
sudo mkdir -p /var/www/exemplo.pt/html
echo "<h1>Site servido por Nginx</h1>" | sudo tee /var/www/exemplo.pt/html/index.html
sudo nano /etc/nginx/sites-available/exemplo.pt
Coloque o seguinte conteúdo no ficheiro. Repare que, por agora, só configuramos o HTTP na porta 80. O certbot vai adicionar automaticamente a parte do HTTPS no passo seguinte.
server {
listen 80;
listen [::]:80;
server_name exemplo.pt www.exemplo.pt;
root /var/www/exemplo.pt/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Ative o site criando uma ligação simbólica para sites-enabled, teste a sintaxe e recarregue o Nginx. O comando nginx -t é o seu melhor amigo: corra-o sempre antes de recarregar, porque apanha erros de sintaxe que de outra forma derrubariam o servidor.
sudo ln -s /etc/nginx/sites-available/exemplo.pt /etc/nginx/sites-enabled/
sudo nginx -t
# nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo systemctl reload nginx
Passo 4: Instalar o Certbot da Let’s Encrypt
A EFF recomenda instalar o certbot através do snap, porque garante sempre a versão mais recente com as últimas correções de segurança e suporte aos protocolos ACME atuais. O pacote apt existe, mas costuma estar várias versões atrasado.
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
certbot --version
# certbot 3.x.x
Se preferir evitar o snap (por exemplo, em Debian minimal), pode instalar via apt com sudo apt install certbot python3-certbot-nginx -y. O fluxo dos passos seguintes é idêntico. A única diferença prática é que com o snap recebe atualizações automáticas do próprio certbot, o que é uma vantagem de segurança em servidores de produção que ficam meses sem manutenção manual.
O certbot usa o protocolo ACME para provar à Let’s Encrypt que controla o domínio. O método predefinido, HTTP-01, coloca um ficheiro num caminho conhecido e a autoridade verifica-o pela internet pública. Existe também o desafio DNS-01, útil para certificados wildcard, mas exige acesso à API do seu fornecedor de DNS e fica fora do âmbito deste tutorial básico.
Passo 5: Emitir o certificado TLS
Com o plugin de Nginx, a emissão é praticamente automática. O certbot lê os seus server blocks, identifica os domínios, obtém o certificado e edita a configuração para ativar o HTTPS. Execute:
sudo certbot --nginx -d exemplo.pt -d www.exemplo.pt
Na primeira execução, o certbot pede o seu email (para notificações urgentes, não comerciais) e que aceite os termos de serviço. A saída de sucesso tem este aspeto:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/exemplo.pt/fullchain.pem
Key is saved at: /etc/letsencrypt/live/exemplo.pt/privkey.pem
This certificate expires on 2026-06-12.
Deploying certificate
Successfully deployed certificate for exemplo.pt to /etc/nginx/sites-enabled/exemplo.pt
Congratulations! You have successfully enabled HTTPS on https://exemplo.pt
Repare nos ficheiros gerados. O fullchain.pem contém o seu certificado mais a cadeia intermédia, e o privkey.pem é a chave privada. Nunca partilhe nem versione a chave privada num repositório Git. O certbot guarda tudo em /etc/letsencrypt/live/ com ligações simbólicas que apontam sempre para a versão mais recente, o que torna a renovação transparente para o Nginx.
Abra agora https://exemplo.pt no navegador. Deve ver o cadeado fechado. Se clicar nele e inspecionar o certificado, verá que foi emitido por uma autoridade intermédia da Let’s Encrypt e que é válido por 90 dias. Parabéns: o site já está cifrado. Mas a configuração predefinida do certbot é apenas o ponto de partida. Os passos seguintes transformam-na numa configuração de produção endurecida.
Passo 6: Ativar TLS 1.3 e cifras seguras
O certbot ativa o TLS, mas convém afinar manualmente os protocolos e as cifras. O objetivo em 2026 é claro: ativar apenas TLS 1.2 e TLS 1.3, e desativar por completo o SSLv3, o TLS 1.0 e o TLS 1.1, que estão obsoletos desde o RFC 8996 (2021). A configuração de referência da Mozilla, no perfil “intermediate”, continua a ser o padrão da indústria.
Edite o ficheiro do site e ajuste o bloco do server que escuta na porta 443 (criado pelo certbot). Adicione ou substitua as diretivas TLS:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
Note que no TLS 1.3 as cifras são fixas pela própria norma (AES-128-GCM, AES-256-GCM e ChaCha20-Poly1305) e não são controladas pela diretiva ssl_ciphers. Essa lista aplica-se apenas ao TLS 1.2. A diretiva ssl_prefer_server_ciphers off deixa o cliente escolher, o que em 2026 é a recomendação porque os clientes modernos preferem ChaCha20 em dispositivos móveis sem aceleração AES por hardware.
| Protocolo | Estado em 2026 | Ação recomendada |
|---|---|---|
| SSLv2 / SSLv3 | Quebrado | Desativar sempre |
| TLS 1.0 / TLS 1.1 | Obsoleto (RFC 8996) | Desativar |
| TLS 1.2 | Seguro com cifras AEAD | Manter como mínimo |
| TLS 1.3 | Recomendado (RFC 8446) | Ativar e preferir |
Teste e recarregue. Sempre que mexer no ficheiro, corra sudo nginx -t && sudo systemctl reload nginx. O reload aplica a nova configuração sem cortar ligações ativas, ao contrário do restart.
Passo 7: Ativar HSTS e cabeçalhos de segurança
O HSTS (HTTP Strict Transport Security) instrui o navegador a só comunicar por HTTPS com o seu domínio, mesmo que o utilizador escreva http://. Isto bloqueia ataques de downgrade e de SSL stripping. Adicione o cabeçalho no bloco da porta 443:
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
O max-age de 63072000 segundos equivale a dois anos. A diretiva preload torna o domínio elegível para a lista de pré-carregamento dos navegadores, que aplica o HSTS antes mesmo da primeira visita. Cuidado: o preload é um compromisso sério. Se mais tarde quiser servir algo por HTTP, vai ter problemas, porque remover um domínio dessa lista demora semanas. Submeta-o em hstspreload.org só quando tiver a certeza de que todo o tráfego, incluindo subdomínios, será sempre HTTPS.
A palavra-chave always no fim de cada cabeçalho é essencial: garante que o cabeçalho é enviado mesmo em respostas de erro (como 404 ou 500). Sem ela, uma página de erro pode escapar sem o HSTS, abrindo uma pequena janela de ataque. Para um endurecimento mais profundo, considere ainda uma Content-Security-Policy (CSP), embora exija testes cuidadosos para não bloquear scripts legítimos do seu site.
Passo 8: Forçar o redirecionamento de HTTP para HTTPS
O certbot já costuma configurar o redirecionamento, mas vale a pena confirmar e perceber como funciona. O bloco da porta 80 deve apenas redirecionar tudo para HTTPS com um código 301 (permanente), exceto o caminho do desafio ACME, que tem de continuar acessível por HTTP para as renovações futuras.
server {
listen 80;
listen [::]:80;
server_name exemplo.pt www.exemplo.pt;
location /.well-known/acme-challenge/ {
root /var/www/exemplo.pt/html;
}
location / {
return 301 https://$host$request_uri;
}
}
O código 301 diz aos navegadores e motores de busca que a mudança é permanente, o que preserva o valor de SEO das ligações antigas. Evite o 302 (temporário) para este caso. Confirme o redirecionamento com curl:
curl -I http://exemplo.pt
# HTTP/1.1 301 Moved Permanently
# Location: https://exemplo.pt/
# Server: nginx/1.26.2
Repare que o redirecionamento usa $host em vez de codificar o domínio. Assim a mesma configuração serve exemplo.pt e www.exemplo.pt sem duplicar regras. Se quiser canonizar para uma das versões (por exemplo, sempre sem www), faça-o num server block separado para manter a lógica clara.
Passo 9: Configurar a renovação automática
Com certificados de 90 dias, a renovação automática não é opcional. Felizmente, a instalação via snap já cria um temporizador do systemd que tenta renovar duas vezes por dia. O certbot só renova de facto quando faltam 30 dias ou menos para a expiração, por isso pode correr com frequência sem sobrecarregar a Let’s Encrypt.
Verifique o temporizador e faça um teste de renovação a seco (dry run), que simula todo o processo sem gastar os limites de emissão:
sudo systemctl list-timers | grep certbot
# snap.certbot.renew.timer Sun 2026-03-15 03:14:00 WET ...
sudo certbot renew --dry-run
# Congratulations, all simulated renewals succeeded:
# /etc/letsencrypt/live/exemplo.pt/fullchain.pem (success)
Se o dry run passar, está tudo certo. Quando o certbot renova, recarrega o Nginx automaticamente através de um hook de deploy. Pode confirmar o hook em /etc/letsencrypt/renewal/exemplo.pt.conf. Caso tenha uma configuração personalizada, adicione um hook explícito com --deploy-hook "systemctl reload nginx" para garantir que o servidor passa a usar o certificado novo sem intervenção.
Uma boa prática extra: configure uma monitorização externa que o avise se o certificado se aproximar da expiração. Como a Let’s Encrypt deixou de enviar emails de aviso em 2025, a responsabilidade de vigiar passou inteiramente para si. Ferramentas gratuitas de uptime conseguem alertar quando faltam, por exemplo, 14 dias.
Passo 10: Testar a configuração no SSL Labs
Nunca confie numa configuração de TLS sem a testar de forma independente. O Qualys SSL Labs é a ferramenta de referência: faz dezenas de verificações e atribui uma nota de F a A+. Com os passos anteriores aplicados, deve obter A+.
Visite o SSL Labs e introduza o seu domínio, ou use a linha de comandos para uma verificação rápida com OpenSSL:
openssl s_client -connect exemplo.pt:443 -tls1_3 </dev/null 2>/dev/null | grep -E "Protocol|Cipher"
# Protocol : TLSv1.3
# Cipher : TLS_AES_256_GCM_SHA384
curl -sI https://exemplo.pt | grep -i strict-transport
# strict-transport-security: max-age=63072000; includeSubDomains; preload
Os pontos que o SSL Labs verifica e que esta configuração já cobre: protocolos modernos (sem TLS 1.0/1.1), cifras com confidencialidade futura (forward secrecy via ECDHE), HSTS ativo, e cadeia de certificados completa. Se receber menos do que A, o relatório indica exatamente o que falta, normalmente um protocolo antigo ainda ativo ou um cabeçalho HSTS em falta.
Passo 11: Limitar pedidos (rate limiting)
O TLS protege o tráfego, mas não trava ataques de força bruta nem inundações de pedidos. O Nginx tem rate limiting nativo através do módulo limit_req. Os ataques automatizados contra páginas de início de sessão e contra a interface de administração são uma constante; limitar a taxa de pedidos reduz drasticamente a superfície de abuso.
Defina uma zona de limite no bloco http (em /etc/nginx/nginx.conf) e aplique-a às rotas sensíveis:
# Dentro do bloco http { ... }
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/s;
# Dentro do server { ... } da porta 443
location /wp-login.php {
limit_req zone=login burst=10 nodelay;
try_files $uri $uri/ =404;
}
A configuração acima permite 5 pedidos por segundo por endereço IP, com uma rajada (burst) de 10 antes de começar a devolver erros 503. A zona de 10 MB guarda o estado de cerca de 160 000 endereços. Para um endurecimento mais forte contra força bruta na camada de rede, combine isto com o fail2ban, que bane IPs após várias tentativas falhadas (com valores predefinidos típicos de 5 tentativas, janela de 10 minutos e banimento de 10 minutos).
Não exagere nos limites: valores demasiado baixos bloqueiam utilizadores legítimos atrás de NAT corporativo, onde muitas pessoas partilham um IP. Comece conservador, observe os registos em /var/log/nginx/error.log e ajuste conforme o tráfego real.
Passo 12: O ficheiro de configuração completo
Eis a configuração final, juntando todos os passos. Use-a como ponto de partida para o seu site, substituindo exemplo.pt pelo seu domínio. Este é o projeto completo e funcional do tutorial.
# /etc/nginx/sites-available/exemplo.pt
# Bloco HTTP: desafio ACME + redirecionamento 301
server {
listen 80;
listen [::]:80;
server_name exemplo.pt www.exemplo.pt;
location /.well-known/acme-challenge/ {
root /var/www/exemplo.pt/html;
}
location / {
return 301 https://$host$request_uri;
}
}
# Bloco HTTPS endurecido
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name exemplo.pt www.exemplo.pt;
root /var/www/exemplo.pt/html;
index index.html;
# Certificados Let's Encrypt
ssl_certificate /etc/letsencrypt/live/exemplo.pt/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/exemplo.pt/privkey.pem;
# Protocolos e cifras (perfil Mozilla intermediate)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
# Cabeçalhos de segurança
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
location / {
try_files $uri $uri/ =404;
}
location /wp-login.php {
limit_req zone=login burst=10 nodelay;
try_files $uri $uri/ =404;
}
}
Depois de gravar, valide e recarregue uma última vez. Se o nginx -t reportar sucesso, tem uma configuração de produção pronta a servir tráfego cifrado com nota A+.
sudo nginx -t && sudo systemctl reload nginx
# nginx: configuration file /etc/nginx/nginx.conf test is successful
Dicas avançadas: troca de chaves pós-quântica
A ameaça dos computadores quânticos ao TLS é real a médio prazo, com o cenário “colher agora, decifrar depois” (harvest now, decrypt later) a preocupar quem protege dados de longa duração. A resposta da indústria já chegou ao TLS 1.3: a troca de chaves híbrida pós-quântica. O Chrome e o Firefox já usam por predefinição o esquema X25519MLKEM768, que combina a curva elíptica clássica X25519 com o algoritmo ML-KEM (Kyber), padronizado pelo NIST.
Se o seu Nginx estiver compilado com OpenSSL 3.5 ou superior (ou com uma versão recente da BoringSSL), pode ativar este grupo no servidor para que o aperto de mão fique resistente a ataques quânticos. A diretiva é:
ssl_ecdh_curve X25519MLKEM768:X25519:secp256r1;
Quando o cliente e o servidor suportam X25519MLKEM768, o segredo partilhado fica protegido contra um futuro adversário quântico, sem perder a segurança clássica do X25519. Esta é a forma mais simples de começar a transição pós-quântica no seu site hoje. Verifique a versão do OpenSSL antes: se a sua compilação não suportar o grupo, o Nginx falha a recarregar e basta remover a diretiva.
Outras otimizações que vale a pena considerar: ativar o HTTP/2 (já incluído no projeto completo com http2 on) para multiplexar pedidos numa só ligação, ou experimentar o HTTP/3 sobre QUIC se a sua versão de Nginx o suportar. O HTTP/3 reduz ainda mais a latência ao eliminar o bloqueio em cabeça de linha do TCP, embora exija abrir a porta 443 também em UDP na firewall.
Let’s Encrypt vale a pena face às autoridades pagas?
Uma dúvida comum de quem configura HTTPS pela primeira vez: se a Let’s Encrypt é gratuita, qual o sentido de pagar dezenas ou centenas de euros por ano a uma autoridade comercial? A resposta curta é que, para a maioria dos casos, não há sentido nenhum. A criptografia é idêntica e o cadeado no navegador é exatamente o mesmo. As diferenças estão na validação, no suporte e nalgumas funcionalidades de nicho.
| Critério | Let’s Encrypt | Autoridade paga (DV) | Autoridade paga (OV/EV) |
|---|---|---|---|
| Preço anual | Gratuito | 10 a 60 euros | 100 a 400+ euros |
| Validade | 90 dias (auto) | até 1 ano | até 1 ano |
| Tipo de validação | Domínio (DV) | Domínio (DV) | Organização / estendida |
| Wildcard | Sim (DNS-01) | Sim | Sim |
| Automatização ACME | Total | Variável | Limitada |
| Garantia / seguro | Não | Sim | Sim (valores altos) |
| Suporte dedicado | Comunidade | Sim | Sim |
A validação estendida (EV), que outrora mostrava o nome da empresa em verde na barra de endereço, perdeu praticamente todo o valor: os navegadores deixaram de a destacar visualmente há vários anos. Para um blogue, uma loja online ou uma API, a Let’s Encrypt cobre tudo o que precisa. As autoridades pagas continuam a fazer sentido sobretudo quando precisa de um seguro contratual associado ao certificado, ou de validação OV para cumprir requisitos específicos de um cliente empresarial.
Há ainda alternativas gratuitas à Let’s Encrypt que também falam ACME, como a ZeroSSL e a autoridade da Google. O fluxo com o certbot é semelhante, bastando apontar para um servidor ACME diferente. Ter mais do que uma opção de autoridade gratuita é saudável para a resiliência da web, mas para começar a Let’s Encrypt continua a ser a escolha mais simples e mais documentada.
Erros comuns e armadilhas a evitar
Mesmo um processo simples tem pontos onde é fácil tropeçar. Estas são as armadilhas mais frequentes ao configurar HTTPS no Nginx:
- DNS não propagado: pedir o certificado antes de o registo A apontar para o servidor causa a falha “Timeout during connect” no desafio HTTP-01. Espere a propagação e confirme com
dig. - Esquecer a porta 443 na firewall: o site funciona em HTTP mas o HTTPS dá timeout. Verifique o
ufwe o grupo de segurança da nuvem. - Recarregar sem testar: editar a configuração e fazer
reloadsemnginx -tpode derrubar todos os sites do servidor por um erro de sintaxe. - HSTS preload prematuro: ativar
preloadantes de garantir HTTPS em todos os subdomínios bloqueia o acesso e é difícil de reverter. - Atingir os limites da Let’s Encrypt: repetir emissões em testes esgota o limite de 5 certificados por domínio por semana. Use sempre
--dry-runnos testes. - Chave privada exposta: versionar
privkey.pemnum repositório ou dar-lhe permissões abertas anula toda a segurança. Mantenha as permissões restritas a root. - Cabeçalhos sem
always: sem essa palavra-chave, os cabeçalhos de segurança desaparecem nas respostas de erro. - Misturar conteúdo HTTP em página HTTPS: imagens ou scripts carregados por
http://geram avisos de “conteúdo misto” e quebram o cadeado.
Resolução de problemas (troubleshooting)
Quando algo corre mal, o registo de erros do Nginx em /var/log/nginx/error.log e os registos do certbot em /var/log/letsencrypt/letsencrypt.log são o primeiro sítio a consultar. Eis os problemas mais comuns e como os resolver.
| Sintoma | Causa provável | Solução |
|---|---|---|
| “Timeout during connect” na emissão | Porta 80 fechada ou DNS errado | Abrir porta 80, confirmar registo A com dig |
| “Connection refused” em HTTPS | Porta 443 fechada | Abrir ‘Nginx Full’ no ufw e na nuvem |
| NET::ERR_CERT_COMMON_NAME_INVALID | Certificado não cobre o domínio usado | Reemitir com todos os -d necessários |
| Aviso “conteúdo misto” | Recursos carregados por HTTP | Mudar URLs internos para https:// ou // |
| “too many certificates already issued” | Limite semanal da Let’s Encrypt atingido | Esperar uma semana ou usar staging |
| Cadeado parcial / nota B no SSL Labs | TLS 1.0/1.1 ainda ativo | Definir ssl_protocols TLSv1.2 TLSv1.3 |
| nginx: [emerg] cannot load certificate | Caminho do certificado errado | Conferir caminhos em /etc/letsencrypt/live/ |
| Renovação automática falha | Bloco da porta 80 removido | Restaurar location do acme-challenge |
| HSTS não aparece em respostas 404 | Falta a palavra-chave always | Adicionar always a cada add_header |
Para depurar a emissão sem gastar limites reais, use o ambiente de testes (staging) da Let’s Encrypt com a flag --staging. Os certificados de staging não são confiáveis pelos navegadores, mas validam todo o fluxo. Quando tudo funcionar, repita sem a flag para obter o certificado de produção. Se mudou de servidor e os certificados antigos ficaram para trás, pode forçar a reemissão com --force-renewal, mas use-o com parcimónia por causa dos limites.
Um erro subtil: depois de obter A+ no SSL Labs, alguns administradores notam que o site fica lento no primeiro acesso. A causa costuma ser a falta de cache de sessão TLS bem dimensionada. A diretiva ssl_session_cache shared:MozSSL:10m resolve, permitindo retomar sessões sem repetir o aperto de mão completo.
Perguntas frequentes
Os certificados da Let’s Encrypt são mesmo gratuitos e seguros?
Sim. São totalmente gratuitos e usam a mesma criptografia dos certificados pagos. A diferença está na validação: a Let’s Encrypt só faz validação de domínio (DV), não de organização (OV) nem estendida (EV). Para a esmagadora maioria dos sites, a validação de domínio é suficiente e os navegadores tratam o cadeado exatamente da mesma forma.
Com que frequência preciso de renovar o certificado?
Os certificados duram 90 dias, mas com a renovação automática via certbot não precisa de fazer nada manualmente. O temporizador do systemd verifica duas vezes por dia e renova quando faltam 30 dias ou menos. Faça um certbot renew --dry-run de vez em quando para confirmar que o automatismo continua saudável.
Devo usar TLS 1.2 ou TLS 1.3?
Ative os dois. O TLS 1.3 é mais rápido e mais seguro e deve ser a preferência, mas alguns clientes mais antigos ainda só falam TLS 1.2. Manter TLS 1.2 como mínimo garante compatibilidade sem comprometer a segurança, desde que use cifras AEAD com ECDHE. Desative tudo abaixo disso.
O HSTS pode trancar-me fora do meu site?
O HSTS normal não, porque pode sempre desativá-lo e esperar que o max-age expire. O perigo está no preload: uma vez na lista dos navegadores, voltar a servir HTTP torna-se impossível durante semanas. Só ative o preload quando tiver a certeza absoluta de que todo o domínio e subdomínios usarão HTTPS para sempre.
Preciso de chaves Diffie-Hellman personalizadas?
Já não. As cifras modernas recomendadas usam ECDHE (troca de chaves de curva elíptica), que não depende dos parâmetros DH clássicos. A antiga prática de gerar um ficheiro dhparam.pem de 2048 ou 4096 bits deixou de ser necessária para a configuração de referência intermediate da Mozilla em 2026.
Como ativo HTTPS para um certificado wildcard?
Os certificados wildcard (*.exemplo.pt) exigem o desafio DNS-01 em vez do HTTP-01, porque a Let’s Encrypt precisa de validar o controlo do DNS. Use certbot certonly --manual --preferred-challenges dns -d "*.exemplo.pt" ou, melhor, um plugin de DNS do seu fornecedor para automatizar a renovação.
O Nginx ou o Apache é melhor para terminação TLS?
Ambos suportam TLS 1.3 e Let’s Encrypt. O Nginx tende a ter melhor desempenho com muitas ligações simultâneas e um modelo de configuração mais limpo para reverse proxy. Para sites de alto tráfego e para servir conteúdo estático, o Nginx é normalmente a escolha mais eficiente.
Conclusão: um Nginx seguro em 30 minutos
Em 12 passos passou de um servidor sem cifra para uma configuração de produção com TLS 1.3, certificados gratuitos e renováveis da Let’s Encrypt, HSTS, cabeçalhos de segurança, rate limiting e até troca de chaves pós-quântica. A nota A+ no SSL Labs deixa de ser um luxo e passa a ser o ponto de partida.
O segredo de uma configuração TLS que dura é a automatização. Com a renovação tratada pelo certbot e uma monitorização externa para o avisar, o site mantém-se seguro sem trabalho manual. Reavalie a configuração de cifras uma ou duas vezes por ano, acompanhando a evolução do perfil intermediate da Mozilla, e estará sempre alinhado com as melhores práticas.
Se gere vários servidores, considere transformar este ficheiro de configuração num modelo reutilizável, por exemplo através de um snippet incluído com a diretiva include do Nginx. Assim, ajustes futuros às cifras ou aos cabeçalhos de segurança aplicam-se a todos os sites num único sítio, sem ter de editar cada server block. A combinação de TLS 1.3, Let’s Encrypt e Nginx é hoje a base padrão da web segura, e domina-la dá-lhe uma vantagem prática que se aplica a qualquer projeto, do blogue pessoal à API de produção.
Cobertura relacionada
- HTTPS e TLS: O que o Cadeado Protege (e o que Não Protege)
- Autenticação SSH com Chaves Ed25519: 12 Passos
- mTLS em Node.js: TLS 1.3 em 12 Passos
- Wireshark: Análise de Pacotes em 12 Passos
- Ciberataques em Portugal: 2.437/Semana
- Segurança Online Explicada: Guia Completo




