SSL Auto Renewal Failed – Let's Fix It Now
SSL cert renewal fails because the validation check can't reach your server. Here's the real fix and why it works.
Yeah, SSL auto renewal failed. It happens. The email says validation failed and you're staring at a soon-expiring cert. Let's skip the panic and fix it.
The Immediate Fix
First, check if the renewal process can actually reach your server. This is the most common reason it fails. Run this command as root or with sudo:
certbot renew --dry-run
If that fails, you'll see an error like "Failed to connect to ... port 80" or "urn:ietf:params:acme:error:connection". The fix is to make sure port 80 (HTTP) and port 443 (HTTPS) are open from the internet. Most Let's Encrypt clients use HTTP-01 challenge by default, which means they need to connect to your server on port 80 and fetch a specific file from /.well-known/acme-challenge/ directory.
Here's what you do:
- Log into your server via SSH.
- Check your firewall:
sudo ufw statusorsudo iptables -L -n. Make sure port 80 and 443 are allowed. - If you're behind a router, check port forwarding. Your router must forward port 80 and 443 to the internal IP of your server.
- Restart your web server:
sudo systemctl restart nginxorsudo systemctl restart apache2. - Try the dry run again.
If the dry run passes, your auto renewal will work next time. The real problem was that the cert validation server couldn't reach your machine.
Why This Fix Works
Let's Encrypt uses ACME protocol. When you request a cert renewal, the client (certbot) tells Let's Encrypt to verify you own the domain. For HTTP-01 challenge, Let's Encrypt checks if a special file exists at http://yourdomain.com/.well-known/acme-challenge/<token>. If port 80 is blocked, this check times out. The fix opens that port so the validation can happen.
What's actually happening here is that the renewal cron job runs but the network path isn't ready. The cron job doesn't fail because of a bug – it fails because the server isn't reachable. So opening port 80 is the real fix in 90% of cases.
Less Common Variations
DNS-01 Challenge
If you're using wildcard certs, you probably use DNS-01 challenge. That one checks a TXT record in your DNS zone. The fix there is different: you need your DNS provider's API credentials set up correctly in certbot. The error usually says "No TXT record found" or "DNS query failed." Check your DNS provider's docs for API key setup. For Cloudflare, you need a Global API Key or API token with DNS edit permission. For Namecheap, get your API key from your account settings.
TLS-ALPN-01 Challenge
This one requires port 443 and a specific ALPN protocol. It's rare but happens with some setups like HAProxy or custom backends. The error looks like "TLS ALPN negotiation failed." Fix: make sure your server supports TLS-ALPN-01. Most web servers do by default. If not, switch to HTTP-01 in your certbot config.
Renewal Timeout
Sometimes the renewal process just hangs and times out. This happens when the server is slow or overloaded. The fix: check your server load with top or htop. If it's at 100%, wait or upgrade. Also check the cron job runs at a sane time – not during peak hours. Set it to run at 3 AM.
Prevention – Stop It From Happening Again
You don't want this email next month. Here's what I do:
- Set up a monitoring check that tests port 80 and 443 from outside. Use a free service like UptimeRobot or a simple curl from another server.
- Add a cron job that runs
certbot renew --quiettwice a day. Let's Encrypt certs last 90 days, so twice a day catches it early. - Keep your web server logs for the renewal directory. Check
/var/log/nginx/access.logfor requests to/.well-known/. If you see none during renewal, something's blocking. - Also, make sure your system clock is accurate. SSL validation uses time. Run
sudo timedatectl set-ntp trueto sync with NTP.
That's it. Your auto renewal won't fail again unless you change firewall or DNS settings. And if it does, you now know where to look.
Was this solution helpful?