SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-24

Instalar Certbot no nginx do Ubuntu 24.04

Veja como instalar o Certbot via apt ou snap, emitir o certificado com certbot --nginx e evitar o erro de renovação por timeout na porta 80.

Instalar o Certbot: apt ou snap

No Ubuntu 24.04, sudo apt install certbot python3-certbot-nginx instala um Certbot funcional que emite certificados Let's Encrypt reais e reconhecidos publicamente. A documentação oficial do Certbot recomenda o snap; a diferença é pequena: o snap acompanha as versões upstream, enquanto o pacote do repositório acompanha a versão incluída no LTS e recebe atualizações de segurança.

Escolha uma opção. Duas cópias do Certbot significam dois temporizadores de renovação a atuar sobre a mesma árvore /etc/letsencrypt. A cópia que foi esquecida é a que pode causar surpresas.

O método com apt:

sudo apt update
sudo apt install certbot python3-certbot-nginx

Isto instala /usr/bin/certbot, o plugin do nginx, um par certbot.service + certbot.timer e uma entrada /etc/cron.d/certbot que não executa nenhuma ação sob systemd.

O método com snap:

sudo apt remove certbot python3-certbot-nginx
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

O snap instala o seu próprio temporizador, snap.certbot.renew.timer. Remova o pacote apt antes de instalar o snap.

Depois disso, ambas as instalações funcionam da mesma forma. Por predefinição, o Certbot 2.x utiliza chaves ECDSA (P-256). Use --key-type rsa apenas com um cliente que não suporte ECDSA. Todo o estado fica em /etc/letsencrypt: archive/ contém os ficheiros reais das chaves e dos certificados, live/ aponta por symlink para os ficheiros atuais, renewal/ contém um ficheiro de configuração por certificado e accounts/ contém a chave da sua conta ACME.

O que o HTTP-01 faz realmente e por que a porta 80 não é opcional

O desafio HTTP-01 é um callback. Você pede à Let's Encrypt um certificado que cubra example.com; o serviço resolve o nome no DNS público, abre uma ligação à porta 80 no endereço encontrado e solicita http://example.com/.well-known/acme-challenge/<token>. O seu servidor responde com o conteúdo exato do token que o Certbot acabou de gravar no disco. Esse é todo o mecanismo. Daqui resultam três consequências, que explicam a maioria das emissões que falham.

  • A porta 80 tem de estar acessível a partir da Internet pública, não apenas a partir do seu portátil. Uma regra ufw, um grupo de segurança do fornecedor de cloud ou uma firewall da consola da VPS que abra apenas a porta 443 interrompe a emissão e todas as renovações futuras.
  • O DNS já tem de apontar para este servidor. O servidor de validação faz a sua própria resolução a partir do exterior; as suas entradas /etc/hosts e a cache do navegador não têm qualquer efeito sobre ele.
  • Se publicar um registo AAAA, o IPv6 será tentado primeiro. A Let's Encrypt tenta novamente por IPv4 quando a ligação IPv6 falha de imediato, mas um registo AAAA desatualizado que aponte para um host que aceita a ligação e serve outro conteúdo provoca uma falha definitiva.

Os redirecionamentos são permitidos: a validação segue um redirecionamento HTTP para HTTPS e não considera relevante que o certificado do outro lado esteja ausente, expirado ou seja autoassinado. O que não fará é começar noutro local que não a porta 80. O Certbot não tem uma implementação de TLS-ALPN-01, portanto “usar apenas a porta 443” não é uma alternativa.

Escolher um autenticador: --nginx, --webroot, --standalone

--nginx é a opção padrão correta quando o nginx já está em execução e já serve o domínio. O Certbot analisa a sua configuração, injeta temporariamente uma localização para o desafio, recarrega o nginx, valida o domínio e depois escreve as diretivas TLS no seu bloco de servidor. Não há indisponibilidade.

sudo certbot --nginx -d example.com -d www.example.com

Para execução por script, num servidor novo:

sudo certbot --nginx \
  -d example.com -d www.example.com \
  --agree-tos -m ops@example.com --no-eff-email \
  --redirect --non-interactive

--webroot é adequado quando não quer que o Certbot altere a configuração do nginx, por exemplo, quando esta é gerada a partir de um modelo, mantida no git ou aplicada com Ansible. O Certbot escreve apenas o ficheiro do desafio num diretório que já é servido pelo nginx.

sudo certbot certonly --webroot -w /var/www/example.com \
  -d example.com -d www.example.com \
  --deploy-hook "systemctl reload nginx"

--standalone é adequado quando não há nenhum serviço a escutar na porta 80: por exemplo, um servidor de correio, uma API que só aceita ligações na porta 443 ou um script de primeiro arranque executado antes de o nginx existir. O Certbot liga-se à porta 80 durante alguns segundos. Se o nginx estiver em execução, este método falha. Pare-o antes da execução e inicie-o depois:

sudo certbot certonly --standalone -d mail.example.com \
  --pre-hook "systemctl stop nginx" \
  --post-hook "systemctl start nginx"

Esses hooks ficam registados na configuração de renovação do certificado. Assim, a mesma paragem e o mesmo arranque ocorrem automaticamente durante a renovação.

Um bloco de servidor que funciona antes e depois de o certificado existir

O problema do ovo e da galinha: o nginx recusa arrancar com ssl_certificate a apontar para um ficheiro que não existe, e o Certbot não consegue validar enquanto o nginx está parado. Coloque primeiro o site a funcionar na porta 80.

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/example.com;
    index index.html;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/example.com;
        default_type "text/plain";
        try_files $uri =404;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

Execute sudo nginx -t && sudo systemctl reload nginx, confirme que curl -I http://example.com/ responde a partir de fora do servidor e, em seguida, emita o certificado. Depois:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/example.com;
        default_type "text/plain";
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

O prefixo ^~ na localização ACME é essencial: impede que o bloco return 301 intercepte o pedido de desafio. Manter essa localização na porta 80 permite que as renovações continuem a funcionar depois de o restante site aceitar apenas HTTPS.

Ambos os blocos acima servem ficheiros do disco. Se o nginx estiver, em vez disso, à frente de uma aplicação, location / passa a ser um bloco proxy_pass e o bloco de servidor do reverse proxy, linha a linha descreve os cabeçalhos de que essa aplicação precisa, enquanto a localização ACME e as diretivas TLS permanecem exatamente iguais.

A sintaxe do HTTP/2 depende da versão do nginx. Misturar as duas formas provoca um erro no arranque. O Ubuntu 24.04 inclui o nginx 1.24, que exige a forma na mesma linha, listen 443 ssl http2;. O Debian 13 inclui uma versão mais recente do nginx, que exige a diretiva http2 on; separada. Verifique primeiro nginx -v.

Aponte o nginx para live/, nunca para archive/. Os links simbólicos live/ são redirecionados em cada renovação. Um caminho fixo dentro de archive/ deixa o servidor preso a um certificado que expira sem ser substituído.

Wildcards exigem DNS-01, e DNS-01 exige um plugin

Um certificado wildcard (*.example.com) não pode ser validado através de HTTP-01, porque não existe um único hostname de onde obter um ficheiro. DNS-01 é o único caminho: prova que controla o domínio ao publicar um registo TXT _acme-challenge.example.com. O Certbot precisa de credenciais de API do seu fornecedor de DNS para fazer isso sem intervenção, e é para esse fim que existem os plugins dos fornecedores. O guia completo para certificados wildcard explica o funcionamento dos registos TXT e o problema da renovação no modo manual; segue uma versão curta para Cloudflare.

sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare

No caminho com apt, use sudo apt install python3-certbot-dns-cloudflare. Guarde as credenciais num ficheiro acessível apenas por root:

# /root/.secrets/cloudflare.ini
# then: sudo chmod 600 /root/.secrets/cloudflare.ini
dns_cloudflare_api_token = your_scoped_token_here

Limite o token a permissões para editar o DNS apenas nessa zona. É uma chave para o seu DNS; trate-a como tal.

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
  -d example.com -d '*.example.com'

Coloque o wildcard entre aspas para impedir que a shell faça a expansão de padrões. DNS-01 também resolve o que HTTP-01 não consegue: certificados para hosts sem a porta pública 80, um serviço interno, uma máquina acessível apenas através de uma VPN WireGuard auto-hospedada num VPS ou um painel de administração numa interface privada.

Renovação: os 90 dias, o timer, o deploy hook

Os certificados Let's Encrypt são válidos por 90 dias. O Certbot renova-os quando faltam menos de 30 dias para expirarem. Isto dá-lhe uma janela de 30 dias em que uma renovação com falha ainda é um problema corrigível, e não uma indisponibilidade. O Let's Encrypt já não envia mensagens de aviso de expiração. Ninguém o vai alertar, por isso a monitorização é agora da sua responsabilidade.

Verifique o timer instalado pelo seu sistema:

systemctl list-timers 'certbot*' 'snap.certbot*'
sudo certbot certificates

certbot renew percorre todas as configurações em /etc/letsencrypt/renewal/, ignora as que estão fora da janela de 30 dias e renova as restantes usando exatamente as flags da execução original. Por isso, a primeira execução é importante: é nessa execução que as opções ficam registadas.

Renovar o ficheiro no disco não altera nada por si só. O nginx continua a servir o certificado antigo que mantém em memória até receber uma instrução para recarregar a configuração. Configure um deploy hook uma vez:

sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/sh
set -e
nginx -t && systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Qualquer ficheiro executável em renewal-hooks/deploy/ é executado depois de qualquer renovação bem-sucedida. A flag --deploy-hook faz o mesmo para um certificado específico e guarda renew_hook = ... na respetiva configuração de renovação. certbot --nginx faz o reload por si; as configurações --webroot e --standalone não o fazem. A ausência de um hook é precisamente o motivo pelo qual um site pode servir um certificado expirado enquanto certbot certificates indica corretamente que existe um certificado novo. Qualquer outro serviço que leia o certificado durante o arranque precisa do mesmo hook. Uma aplicação contentorizada, como uma instalação do Nextcloud VPS com Docker, TLS e backups, também precisa de ter aqui configurado o seu próprio passo de reinício ou reload.

Testar a renovação de forma real

sudo certbot renew --dry-run

Isto executa o desafio completo no ambiente de staging da Let's Encrypt: o mesmo caminho de código, a mesma firewall, o mesmo DNS, sem consumir limites de frequência e sem escrever nada no disco. Se passar hoje, a renovação automática daqui a 60 dias também passará, desde que nada mude entretanto no servidor.

Um teste simulado não prova que o hook de reload é executado. O comportamento varia consoante a versão do Certbot. Teste essa parte manualmente: execute diretamente o script do hook, confirme que systemctl reload nginx é concluído com sucesso e verifique sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.

Os erros que você encontrará na prática

Could not bind to IPv4 or IPv6., --standalone enquanto o nginx já ocupa a porta 80. Use --nginx ou --webroot, ou pare o nginx durante a execução. Confirme qual processo ocupa a porta com sudo ss -lntp | grep ':80'.

Timeout during connect (likely firewall problem), o Let's Encrypt não conseguiu aceder à porta 80. Verifique de dentro para fora: sudo ufw status (abra-a com sudo ufw allow 'Nginx Full'), depois a firewall do próprio provedor do VPS e, por fim, o DNS. Teste a partir de um local que não seja o seu servidor: curl -sSv http://example.com/.well-known/acme-challenge/test. Um registo AAAA obsoleto produz esta mesma mensagem.

unauthorized :: Invalid response from http://example.com/.well-known/acme-challenge/xyz: 404, a porta 80 está acessível, mas o token não está a ser servido. O pedido chegou a outro bloco de servidor (verifique qual deles controla default_server), ou o diretório passado a -w não é o diretório servido pelo nginx. Crie um ficheiro em /var/www/example.com/.well-known/acme-challenge/test e tente obtê-lo externamente; se o resultado for 404, o certificado nunca foi o problema.

DNS problem: NXDOMAIN looking up A for example.com, o nome não é resolvido publicamente. Pode tratar-se de registos novos que ainda não foram propagados ou de um registo numa zona que o seu registrador não está a servir.

too many certificates already issued for: example.com, um limite de taxa, que é o limite atingido durante a depuração repetida. O Let's Encrypt limita os certificados duplicados, com exatamente o mesmo conjunto de nomes, a cinco por semana. Separadamente, permite 50 certificados novos por domínio registado por semana. Nada desbloqueia nenhum dos limites além do tempo. Faça a depuração no ambiente de staging com --dry-run.

nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": No such file or directory, o nginx está configurado para um certificado que nunca foi emitido ou que foi removido com certbot delete. Comente o bloco de servidor TLS, inicie o nginx, emita o certificado e restaure o bloco.

open() "/etc/letsencrypt/options-ssl-nginx.conf" failed, esse ficheiro é incluído no pacote do plugin do nginx. Numa máquina certonly sem python3-certbot-nginx, instale o plugin ou substitua a linha include pelas suas próprias definições ssl_protocols e ssl_ciphers.

Gerir isto em escala

Um certificado pode conter até 100 nomes, e um único certbot --nginx -d a.example.com -d b.example.com ... parece tentador, até que um registo DNS obsoleto falhe a validação e faça todos os outros nomes desse certificado falharem também. Certificados separados por site falham de forma independente, que é o comportamento pretendido num servidor que aloja mais do que alguns serviços. Quando ultrapassa um pequeno número de sites, uma porta de entrada com suporte para ACME compensa: um reverse proxy Traefik que executa várias aplicações com Docker Compose solicita e renova os certificados por si próprio, e o Certbot deixa de ser necessário. A escolha do proxy para essa porta de entrada é uma decisão à parte, e comparar Nginx com Caddy e Traefik depende sobretudo de quanto trabalho de certificados e de configuração por aplicação pretende delegar no proxy.

Faça uma cópia de segurança completa de /etc/letsencrypt, incluindo sudo tar -czf letsencrypt-$(date +%F).tar.gz -C /etc letsencrypt, com os links simbólicos intactos. Essa árvore contém accounts/, a chave da conta ACME, que não pode regenerar de forma idêntica. A migração para um novo VPS resume-se então a: sincronizar a árvore com -a, instalar o Certbot, apontar o DNS para o novo servidor e executar certbot renew --dry-run antes de fazer a mudança.

Se reconstruir o servidor ou mudar para uma nova versão LTS, o temporizador de renovação não será transferido. Depois de qualquer migração, restauração de um snapshot ou atualização da distribuição, execute systemctl list-timers 'certbot*' e um --dry-run. Ignorar este passo pode fazer com que um site fique indisponível 89 dias depois, às 3am, com um certificado que todos presumiam estar a ser renovado automaticamente.

Tudo isto pressupõe uma máquina que controla, com um IP público e a porta 80 aberta para a Internet: um VPS, por outras palavras. Os procedimentos acima são idênticos em qualquer uma dessas máquinas.

Os mesmos passos para certificados aplicam-se no Apache em vez do nginx e, quando não é possível utilizar um certificado público, um certificado autoassinado no Ubuntu permite proteger serviços internos.

FAQ

Preciso de ter a porta 80 aberta se o meu site só disponibiliza HTTPS?

Sim, para o desafio HTTP-01. O Let's Encrypt inicia sempre o pedido de validação na porta 80, e o Certbot não tem uma implementação de TLS-ALPN-01. Por isso, uma firewall que abre apenas a porta 443 bloqueia tanto a primeira emissão como todas as renovações automáticas seguintes. Um redirecionamento da porta 80 para HTTPS funciona; a validação segue-o. A única forma de omitir completamente a porta 80 é usar DNS-01 com um plugin do fornecedor.

apt ou snap: qual Certbot devo instalar para o nginx no Ubuntu 24.04?

Use apt. sudo apt install certbot python3-certbot-nginx disponibiliza o Certbot 2.9.0 no Ubuntu 24.04. Esta versão é suficientemente atual para tudo o que é apresentado neste guia, recebe correções de segurança através de unattended-upgrades e não requer snapd. Escolha snap apenas se precisar imediatamente da versão mais recente ou de um plugin DNS distribuído exclusivamente como snap. Em qualquer caso, escolha exatamente um: duas instalações significam dois temporizadores de renovação apontados para a mesma árvore /etc/letsencrypt, e a instalação esquecida é a que causa problemas.

O Certbot pode emitir um certificado wildcard para o nginx?

Apenas através de DNS-01. Um wildcard como *.example.com não tem um único nome de anfitrião a partir do qual seja possível obter um ficheiro de desafio. Por isso, --nginx, --webroot e --standalone estão todos excluídos. Instale o plugin do seu fornecedor DNS, coloque um token de API com permissões limitadas num ficheiro de credenciais acessível apenas por root e execute certbot certonly --dns-cloudflare -d example.com -d '*.example.com', colocando o wildcard entre aspas para impedir que o shell o interprete como um padrão glob.

Por que motivo o nginx continua a disponibilizar o certificado antigo depois de uma renovação bem-sucedida?

O nginx mantém o certificado em memória e não deteta o novo ficheiro no disco até recarregar a configuração. certbot --nginx faz o recarregamento automaticamente, mas --webroot e --standalone não o fazem. Por isso, uma renovação pode ser concluída com sucesso enquanto o navegador continua a ver um certificado prestes a expirar. Coloque um script executável em /etc/letsencrypt/renewal-hooks/deploy/ que execute nginx -t && systemctl reload nginx. O script será executado depois de cada renovação bem-sucedida.

certbot renew --dry-run garante que a renovação vai funcionar?

Na maioria dos casos. O comando executa o desafio real no ambiente de staging, usando a mesma firewall, o mesmo DNS e o mesmo caminho de código, sem consumir limites de frequência nem escrever dados no disco. Por isso, um resultado bem-sucedido confirma que a parte de rede está correta. No entanto, não confirma de forma fiável que o deploy hook é executado. Teste-o separadamente: execute o script do hook manualmente e verifique sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.