How to Monitor SSL Certificate Expiration Automatically
Expired SSL certificates cause browser warnings, break API integrations, and erode trust. Automated monitoring ensures you are alerted well before any certificate expires on your Breeze server or across your infrastructure.
Method 1: Bash Script with Cron
Create a monitoring script at /usr/local/bin/check-ssl.sh:
#!/bin/bash
# SSL Certificate Expiration Checker
DOMAINS=(
"yourdomain.com"
"api.yourdomain.com"
"app.yourdomain.com"
)
WARNING_DAYS=30
CRITICAL_DAYS=7
LOG="/var/log/ssl-check.log"
echo "$(date): SSL Certificate Check" >> "$LOG"
for DOMAIN in "${DOMAINS[@]}"; do
EXPIRY=$(echo | openssl s_client -servername "$DOMAIN" \
-connect "$DOMAIN:443" 2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | \
cut -d= -f2)
if [ -z "$EXPIRY" ]; then
echo " ERROR: Cannot connect to $DOMAIN" >> "$LOG"
continue
fi
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ "$DAYS_LEFT" -lt "$CRITICAL_DAYS" ]; then
echo " CRITICAL: $DOMAIN expires in $DAYS_LEFT days ($EXPIRY)" >> "$LOG"
mail -s "CRITICAL: SSL cert for $DOMAIN expires in $DAYS_LEFT days" \
admin@yourdomain.com "$LOG"
mail -s "WARNING: SSL cert for $DOMAIN expires in $DAYS_LEFT days" \
admin@yourdomain.com "$LOG"
fi
done
chmod +x /usr/local/bin/check-ssl.sh
# Run daily at 8 AM via cron
echo "0 8 * * * /usr/local/bin/check-ssl.sh" | sudo crontab -
Method 2: Prometheus ssl_exporter
Use the Prometheus SSL exporter for metric-based monitoring:
docker run -d --name ssl-exporter \
-p 9219:9219 \
ribbybibby/ssl-exporter:latest
Add a scrape config to prometheus.yml:
scrape_configs:
- job_name: ssl
metrics_path: /probe
static_configs:
- targets:
- yourdomain.com:443
- api.yourdomain.com:443
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: ssl-exporter:9219
Create an alert rule for certificates nearing expiry:
groups:
- name: ssl_alerts
rules:
- alert: SSLCertExpiringSoon
expr: ssl_cert_not_after - time() < 30 * 24 * 3600
for: 1h
labels:
severity: warning
annotations:
summary: "SSL cert for {{ $labels.instance }} expires in less than 30 days"
- alert: SSLCertExpiryCritical
expr: ssl_cert_not_after - time() < 7 * 24 * 3600
for: 1h
labels:
severity: critical
annotations:
summary: "SSL cert for {{ $labels.instance }} expires in less than 7 days"
Method 3: Python Script for Multiple Protocols
#!/usr/bin/env python3
import ssl
import socket
import datetime
import json
def check_cert(hostname, port=443):
context = ssl.create_default_context()
with socket.create_connection((hostname, port), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
expire_date = datetime.datetime.strptime(
cert['notAfter'], '%b %d %H:%M:%S %Y %Z'
)
days_left = (expire_date - datetime.datetime.utcnow()).days
return {
'hostname': hostname,
'expires': cert['notAfter'],
'days_left': days_left,
'issuer': dict(x[0] for x in cert['issuer'])
}
domains = ['yourdomain.com', 'api.yourdomain.com', 'app.yourdomain.com']
for domain in domains:
try:
result = check_cert(domain)
status = 'OK' if result['days_left'] > 30 else 'WARNING' if result['days_left'] > 7 else 'CRITICAL'
print(f"[{status}] {domain}: {result['days_left']} days remaining")
except Exception as e:
print(f"[ERROR] {domain}: {e}")
Setting Up Grafana Dashboard
If using the Prometheus method, create a Grafana dashboard with these panels:
- Gauge panel — showing days until expiry for each domain
- Table panel — listing all certificates with issuer and expiry dates
- Alert list — showing any triggered SSL alerts
Best Practices
- Monitor all domains, subdomains, and API endpoints on your Breeze infrastructure
- Set warning thresholds at 30 days and critical thresholds at 7 days
- Include internal services that use self-signed or private CA certificates
- Test your alerting pipeline regularly to confirm notifications are delivered
- Combine monitoring with automated renewal using Certbot for a hands-free solution