SSL certificate expiry is the most preventable production outage in web infrastructure. The fix is simple: get a reminder with enough lead time to act. Yet despite Let's Encrypt, Certbot, and years of automation tooling, certificates continue to expire and take real sites offline. An SSL renewal reminder — a proactive alert sent days or weeks before the expiry date — is the difference between a scheduled task and a 2am incident.
The narrative is that Let's Encrypt solved SSL expiry. Ninety-day certificates with automatic renewal via Certbot mean no human ever needs to remember to renew. In practice, this is only true when every link in the chain keeps working indefinitely. Here's what breaks it:
Certbot renewal is a scheduled job — either a systemd timer or a crontab entry. Scheduled jobs fail silently. A package update can mask the timer. A server reimaging can wipe the crontab. A configuration management deploy can overwrite it. Nobody notices until the cert is 10 days from expiry and users start seeing browser warnings.
Let's Encrypt validates your domain via HTTP-01 or DNS-01 challenges. The HTTP-01 challenge requires that /.well-known/acme-challenge/ is reachable on port 80. Add a redirect rule, a new CDN configuration, or a reverse proxy change, and that path can silently break — meaning the next renewal attempt fails, again without alerting anyone.
Commercial certificates from DigiCert, Sectigo, or GlobalSign, internal PKI certificates, and certificates for services behind firewalls that can't complete ACME challenges are all managed manually. A 1-year or 2-year certificate has no automated renewal path. It expires when the calendar says it expires — which is typically when nobody is watching.
In a load-balanced setup, a certificate may be renewed on one node but not distributed to the others. Or the renewed cert lives in a secrets manager and a deployment pipeline is responsible for pushing it to servers — and that pipeline fails for one environment. The result: a valid cert in staging and an expiring cert serving 50% of production traffic.
Before purpose-built monitoring tools existed, developers built their own SSL renewal reminder systems. Here are the three most common approaches — with their real limitations.
The simplest approach: when you provision a certificate, add a calendar event 30 days before expiry. For a single domain with a long-lived commercial cert, this works. For a team managing dozens of domains across multiple environments, calendar alerts break down quickly. They don't survive team turnover. They don't account for emergency certificate replacements that change the expiry date. They generate no alert if the renewal fails between the calendar event and the actual expiry date.
A more robust approach: a scheduled script that checks the live certificate's expiry date and sends an alert when the certificate falls within a threshold. Here's a one-liner to check the current expiry date from the command line:
openssl s_client -connect domain.com:443 -servername domain.com 2>/dev/null | openssl x509 -noout -dates
This outputs both notBefore and notAfter dates for the currently-served certificate. You can wrap it in a script that computes days remaining and sends an email if the threshold is breached:
#!/bin/bash
DOMAIN="example.com"
EXPIRY=$(echo | openssl s_client -servername "$DOMAIN" \
-connect "$DOMAIN:443" 2>/dev/null \
| openssl x509 -noout -enddate \
| cut -d= -f2)
# Convert to epoch (Linux)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s 2>/dev/null)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ "$DAYS_LEFT" -lt 30 ]; then
echo "$DOMAIN cert expires in $DAYS_LEFT days ($EXPIRY)" \
| mail -s "SSL RENEWAL REMINDER: $DOMAIN" ops@yourcompany.com
fi
Run this daily via cron. Limitations: requires a working MTA on the server; only checks one domain per script; the cron job itself can fail silently; you need to maintain and update the domain list manually; it runs from inside your infrastructure, so a network misconfiguration that blocks external access won't be caught.
Let's Encrypt sends a single expiry notification email to the address registered with your account — but only when a certificate is within 20 days of expiry and hasn't been renewed. This is a safety net, not a reminder system. By the time you receive it, you have less than three weeks to act, and the notification gives no context about why renewal failed. It also only covers Let's Encrypt certificates, and it fires once — not at 30 days, 14 days, and 7 days the way a proper reminder cadence should.
Before setting up any reminder system, check where your certificates currently stand. The fastest way is the openssl command-line tool, which connects to your server and reads the live certificate:
openssl s_client -connect domain.com:443 -servername domain.com 2>/dev/null | openssl x509 -noout -dates
Replace domain.com with your actual domain. The output looks like this:
notBefore=Jan 1 00:00:00 2026 GMT
notAfter=Apr 1 00:00:00 2026 GMT
The notAfter line is your expiry date. To compute days remaining, pipe through a date calculation:
EXPIRY=$(openssl s_client -connect domain.com:443 -servername domain.com \
2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
echo "Expires: $EXPIRY"
echo "Days left: $(( ( $(date -d "$EXPIRY" +%s) - $(date +%s) ) / 86400 ))"
If you want to check without installing anything locally, you can check your current expiry date in 5 seconds with the free SSLWatch checker tool — paste your domain and it reads the live certificate instantly.
The goal of an SSL renewal reminder isn't just to send one alert — it's to give you enough lead time to act at every stage of urgency. A reliable cadence looks like this:
Most homegrown cron scripts only send one alert at a single threshold. A multi-stage cadence ensures that if the first alert gets buried in a busy inbox, there are still multiple opportunities to catch the issue before users are affected.
SSLWatch is purpose-built for this problem. Rather than relying on your own infrastructure to monitor itself, SSLWatch checks your certificates externally — from outside your servers — and sends email alerts at 30, 14, 7, and 1 day before expiry. It works for any domain, any certificate type, whether or not you're using Let's Encrypt, and regardless of how your renewal is set up.
The key difference from a cron job: SSLWatch runs independently of the infrastructure it monitors. If your server has a misconfigured renewal timer, a broken ACME challenge path, or a deployment pipeline that failed to push the renewed cert, SSLWatch catches it because it's reading the live certificate from the outside — the same view your users and browsers have.
It covers the cases that homegrown solutions miss:
SSLWatch monitors your domains and emails you at 30, 14, 7, and 1 day before expiry — no cron jobs, no server access required. Works for any cert type on any infrastructure.
Join the waitlist at https://lior-seats.github.io/sslwatch-waitlist/
Join the SSLWatch Waitlist Check Expiry Now (Free)SSL renewal reminders matter because auto-renewal is not the same as guaranteed renewal. Cron jobs break. ACME challenges fail. Commercial certs don't renew themselves. A multi-stage reminder cadence — 30, 14, 7, and 1 day out — gives you multiple opportunities to catch and fix a failing renewal before users see browser warnings.
The fastest way to check where your certificates currently stand: run openssl s_client -connect domain.com:443 -servername domain.com 2>/dev/null | openssl x509 -noout -dates from your terminal, or use the free online checker for a zero-install option. Then set up a reliable external reminder so you're never caught off guard.