An expired SSL certificate causes an abrupt, visible outage for visitors — entirely preventable with proactive monitoring. This guide covers setting up automated expiration checks.
Why This Still Matters Even with Auto-Renewal
Let's Encrypt's auto-renewal (see How to Renew and Auto-Renew Let's Encrypt Certificates) is generally reliable, but renewal can still silently fail — DNS changes, firewall issues, or configuration drift can all break automated renewal without obvious warning; independent monitoring catches this before it becomes a visible outage.
Checking Expiration Manually
echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | openssl x509 -noout -enddate
Building a Simple Expiration Check Script
sudo nano /usr/local/bin/check-ssl-expiry.sh
#!/bin/bash
DOMAIN="yourdomain.com"
WARN_DAYS=14
EXPIRY_DATE=$(echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ "$DAYS_LEFT" -lt "$WARN_DAYS" ]; then
echo "WARNING: SSL certificate for $DOMAIN expires in $DAYS_LEFT days" | mail -s "SSL Expiration Warning: $DOMAIN" [email protected]
fi
Running the Check on a Schedule
sudo crontab -e
0 8 * * * /usr/local/bin/check-ssl-expiry.sh
Monitoring Multiple Domains
DOMAINS=("yourdomain.com" "api.yourdomain.com" "shop.yourdomain.com")
for DOMAIN in "${DOMAINS[@]}"; do
# ... same check logic for each domain ...
done
Integrating with Prometheus/Grafana for Dashboard Visibility
Several Prometheus exporters specifically check SSL certificate expiration and expose it as a metric — integrate with your existing monitoring stack (see How to Set Up Prometheus and Grafana for VPS Monitoring) for dashboard visibility alongside other server metrics, plus proper alerting integration.
Using an External Uptime Monitoring Service
See How to Set Up Uptime Monitoring for Your Website — many uptime monitoring tools include SSL expiration checking as a built-in feature, providing this alongside general availability monitoring without needing a separate custom script.
Setting Appropriate Warning Thresholds
A 14-day warning window (as in the example script) gives reasonable time to investigate and fix a failed renewal before actual expiration — adjust based on how quickly your team can realistically respond to and resolve a renewal issue.
Verifying Auto-Renewal Is Actually Configured Correctly
sudo certbot renew --dry-run
Periodically test that renewal would actually succeed, rather than only discovering a problem when expiration monitoring finally triggers an alert — a proactive check complements, rather than replaces, expiration monitoring.
Common Errors
Monitoring script reports errors instead of a date — verify the domain is actually reachable on port 443 and that DNS resolves correctly from the server running the check.
Continue Reading
- How to Renew and Auto-Renew Let's Encrypt Certificates
- How to Set Up Uptime Monitoring for Your Website
- How to Set Up Effective Server Alerting (Without Alert Fatigue)
Browse more articles in SSL/TLS & Certificates.