Back to Learning Center
DevOps

Let's Encrypt Renewal Failed: Troubleshooting Guide

7 min read
Updated June 2026By CertNotify Team

Let's Encrypt certificates expire every 90 days. Certbot handles renewal automatically — until it doesn't. When renewal fails silently, you discover it when your site shows a certificate error to all visitors. Here's how to diagnose and fix every common failure scenario.

Run Renewal Manually First

Always start by running renewal manually to see the actual error:

Run as root / sudo
sudo certbot renew --dry-run

The --dry-run flag tests without actually renewing. Remove it for real renewal. Certbot's error output will tell you exactly what failed.

# Check renewal logs
sudo cat /var/log/letsencrypt/letsencrypt.log | tail -100

Error: Connection Refused / Port 80 Blocked

Error: Challenge failed for domain example.com Connection refused

The HTTP-01 challenge requires port 80 to be accessible from the internet. Check:

# Check if port 80 is listening
sudo ss -tlnp | grep :80
# Check firewall
sudo ufw status
sudo ufw allow 80/tcp

If you're using Cloudflare or a load balancer that strips port 80, switch to DNS-01 challenge (see below).

Error: ACME Challenge File Not Found

Error: 404 Not Found /.well-known/acme-challenge/xxxxx

The challenge file is created but your web server is not serving it. Common causes:

Web root mismatch:Ensure --webroot-path matches your actual web root (e.g., /var/www/html)
Nginx rewrite rules:Add an exception before catch-all rewrites: location ^~ /.well-known/acme-challenge/ { root /var/www/html; }
PHP/app catching all routes:Ensure /.well-known/ is excluded from application routing

Error: Rate Limit Exceeded

Error: too many certificates already issued

Let's Encrypt rate limits: 50 certificates per registered domain per week, 5 duplicate certificates per week. If you hit limits: wait until the limit resets, use the staging environment for testing (--staging flag), and avoid re-issuing when renewals will suffice.

Switch to DNS-01 Challenge

DNS-01 works even when port 80 is blocked, behind Cloudflare, or for wildcard certificates:

# Install Cloudflare DNS plugin (example)
sudo pip install certbot-dns-cloudflare
# Create credentials file
sudo mkdir -p /etc/letsencrypt/cloudflare
echo "dns_cloudflare_api_token = YOUR_TOKEN" | sudo tee /etc/letsencrypt/cloudflare/credentials.ini
sudo chmod 600 /etc/letsencrypt/cloudflare/credentials.ini
# Issue wildcard certificate
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini -d "*.yourdomain.com" -d "yourdomain.com"

Verify Auto-Renewal is Set Up

# Check if systemd timer is active (modern systems)
sudo systemctl status certbot.timer
# Or check cron
sudo crontab -l | grep certbot
# Manual cron entry if missing
0 3 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"

Renewal checklist:

Port 80 accessible from the internet (or DNS-01 configured)
Web root path matches actual document root
Systemd timer or cron job running certbot renew
Post-hook reloads web server after renewal
Monitoring alerts set up for 30 and 7 days before expiry

Don't rely on certbot alone

Certbot failures can be silent. Set up external certificate monitoring as a safety net. CertNotify checks your certificates every 24 hours and alerts you before expiry — independent of your renewal setup.