Ubuntu HTTPS (Let's Encrypt)
HTTPS é o HTTP com criptografia: é o que coloca o cadeado na barra do navegador. Para isso, o servidor precisa de um certificado, um documento digital que prova que ele é mesmo o dono do domínio. O Let's Encrypt emite certificados de graça, e o programa certbot pede, instala e renova tudo sozinho.
- O que é um certificado e por que o navegador confia nele.
- O que precisa estar pronto antes de pedir um certificado.
- Instalar o certbot e ativar HTTPS no nginx com um comando.
- Conferir e testar a renovação automática.
- Criar um certificado autoassinado para um laboratório sem domínio.
Esta aula continua Servidor Web (nginx). Os exemplos usam a máquina fictícia servidor e o domínio fictício meusite.com.br.
Conceito: o cartório da internet
- O servidor gera um par de chaves: a privada, que nunca sai do servidor, e a pública, que vai no certificado.
- Uma autoridade certificadora (CA), como o Let's Encrypt, confere que você controla o domínio e assina o certificado. É como um cartório reconhecendo firma.
- O navegador já vem com a lista das autoridades confiáveis. Quando recebe o certificado, confere a assinatura e mostra o cadeado.
Como o Let's Encrypt confere que o domínio é seu? No método mais comum (HTTP-01), ele pede para o certbot colocar um arquivo secreto no seu site e tenta baixá-lo pela internet, em http://meusite.com.br/.well-known/acme-challenge/…. Se conseguir, o domínio é seu.
Os certificados do Let's Encrypt valem 90 dias. Isso não é problema: o certbot renova sozinho.
Antes de começar: a lista de conferência
| Requisito | Como conferir |
|---|---|
| Um domínio seu apontando para o IP público do servidor | dig +short meusite.com.br mostra o IP do servidor |
| Porta 80 aberta para a internet (é por ela que o Let's Encrypt confere) | sudo ufw status e o redirecionamento de portas do roteador |
| Porta 443 aberta (é por ela que o HTTPS funciona) | sudo ufw allow 'Nginx Full' |
O site respondendo em HTTP com o server_name certo | curl -I http://meusite.com.br de outra rede |
$ dig +short meusite.com.br 203.0.113.10 « o IP público do servidor $ curl -I http://meusite.com.br HTTP/1.1 200 OK Server: nginx/1.28.3 (Ubuntu)
O Let's Encrypt não emite certificado para IPs internos (192.168.x.x) nem para nomes como meusite.local. Para laboratório, use o certificado autoassinado no fim desta aula.
Instalar o certbot
A forma recomendada pelos autores do certbot é o snap, que recebe atualizações mais rápido que o pacote do apt.
- sudo snap install
- Instala um pacote snap.
- --classic
- Dá ao snap acesso normal ao sistema. O certbot precisa disso para editar a configuração do nginx.
- certbot
- O pacote.
$ sudo snap install --classic certbot certbot 5.1.0 from Certbot Project (certbot-eff✓) installed $ sudo ln -s /snap/bin/certbot /usr/bin/certbot $ certbot --version certbot 5.1.0
O link em /usr/bin garante que o comando seja encontrado mesmo por scripts com PATH reduzido. A versão no seu servidor pode ser outra.
sudo apt install certbot python3-certbot-nginx funciona igual. Use um jeito só: ter os dois instalados causa confusão sobre qual está renovando.
Pedir o certificado e ativar o HTTPS
- sudo certbot
- O programa, como administrador (ele grava em
/etc). - --nginx
- Usa o plugin do nginx: faz a verificação e já edita o server block para usar o certificado.
- -d meusite.com.br
- Domínio do certificado (
-dde domain). - -d www.meusite.com.br
- Outro nome no mesmo certificado. Repita
-dpara cada um.
$ sudo certbot --nginx -d meusite.com.br -d www.meusite.com.br Saving debug log to /var/log/letsencrypt/letsencrypt.log Enter email address or hit Enter to skip. (Enter 'c' to cancel): ana@meusite.com.br - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please read the Terms of Service at: https://letsencrypt.org/documents/LE-SA-v1.5-February-24-2025.pdf You must agree in order to register with the ACME server. Do you agree? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Y Account registered. Requesting a certificate for meusite.com.br and www.meusite.com.br Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/meusite.com.br/fullchain.pem « o certificado Key is saved at: /etc/letsencrypt/live/meusite.com.br/privkey.pem « a chave privada This certificate expires on 2027-01-13. These files will be updated when the certificate renews. Certbot has set up a scheduled task to automatically renew this certificate in the background. Deploying certificate Successfully deployed certificate for meusite.com.br to /etc/nginx/sites-enabled/meusite Successfully deployed certificate for www.meusite.com.br to /etc/nginx/sites-enabled/meusite Congratulations! You have successfully enabled HTTPS on https://meusite.com.br and https://www.meusite.com.br
O certbot é em inglês. O que ele fez, em português:
- Registrou uma conta no Let's Encrypt com seu e-mail (é opcional).
- Provou que o domínio é seu, pela porta 80.
- Salvou o certificado em
/etc/letsencrypt/live/meusite.com.br/. - Editou o server block do nginx para escutar na porta 443 e redirecionar HTTP para HTTPS.
- Recarregou o nginx e deixou a renovação agendada.
Veja o que mudou no seu server block. As linhas novas terminam com # managed by Certbot:
server {
server_name meusite.com.br www.meusite.com.br;
root /var/www/meusite;
…
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/meusite.com.br/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/meusite.com.br/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
}
server {
if ($host = meusite.com.br) {
return 301 https://$host$request_uri; # quem chega por HTTP vai para HTTPS
} # managed by Certbot
listen 80;
server_name meusite.com.br www.meusite.com.br;
return 404; # managed by Certbot
}
Conferir
$ curl -I http://meusite.com.br HTTP/1.1 301 Moved Permanently « HTTP agora redireciona Location: https://meusite.com.br/ $ curl -I https://meusite.com.br HTTP/1.1 200 OK « e o HTTPS responde Server: nginx/1.28.3 (Ubuntu)
Formas diferentes de pedir o certificado
| Forma | Comando | Quando usar |
|---|---|---|
| Plugin do nginx | sudo certbot --nginx -d DOMINIO | Site no nginx: o mais simples |
| Só o certificado | sudo certbot certonly --nginx -d DOMINIO | Você quer editar a configuração do nginx à mão |
| Webroot | sudo certbot certonly --webroot -w /var/www/meusite -d DOMINIO | Outro servidor web, ou o certbot não deve mexer na configuração |
| Standalone | sudo certbot certonly --standalone -d DOMINIO | Não há servidor web; o certbot sobe um temporário na porta 80 |
| Sem perguntas | sudo certbot --nginx --non-interactive --agree-tos -m EMAIL -d DOMINIO | Scripts e automação |
Renovação automática
O snap do certbot instala um timer do systemd que tenta renovar duas vezes por dia. Só renova de fato quando faltam menos de 30 dias para vencer.
$ systemctl list-timers | grep certbot Thu 2026-10-15 21:42:00 -03 7h left Thu 2026-10-15 09:12:31 -03 5h ago snap.certbot.renew.timer snap.certbot.renew.service
Teste a renovação sem gastar nada (o --dry-run usa um servidor de testes do Let's Encrypt):
$ sudo certbot renew --dry-run Saving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Processing /etc/letsencrypt/renewal/meusite.com.br.conf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Simulating renewal of an existing certificate for meusite.com.br and www.meusite.com.br - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/meusite.com.br/fullchain.pem (success) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Se o teste passa, a renovação real vai funcionar. Veja seus certificados e as datas de validade:
$ sudo certbot certificates
Found the following certs:
Certificate Name: meusite.com.br
Domains: meusite.com.br www.meusite.com.br
Expiry Date: 2027-01-13 12:31:07+00:00 (VALID: 89 days)
Certificate Path: /etc/letsencrypt/live/meusite.com.br/fullchain.pem
Private Key Path: /etc/letsencrypt/live/meusite.com.br/privkey.pem
O Let's Encrypt parou de enviar e-mails avisando que o certificado vai vencer. Por isso, confira de vez em quando com sudo certbot certificates e mantenha o --dry-run passando.
Laboratório sem domínio: certificado autoassinado
Num laboratório (meusite.local, IP interno), você mesmo assina o certificado. A criptografia funciona igual, mas o navegador mostra um aviso, porque ninguém de confiança assinou.
- sudo openssl req
- Cria um pedido de certificado (request).
- -x509
- Em vez de pedido, gera direto um certificado assinado por você mesmo.
- -nodes
- "no DES": não protege a chave com senha (senão o nginx pediria senha ao iniciar).
- -days 365
- Validade: um ano.
- -newkey rsa:2048
- Gera uma chave nova, RSA de 2048 bits.
- -keyout … -out …
- Onde salvar a chave privada e o certificado.
- -subj "/CN=meusite.local"
- O nome do certificado (Common Name), sem fazer perguntas.
$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/meusite.key -out /etc/ssl/certs/meusite.crt -subj "/CN=meusite.local" ....+..+...+++++++++++++++++++++++++++++++++++++++*.+.....+....+......+++++++ ----- $ sudo openssl x509 -in /etc/ssl/certs/meusite.crt -noout -subject -dates subject=CN=meusite.local notBefore=Oct 15 13:20:11 2026 GMT notAfter=Oct 15 13:20:11 2027 GMT
Os + e . são só o progresso da geração da chave. Agora acrescente um bloco HTTPS ao site:
server {
listen 443 ssl;
server_name meusite.local;
root /var/www/meusite;
index index.html;
ssl_certificate /etc/ssl/certs/meusite.crt; # o certificado
ssl_certificate_key /etc/ssl/private/meusite.key; # a chave privada
}
$ sudo nginx -t && sudo systemctl reload nginx $ curl -I https://localhost -H "Host: meusite.local" curl: (60) SSL certificate problem: self-signed certificate « o curl não confia $ curl -k -I https://localhost -H "Host: meusite.local" HTTP/1.1 200 OK « com -k (ignorar), funciona
O Ubuntu já traz um certificado de teste gerado na instalação (pacote ssl-cert). No server block, troque as duas linhas ssl_certificate por include snippets/snakeoil.conf;.
Quando não funciona
$ sudo certbot --nginx -d meusite.com.br … Certbot failed to authenticate some domains (authenticator: nginx). The Certificate Authority reported these problems: Domain: meusite.com.br Type: connection Detail: 203.0.113.10: Fetching http://meusite.com.br/.well-known/acme-challenge/kM3…: Timeout during connect (likely firewall problem)
O que aconteceu: o Let's Encrypt não conseguiu chegar ao seu servidor pela porta 80.
Como confirmar: de outra rede (o 4G do celular), abra http://meusite.com.br.
Como resolver: libere a porta 80 no ufw, no firewall do provedor de nuvem e no redirecionamento de portas do roteador. Alguns provedores de internet residencial bloqueiam a porta 80.
Domain: meusite.com.br Type: dns Detail: DNS problem: NXDOMAIN looking up A for meusite.com.br - check that a DNS record exists for this domain
O que aconteceu: o domínio não aponta para lugar nenhum (o registro A não existe, ou ainda não se propagou).
Como resolver: crie o registro A no painel do seu domínio, espere alguns minutos e confira com dig +short meusite.com.br antes de tentar de novo.
O que aconteceu: você tentou muitas vezes com erro e bateu no limite de tentativas do Let's Encrypt.
Como resolver: espere (cerca de uma hora) e, enquanto ajusta, teste com --dry-run ou --staging, que usam o servidor de testes e não contam no limite.
O que aconteceu: a renovação automática falhou em silêncio (porta 80 fechada depois, configuração mudada…).
Como confirmar: sudo certbot renew --dry-run mostra o motivo. O log completo está em /var/log/letsencrypt/letsencrypt.log.
Como resolver: corrija o motivo e rode sudo certbot renew.
Referência rápida
| Comando | O que faz |
|---|---|
sudo snap install --classic certbot | Instala o certbot |
sudo certbot --nginx -d DOMINIO | Pede o certificado e configura o nginx |
sudo certbot certonly --webroot -w PASTA -d DOMINIO | Só pede o certificado |
sudo certbot certificates | Lista certificados e validade |
sudo certbot renew --dry-run | Testa a renovação |
sudo certbot renew | Renova o que estiver perto de vencer |
sudo certbot delete --cert-name DOMINIO | Apaga um certificado |
openssl x509 -in CERT -noout -dates | Mostra a validade de um certificado |
openssl s_client -connect DOMINIO:443 -servername DOMINIO | Mostra o certificado que o servidor entrega |
Exercícios
1. Pedir o certificado
Complete para pedir um certificado para loja.com.br e já configurar o nginx:
2. Testar a renovação
Complete para simular a renovação sem pedir certificados de verdade:
3. Ignorar o certificado no teste
Complete para o curl aceitar um certificado autoassinado:
4. Qual porta precisa estar aberta para o Let's Encrypt confirmar o domínio pelo método mais comum?
5. Você quer HTTPS num servidor de laboratório acessado como meusite.local. O que funciona?
Resumo
- Antes: domínio apontando para o servidor, portas 80 e 443 abertas, site respondendo em HTTP.
sudo certbot --nginx -d DOMINIOpede, instala e configura o redirecionamento.- Certificados valem 90 dias; o timer renova sozinho. Teste com
certbot renew --dry-run. - Sem domínio público, use certificado autoassinado (
openssl req -x509) e aceite o aviso do navegador.