Tutoriais de VPS
O que fazer quando a renovação do certificado Let's Encrypt falha no VPS (2026): checklist de certbot, Cloudflare, DNS-01 e porta 80
Os certificados Let's Encrypt têm validade de apenas 90 dias, e o certbot.timer pode parecer normal mesmo quando a renovação falha. Este artigo organiza um checklist de diagnóstico para falhas de renovação de certificados HTTPS em VPS nesta ordem: certbot renew --dry-run, porta 80, challenge do Nginx, proxy da Cloudflare, DNS-01, deploy hook e monitoramento de expiração.

A falha na renovação de um certificado Let's Encrypt normalmente não começa no dia em que ele vence.
Muitas vezes ela já falhou várias vezes muito antes, só que você não viu. Quando o navegador começa a avisar que o certificado expirou, os usuários não conseguem abrir o HTTPS, os callbacks de pagamento falham e os clientes de API retornam erros TLS, a falha já virou um incidente em produção.
O pior é que muitos usuários de VPS acham que, por terem instalado o certbot e terem certbot.timer no sistema, a renovação automática está garantida. Na prática, o timer só significa que ele vai rodar periodicamente, não que toda renovação vai dar certo.
Este artigo segue uma ordem de diagnóstico: primeiro confirmar quais certificados existem, depois rodar o dry-run, em seguida verificar a porta 80, o Nginx, a Cloudflare, o DNS-01, o deploy hook e o monitoramento.
Primeiro comando:
sudo certbot certificates
Observe:
- Certificate Name
- Domains
- Expiry Date
- Certificate Path
- Key Type
Se aqui o certificado mostrar que faltam só uns dez dias ou até poucos dias, não espere a renovação automática "se consertar sozinha". Rode o dry-run diretamente.
sudo certbot renew --dry-run
A documentação oficial do Certbot também recomenda usar o dry-run para testar o caminho de renovação automática. Ele percorre um processo de renovação simulado, sem substituir o certificado real, sendo o primeiro comando de diagnóstico mais seguro.
Se o dry-run der certo, pelo menos indica que o método de validação atual, a integração com o servidor web e o DNS ou challenge estão basicamente ok. Se falhar, continue investigando conforme a mensagem de erro.
Primeiro veja o timer:
systemctl list-timers | grep certbot
systemctl status certbot.timer
Depois veja os logs:
journalctl -u certbot --since "7 days ago" --no-pager
journalctl -u certbot.timer --since "7 days ago" --no-pager
Dependendo da forma de instalação, pode usar cron ou systemd timer. Você também pode verificar:
ls /etc/cron.d/
ls /etc/cron.daily/
Um erro comum é: o timer está ativo, mas toda execução falha; ou o sistema usa a versão snap do certbot, cujo local dos logs não é exatamente igual ao da versão instalada pelo gerenciador de pacotes. Não olhe só "se existe timer", olhe o dry-run e os logs.
O challenge HTTP-01 do Let's Encrypt acessa:
http://你的域名/.well-known/acme-challenge/<TOKEN>
A documentação oficial do Let's Encrypt deixa claro que o HTTP-01 só pode ser concluído na porta 80. Não é possível especificar 8080, 8888 ou qualquer outra porta.
Então você precisa confirmar:
- Os registros A / AAAA do domínio apontam para este VPS
- O security group / firewall do VPS libera a porta 80
- O Nginx/Apache escuta na porta 80
.well-known/acme-challenge/não está redirecionado ou bloqueado por engano- O proxy da Cloudflare não alterou o caminho de validação
Primeiro verifique de fora se a porta 80 está acessível:
curl -I http://example.com
Depois teste o caminho do challenge. Você pode criar temporariamente um arquivo de teste:
sudo mkdir -p /var/www/html/.well-known/acme-challenge
printf 'ok\n' | sudo tee /var/www/html/.well-known/acme-challenge/test
curl http://example.com/.well-known/acme-challenge/test
Se retornar ok, significa que esse caminho pelo menos é acessível pela internet pública. Apague após o teste:
sudo rm /var/www/html/.well-known/acme-challenge/test
Se não for acessível, continue verificando a configuração do Nginx e o firewall.
Muitos sites forçam o redirecionamento de HTTP para HTTPS:
return 301 https://$host$request_uri;
Isso normalmente não é problema; o Let's Encrypt consegue seguir um certo número de redirecionamentos HTTP/HTTPS. Mas se você redirecionar .well-known para o diretório errado, para uma página de login, para outro domínio, ou se o CDN/WAF retornar 403, vai falhar.
Recomenda-se reservar um caminho separado para o challenge:
server {
listen 80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
try_files $uri =404;
}
location / {
return 301 https://$host$request_uri;
}
}
Depois de alterar, teste primeiro:
sudo nginx -t
sudo systemctl reload nginx
Não reinicie diretamente. Deixe nginx -t passar primeiro e depois faça o reload.
Muitos sites em VPS ficam atrás da Cloudflare. A Cloudflare em si não é o problema, mas adiciona mais uma camada ao diagnóstico.
Armadilhas comuns:
- Após ativar o proxy nuvem laranja no registro DNS, as requisições de validação chegam primeiro à Cloudflare e depois à origem
- A porta 80 da origem não está aberta, mas o cache ou as regras da Cloudflare fazem o acesso superficial parecer normal
- WAF / Redirect Rule / Page Rule afetam
/.well-known/acme-challenge/ - O modo SSL da Cloudflare e o status do certificado da origem se misturam no diagnóstico
Se você usa HTTP-01, primeiro confirme que a porta 80 da origem é realmente acessível. Se necessário, você pode mudar temporariamente os registros relevantes para DNS only (nuvem cinza) para testar, ou passar para DNS-01.
Se o site fica atrás da Cloudflare a longo prazo, precisa de certificado wildcard ou não é conveniente abrir a porta 80, o DNS-01 costuma ser mais adequado.
O challenge DNS-01 do Let's Encrypt cria um registro TXT no DNS:
_acme-challenge.example.com TXT "..."
Ele é adequado para estas situações:
- Você precisa de um certificado wildcard
*.example.com - Não é conveniente abrir a porta 80 na origem
- O site está atrás da Cloudflare / de um proxy reverso
- Vários servidores compartilham o mesmo processo de certificado
Mas o problema central do DNS-01 é o tempo de propagação. Ver o registro TXT localmente não significa que o Let's Encrypt consiga vê-lo a partir dos nós de validação dele.
Você pode verificar assim:
dig TXT _acme-challenge.example.com @1.1.1.1
dig TXT _acme-challenge.example.com @8.8.8.8
Também pode consultar os NS autoritativos:
dig example.com NS +short
dig TXT _acme-challenge.example.com @ns1.example-dns.com
Se vários nameservers retornarem resultados inconsistentes, a renovação pode falhar de forma aleatória. Esse problema é comum em alguns provedores de DNS, DNS primário/secundário e cenários de atualização manual de registros TXT.
Ao usar um token de API de DNS, atenção às permissões:
- Dê apenas permissão de edição de DNS para a zona de destino
- Não coloque uma chave de API global no diretório raiz web
- Defina as permissões do arquivo de credenciais como 600
Por exemplo:
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
A documentação oficial do Let's Encrypt informa que o DNS-01 pode emitir certificados wildcard, enquanto o HTTP-01 não pode.
Então, se você quer:
*.example.com
Não fique mais quebrando a cabeça com a porta 80; você deve usar DNS-01.
Ao usar o plugin da Cloudflare, o processo geral é:
sudo apt install python3-certbot-dns-cloudflare
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d example.com \
-d '*.example.com'
Dependendo do sistema, da versão snap do certbot e dos diferentes pacotes de plugin DNS, os nomes podem variar. Antes de executar de verdade, verifique primeiro como o seu certbot atual está instalado:
which certbot
certbot --version
Há outro caso: o certbot renovou com sucesso, mas o Nginx não fez reload e continua servindo com o certificado antigo.
Primeiro veja a data de expiração do arquivo de certificado:
sudo openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -dates
Depois veja o certificado que realmente é retornado online:
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
Se o arquivo local é novo e o online ainda é o antigo, faça reload do serviço web.
sudo nginx -t
sudo systemctl reload nginx
Uma forma melhor é configurar um deploy hook para fazer reload automaticamente após uma renovação bem-sucedida:
sudo certbot renew --deploy-hook "systemctl reload nginx"
Você também pode colocar o hook em:
/etc/letsencrypt/renewal-hooks/deploy/
Atenção: o deploy hook só deve fazer ações leves e determinísticas, como reload do nginx. Não escreva scripts de deploy complexos dentro dele.
Depois de ver uma falha, algumas pessoas ficam rodando:
sudo certbot renew --force-renewal
Isso não é um bom hábito. O Let's Encrypt tem limites de taxa, e falhas repetidas podem impedir você de continuar emitindo por um curto período. Ao diagnosticar, priorize:
sudo certbot renew --dry-run
Se você precisa testar o processo com frequência, pode usar o ambiente staging para não consumir a cota de produção:
sudo certbot certonly --staging -d example.com
Quando a configuração estiver realmente corrigida, volte para o ambiente de produção.
Não dependa só do certbot. Pelo menos deve haver um lembrete externo ou local.
Verificação local simples:
DOMAIN=example.com
END_DATE=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN:443" 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
END_TS=$(date -d "$END_DATE" +%s)
NOW_TS=$(date +%s)
DAYS_LEFT=$(( (END_TS - NOW_TS) / 86400 ))
echo "$DOMAIN certificate expires in $DAYS_LEFT days"
Se faltar menos de 14 dias, você deve alertar. Em produção, recomenda-se mais o monitoramento externo, porque se o próprio DNS, a rede ou o agendamento de tarefas do VPS der problema, o script local também pode falhar junto.
Quando a renovação do Let's Encrypt falhar, siga esta ordem:
-
sudo certbot certificatesver certificados e datas de expiração -
sudo certbot renew --dry-runreproduzir o erro de renovação -
systemctl list-timers | grep certbotver as tarefas automáticas -
journalctl -u certbot --since "7 days ago"ver os logs - HTTP-01: confirmar que a porta 80 é acessível pela internet pública
- HTTP-01: confirmar que
/.well-known/acme-challenge/é acessível - Nginx: fazer reload após
nginx -t - Cloudflare: verificar nuvem laranja, WAF, Redirect Rule, modo SSL
- DNS-01: confirmar que o TXT aparece em vários resolvers e NS autoritativos
- Certificado wildcard: usar DNS-01, não HTTP-01
- Renovação bem-sucedida mas certificado antigo online: verificar deploy hook / reload
- Não repetir
--force-renewal; priorizar dry-run e staging - Configurar lembrete de expiração de 14 dias
Falha na renovação de certificado não é mágica. A maioria dos problemas cai em quatro categorias: as requisições de validação não chegam, o TXT do DNS não propagou, a renovação deu certo mas o serviço não fez reload, e ninguém monitora a data de expiração. Se você organizar o dry-run, o caminho do challenge, o DNS-01 e o deploy hook, o certificado HTTPS não vai te dar um susto a cada 90 dias.