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.

ComponenteVersão mínimaPara que serve
Servidor LinuxUbuntu 24.04 LTS ou Debian 12Sistema base com systemd
Nginx1.26 ou superiorServidor web e terminação TLS
OpenSSL3.0 ou superiorBiblioteca criptográfica (TLS 1.3)
Certbotversão mais recente (via snap)Cliente ACME da Let’s Encrypt
Nome de domíniocom registo DNS A/AAAAValidação do certificado
Acesso root/sudoobrigatórioEditar configurações e portas
Portas 80 e 443abertas na firewallHTTP-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.

ProtocoloEstado em 2026Ação recomendada
SSLv2 / SSLv3QuebradoDesativar sempre
TLS 1.0 / TLS 1.1Obsoleto (RFC 8996)Desativar
TLS 1.2Seguro com cifras AEADManter como mínimo
TLS 1.3Recomendado (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érioLet’s EncryptAutoridade paga (DV)Autoridade paga (OV/EV)
Preço anualGratuito10 a 60 euros100 a 400+ euros
Validade90 dias (auto)até 1 anoaté 1 ano
Tipo de validaçãoDomínio (DV)Domínio (DV)Organização / estendida
WildcardSim (DNS-01)SimSim
Automatização ACMETotalVariávelLimitada
Garantia / seguroNãoSimSim (valores altos)
Suporte dedicadoComunidadeSimSim

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 ufw e o grupo de segurança da nuvem.
  • Recarregar sem testar: editar a configuração e fazer reload sem nginx -t pode derrubar todos os sites do servidor por um erro de sintaxe.
  • HSTS preload prematuro: ativar preload antes 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-run nos testes.
  • Chave privada exposta: versionar privkey.pem num 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.

SintomaCausa provávelSolução
“Timeout during connect” na emissãoPorta 80 fechada ou DNS erradoAbrir porta 80, confirmar registo A com dig
“Connection refused” em HTTPSPorta 443 fechadaAbrir ‘Nginx Full’ no ufw e na nuvem
NET::ERR_CERT_COMMON_NAME_INVALIDCertificado não cobre o domínio usadoReemitir com todos os -d necessários
Aviso “conteúdo misto”Recursos carregados por HTTPMudar URLs internos para https:// ou //
“too many certificates already issued”Limite semanal da Let’s Encrypt atingidoEsperar uma semana ou usar staging
Cadeado parcial / nota B no SSL LabsTLS 1.0/1.1 ainda ativoDefinir ssl_protocols TLSv1.2 TLSv1.3
nginx: [emerg] cannot load certificateCaminho do certificado erradoConferir caminhos em /etc/letsencrypt/live/
Renovação automática falhaBloco da porta 80 removidoRestaurar location do acme-challenge
HSTS não aparece em respostas 404Falta a palavra-chave alwaysAdicionar 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

Fontes e leitura adicional