SSL Certificates Are Getting Shorter — Here's How to Monitor Before They Bite
Last month, a friend's SaaS went down for 47 minutes because an SSL certificate expired. Not because Let's Encrypt failed — because someone moved a nginx config during a deployment and the renewal cron silently broke.
The worst part? It was completely avoidable. A simple daily check would have caught it 30 days earlier.
Here's the thing: certificate lifetimes are about to get a lot shorter, and the problem is about to get 8x worse.
The 47-Day Reality
The CA/Browser Forum approved ballot SC-081, and here's the timeline:
| Date | Max Certificate Validity |
|---|---|
| Today | 398 days |
| March 15, 2026 | 200 days |
| March 15, 2027 | 100 days |
| March 15, 2029 | 47 days |
That last number is the one that should keep you up at night. At 47-day validity, you're renewing certificates roughly every 31 days (at the recommended 2/3 mark). For a fleet of 100 domains, that's potentially 3 renewals per day, seven days a week.
Manual renewal is dead. And automated renewal that fails silently? That's the new biggest risk.
Why "It Works in My Browser" Isn't Enough
I've seen this pattern too many times:
- Developer deploys a new service with a valid certificate
- Auto-renewal is configured and "works"
- Six months later, someone changes a DNS record or moves infrastructure
- The renewal challenge fails silently
- Certificate expires at 2 AM on a Saturday
- Production goes down
The gap between "the certificate was issued" and "the certificate is actually being served" is where outages live. Your browser might show a valid certificate because of CDN caching, while the origin server has already expired.
Building a Practical Monitor
Here's a minimal SSL certificate monitor in Python that checks the live certificate — not a cached value, not a DNS lookup, but the actual certificate your users see:
import ssl
import socket
import datetime
from dataclasses import dataclass
@dataclass
class CertInfo:
hostname: str
expires_at: datetime
days_remaining: int
issuer: str
error: str = None
def check_cert(hostname: str, port: int = 443, timeout: int = 10) -> CertInfo:
context = ssl.create_default_context()
try:
with socket.create_connection((hostname, port), timeout=timeout) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
except Exception as e:
return CertInfo(
hostname=hostname,
expires_at=datetime.now(datetime.timezone.utc),
days_remaining=-1,
issuer="",
error=str(e),
)
not_after = datetime.strptime(cert["notAfter"], "%b %d %H:%M:%S %Y %Z")
not_after = not_after.replace(tzinfo=datetime.timezone.utc)
days_remaining = (not_after - datetime.now(datetime.timezone.utc)).days
issuer = dict(x[0] for x in cert.get("issuer", [])).get("organizationName", "")
return CertInfo(
hostname=hostname,
expires_at=not_after,
days_remaining=days_remaining,
issuer=issuer,
)
Key details:
-
ssl.create_default_context()enables hostname verification by default - We check the live certificate from outside your network
- Timezone-aware datetime prevents midnight comparison bugs
Multi-Domain Monitoring with Thresholds
Different domains need different urgency levels. Your payment page needs earlier alerts than your internal wiki:
DOMAINS = [
{"hostname": "api.yoursite.com", "warn_days": 30, "critical_days": 7},
{"hostname": "dashboard.yoursite.com", "warn_days": 21, "critical_days": 5},
{"hostname": "internal.corp.com", "port": 8443, "warn_days": 14, "critical_days": 3},
]
def assess(cert, warn_days, critical_days):
if cert.error:
return "ERROR"
if cert.days_remaining <= critical_days:
return "CRITICAL"
if cert.days_remaining <= warn_days:
return "WARN"
return "OK"
Alert Only on Deviation
One mistake I see often: teams send "all certs OK" messages every day. Within a week, on-call engineers start ignoring them.
Alert on problems, not on health. If everything is fine, don't send anything. When something breaks the threshold, that's when people need to know.
def send_alert(issues):
if not issues:
return # No noise when everything is fine
lines = []
for cert, level in issues:
emoji = {"CRITICAL": "🔴", "WARN": "🟡", "ERROR": "⚪"}[level]
lines.append(f"{emoji} {cert.hostname} — expires in {cert.days_remaining} days")
# Send to Slack, email, PagerDuty, etc.
print("\n".join(lines))
Scheduling: systemd vs Cron
For anything beyond a quick script, systemd timers beat cron:
# /etc/systemd/system/ssl-check.timer
[Unit]
Description=Daily SSL certificate check
[Timer]
OnCalendar=*-*-* 06:30:00
Persistent=true
RandomizedDelaySec=10m
[Install]
WantedBy=timers.target
The Persistent=true flag matters: if your server was down at 6:30 AM, systemd runs the check as soon as it comes back up instead of silently skipping it.
The "Right-Click" Approach
If you don't want to build and maintain a monitor from scratch, there are tools that handle this for you. One that I've found useful is a free SSL certificate checker that:
- Checks multiple domains at once
- Shows days remaining with color-coded status
- Exports results as JSON (great for automation)
- Supports custom port checks (not just 443)
The key is that it checks the live certificate — the one your users actually see — not just the DNS record or CA database entry.
What I Learned
After dealing with three certificate-related outages in the past year, here's what I'd tell myself on day one:
- Check the live cert, not the cached one — CDN caching and browser caching can hide expired origin certificates
- Separate warn and critical thresholds — a single global threshold creates alert fatigue
- Log every run, alert only on deviation — you need history for postmortems, but daily "OK" messages train people to ignore alerts
- Automate renewal AND verify it worked — automation that fails silently is worse than no automation
- Track certificate changes — a cert that suddenly changes issuer or expiry date without a deployment is suspicious
The Bottom Line
SSL certificate monitoring is one of those tiny automations with outsized impact. A 50-line script can prevent a very public outage. And with certificate lifetimes dropping to 47 days by 2029, the teams that survive will be the ones treating renewal as a deployment pipeline, not a calendar reminder.
If you're still manually checking certificates or relying solely on auto-renewal without verification, now is the time to add a monitor. Your future 2 AM self will thank you.
What's your approach to SSL certificate monitoring? Do you have a favorite tool or workflow? Drop a comment below — I'm always curious how other teams handle this.
Top comments (0)