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.

Você vai aprender
  • 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

  1. O servidor gera um par de chaves: a privada, que nunca sai do servidor, e a pública, que vai no certificado.
  2. 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.
  3. 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

RequisitoComo conferir
Um domínio seu apontando para o IP público do servidordig +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 certocurl -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)
Servidor em casa, sem domínio?

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.

Também dá pelo apt

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 (-d de domain).
-d www.meusite.com.br
Outro nome no mesmo certificado. Repita -d para 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:

  1. Registrou uma conta no Let's Encrypt com seu e-mail (é opcional).
  2. Provou que o domínio é seu, pela porta 80.
  3. Salvou o certificado em /etc/letsencrypt/live/meusite.com.br/.
  4. Editou o server block do nginx para escutar na porta 443 e redirecionar HTTP para HTTPS.
  5. 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

FormaComandoQuando usar
Plugin do nginxsudo certbot --nginx -d DOMINIOSite no nginx: o mais simples
Só o certificadosudo certbot certonly --nginx -d DOMINIOVocê quer editar a configuração do nginx à mão
Webrootsudo certbot certonly --webroot -w /var/www/meusite -d DOMINIOOutro servidor web, ou o certbot não deve mexer na configuração
Standalonesudo certbot certonly --standalone -d DOMINIONão há servidor web; o certbot sobe um temporário na porta 80
Sem perguntassudo certbot --nginx --non-interactive --agree-tos -m EMAIL -d DOMINIOScripts 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
Não espere e-mail de aviso

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
Mais rápido ainda: o "snakeoil"

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

"Timeout during connect (likely firewall problem)"
$ 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.

"DNS problem: NXDOMAIN"
  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.

"too many failed authorizations recently"

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 certificado venceu

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

ComandoO que faz
sudo snap install --classic certbotInstala o certbot
sudo certbot --nginx -d DOMINIOPede o certificado e configura o nginx
sudo certbot certonly --webroot -w PASTA -d DOMINIOSó pede o certificado
sudo certbot certificatesLista certificados e validade
sudo certbot renew --dry-runTesta a renovação
sudo certbot renewRenova o que estiver perto de vencer
sudo certbot delete --cert-name DOMINIOApaga um certificado
openssl x509 -in CERT -noout -datesMostra a validade de um certificado
openssl s_client -connect DOMINIO:443 -servername DOMINIOMostra 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:

sudo certbot -d loja.com.br

2. Testar a renovação

Complete para simular a renovação sem pedir certificados de verdade:

sudo certbot renew

3. Ignorar o certificado no teste

Complete para o curl aceitar um certificado autoassinado:

curl https://localhost

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 DOMINIO pede, 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.