How to Fix and Renew an Expired SSL Certificate on Linux — Let's Encrypt Certbot Guide

By Adhen Prasetiyo

Thursday, March 12, 2026 • 8 min read

Terminal showing SSL certificate renewal with padlock changing from expired to valid

You check your phone and there’s a message from a user: “Your website says it’s not secure. I can’t access it.”

You open the site in your browser and see the dreaded red warning: “Your connection is not private.” You check the certificate — expired three days ago. The Let’s Encrypt auto-renewal that’s supposed to handle this silently in the background? It failed. And you didn’t notice until visitors started complaining.

This happens to more websites than anyone wants to admit. Let’s Encrypt certificates only last 90 days, and if the auto-renewal breaks for any reason, you have a ticking clock until your site goes dark. The good news: fixing it takes about two minutes. The better news: I’ll show you how to make sure it never happens again.

Step 1: Check the Damage

SSH into your server and see what Certbot knows:

sudo certbot certificates

This shows all certificates Certbot manages on your server. You’ll see something like:

Certificate Name: yourdomain.com

  Domains: yourdomain.com www.yourdomain.com

  Expiry Date: 2026-02-15 (EXPIRED)

  Certificate Path: /etc/letsencrypt/live/yourdomain.com/fullchain.pem

  Key Path: /etc/letsencrypt/live/yourdomain.com/privkey.pem

There it is — EXPIRED. Now let’s fix it.

If certbot isn’t installed (maybe someone else set up the server):

# Debian/Ubuntu

sudo apt update && sudo apt install certbot

# CentOS/RHEL

sudo dnf install certbot

# With Nginx plugin

sudo apt install python3-certbot-nginx

# With Apache plugin

sudo apt install python3-certbot-apache

Step 2: Renew the Certificate

The simplest command:

sudo certbot renew

Certbot checks all certificates and renews any that are expired or close to expiring. If everything goes smoothly, you’ll see:

Congratulations, all renewals succeeded.

But if it were that easy, you probably wouldn’t be reading this article. Let’s handle the failures.

When Renewal Fails: The Common Errors

“Problem binding to port 80”

Could not bind to IPv4 or IPv6.. Skipping.

Something else is using port 80. Usually it’s your web server (Nginx or Apache) and Certbot needs port 80 for the HTTP challenge.

Fix for Nginx:

sudo certbot renew --nginx

This tells Certbot to use the Nginx plugin, which handles the challenge through the running Nginx process instead of needing to bind to port 80 directly.

Fix for Apache:

sudo certbot renew --apache

Fix if neither works — temporarily stop the web server:

sudo systemctl stop nginx    # or apache2

sudo certbot renew

sudo systemctl start nginx   # or apache2

Your site will be down for a few seconds during renewal. Not ideal, but it works.

“Connection refused” or “DNS problem”

Failed to connect to host for DVSNI challenge

DNS problem: NXDOMAIN looking up A for yourdomain.com

The Let’s Encrypt servers can’t reach your server. Possible causes:

Firewall blocking port 80. Let’s Encrypt needs to connect to port 80 on your server to verify domain ownership. Check your firewall:

sudo ufw status                    # Ubuntu

sudo firewall-cmd --list-ports     # CentOS

If port 80 isn’t open:

sudo ufw allow 80/tcp             # Ubuntu

sudo firewall-cmd --permanent --add-port=80/tcp && sudo firewall-cmd --reload  # CentOS

Also check your cloud provider’s firewall (AWS Security Groups, DigitalOcean Firewall, etc.) — port 80 must be open there too.

DNS doesn’t point to this server. If you recently moved servers or changed DNS, the domain might point to the old IP. Check:

dig yourdomain.com +short

The IP returned should match your server’s IP. If it doesn’t, update your DNS records.

“.htaccess is blocking the challenge”

This affects Apache servers with restrictive .htaccess rules. The ACME challenge creates a file at /.well-known/acme-challenge/ and Let’s Encrypt needs to read it over HTTP. If .htaccess redirects everything to HTTPS or blocks access to dotfiles, the challenge fails.

Temporary fix:

sudo mv /var/www/html/.htaccess /var/www/html/.htaccess_backup

sudo certbot renew

sudo mv /var/www/html/.htaccess_backup /var/www/html/.htaccess

Permanent fix — add this to your .htaccess before any redirect rules:

RewriteEngine On

RewriteRule ^\.well-known/acme-challenge/ - [L]

This lets ACME challenges through while keeping all other rules intact.

“Too many failed authorizations recently”

Let’s Encrypt has rate limits. If you’ve been trying to renew and failing repeatedly, you might hit the limit. The error tells you when you can try again — usually after an hour. Wait it out, fix the underlying problem, then try again.

Step 3: Force Renewal When Normal Renewal Doesn’t Work

If certbot renew doesn’t pick up your certificate (maybe because it thinks it’s not due yet), force it:

sudo certbot renew --cert-name yourdomain.com --force-renewal

Or if everything is completely broken, start fresh:

# For Nginx

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

# For Apache

sudo certbot --apache -d yourdomain.com -d www.yourdomain.com

This obtains a completely new certificate and automatically configures your web server to use it.

Step 4: Restart Your Web Server

After renewal, the new certificate files exist on disk but your web server might still be serving the old, expired certificate from memory. Restart it:

sudo systemctl restart nginx

# or

sudo systemctl restart apache2

Verify the new certificate is live:

sudo openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | openssl x509 -noout -dates

You should see the new expiry date — 90 days from now.

Or just open your website in a browser. The security warning should be gone, replaced by the familiar padlock icon.

Step 5: Fix Auto-Renewal So This Never Happens Again

Certbot installs either a systemd timer or a cron job to handle auto-renewal. Let’s make sure it’s working.

Check the systemd timer:

sudo systemctl status certbot.timer

If it shows active (waiting), auto-renewal is scheduled. If it shows inactive or not found:

sudo systemctl enable certbot.timer

sudo systemctl start certbot.timer

Check cron jobs:

sudo cat /etc/cron.d/certbot

Or check the root crontab:

sudo crontab -l

You should see a line that runs certbot renew periodically, something like:

0 */12 * * * root certbot renew --quiet

If there’s no cron job and no timer, add one:

sudo crontab -e

Add this line:

0 3 * * * certbot renew --quiet --deploy-hook "systemctl restart nginx"

This runs renewal at 3 AM every day. The --deploy-hook automatically restarts Nginx only when a certificate is actually renewed — not every day.

Replace nginx with apache2 if you use Apache.

Test that auto-renewal works:

sudo certbot renew --dry-run

A dry run simulates the renewal process without actually changing anything. If it succeeds, you’re good. If it fails, the error message tells you what to fix.

Monitor Your Certificates

Auto-renewal usually works. But “usually” isn’t good enough when your website’s reputation is at stake. Add a monitoring layer:

Let’s Encrypt sends expiry emails. Make sure the email in your Certbot config is correct:

sudo cat /etc/letsencrypt/renewal/yourdomain.com.conf | grep email

If the email is wrong or missing, update it:

sudo certbot update_account --email your@email.com

Let’s Encrypt sends warning emails at 20 days, 10 days, and 1 day before expiry. If you get one of these emails, auto-renewal has failed and you need to act.

Use an external monitor. Services like UptimeRobot, Better Uptime, or Pingdom can check your HTTPS endpoint and alert you when the certificate is about to expire. The free tier of UptimeRobot supports SSL monitoring with email and webhook alerts.

Check manually once a month. Run sudo certbot certificates and verify all certificates have expiry dates in the future. Takes ten seconds and gives you peace of mind.

Wildcard Certificates (Special Case)

If you have a wildcard certificate (*.yourdomain.com), renewal is different because wildcard certificates require DNS-01 challenges instead of HTTP-01. This means Certbot needs to create a DNS TXT record to prove domain ownership.

If you used the DNS plugin during initial setup:

sudo certbot renew

Should work automatically. If it doesn’t, you may need to provide DNS API credentials again:

sudo certbot certonly --dns-cloudflare \

  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \

  -d yourdomain.com -d *.yourdomain.com

Replace cloudflare with your DNS provider’s plugin (route53, digitalocean, etc.).

Prevention Checklist

After fixing the expired certificate, run through this checklist to prevent it from happening again:

Certbot timer or cron is active — check with systemctl status certbot.timer or crontab -l

Dry run succeedssudo certbot renew --dry-run completes without errors

Port 80 is open — firewall and cloud security groups allow HTTP traffic

Email is correct — Let’s Encrypt expiry warnings go to an email you actually read

Web server restarts after renewal — deploy hook is configured in the renewal config or cron job

External monitoring is set up — an outside service checks your HTTPS and alerts on certificate issues

Your certificate is renewed, your website is secure again, and auto-renewal is set up properly. The whole thing should have taken less than five minutes. And with the right monitoring in place, you’ll never have an expired certificate surprise again.

Step-by-Step Guide

1

Check which certificates are expired

SSH into your server and run sudo certbot certificates. This shows all certificates managed by Certbot including their domain names expiry dates and file paths. Look for any certificate where the expiry date has passed. Note the certificate name and domains because you will need them for renewal. If certbot is not installed you need to install it first with sudo apt install certbot for Debian/Ubuntu or sudo dnf install certbot for CentOS/RHEL.

2

Renew the expired certificate

Run sudo certbot renew to attempt renewal of all certificates that are due for renewal. If the renewal succeeds Certbot automatically updates the certificate files. If renewal fails read the error message carefully. Common failures include port 80 being blocked by a firewall, the web server not running, or DNS not pointing to the server. For a single specific certificate run sudo certbot renew --cert-name yourdomain.com --force-renewal to force renewal even if Certbot thinks it is not yet due.

3

Restart your web server after renewal

After successful renewal restart your web server to load the new certificate. For Nginx run sudo systemctl restart nginx. For Apache run sudo systemctl restart apache2. Without restarting the web server will continue using the old expired certificate from memory even though the new files exist on disk. Verify the new certificate is working by visiting your website in a browser or run sudo openssl s_client -connect yourdomain.com:443 -servername yourdomain.com to check the

4

Fix auto-renewal so it never expires again

Certbot sets up a timer or cron job for auto-renewal during installation. Check if the timer is active with sudo systemctl status certbot.timer. If it shows inactive enable it with sudo systemctl enable certbot.timer and sudo systemctl start certbot.timer. Also verify the renewal works by running a dry run with sudo certbot renew --dry-run. If the dry run succeeds auto-renewal is configured correctly and your certificates will renew automatically 30 days

5

Set up renewal notification alerts

Even with auto-renewal you should monitor for failures. Add a cron job that checks certificate expiry dates and sends an alert. Create a script that runs openssl s_client -connect yourdomain.com:443 and checks the expiry date. If the certificate expires within 7 days send an email notification. Alternatively use a free monitoring service like UptimeRobot or Better Uptime that checks your HTTPS endpoint and alerts you when the certificate is about to expire.

Frequently Asked Questions

Why did my Let's Encrypt certificate not auto-renew?
The most common reasons are the Certbot timer or cron job was disabled or removed, port 80 is blocked by a firewall preventing the ACME challenge verification, the web server configuration changed and Certbot can no longer authenticate, the .htaccess file is blocking the .well-known/acme-challenge directory, or the server ran out of disk space and Certbot could not write the new certificate files.
How often does Let's Encrypt need to renew?
Let's Encrypt certificates are valid for 90 days. Certbot attempts renewal when the certificate has 30 days or less remaining. This means renewal happens roughly every 60 days. The short validity period is intentional as it encourages automation and limits the damage if a certificate is compromised.
Can I renew a certificate that expired months ago?
Yes. There is no time limit on renewing an expired Let's Encrypt certificate. Run sudo certbot renew --force-renewal and Certbot will issue a brand new certificate regardless of how long ago the old one expired. The only requirement is that your domain DNS still points to the server and port 80 is accessible for the ACME challenge.
What is the difference between certbot renew and certbot certonly?
The certbot renew command attempts to renew all existing certificates using the same method that was used to obtain them originally. The certbot certonly command obtains a new certificate without installing it into your web server configuration. Use renew for routine maintenance and certonly when you need to set up a certificate for the first time or change the domains on an existing certificate.
Adhen Prasetiyo

Research Bug bounty at javahack team

Research Bug bounty Profesional

Web Development Research Bug Hunter
View all articles →