Few events are more frustrating than a sudden production outage caused by an expired SSL/TLS certificate. Secure browser locks turn into giant red warnings, users flee, APIs reject connections, and engineering teams scramble. Even in the age of automated renewal tools like Let's Encrypt, cron failures, DNS validation issues, or network glitches can silently break renewal flows.
In this guide, we'll implement a multi-layered SSL monitoring strategy: a lightweight Bash script using openssl for isolated endpoints, and a Prometheus blackbox_exporter setup for robust, enterprise-grade multi-target probing.
DevOps Principle: Never trust that auto-renewal works silently. Always configure an external, independent checking mechanism to verify the actual certificates served to clients.
Method 1: The Lightweight OpenSSL Bash Script
This script connects to a remote endpoint, extracts the expiration date, calculates the remaining lifetime, and triggers alerts if the certificate is within its warning threshold (e.g., less than 14 days).
#!/usr/bin/env bash # ------------------------------------------------------------- # SSL Certificate expiration checker via OpenSSL. # ------------------------------------------------------------- set -euo pipefail TARGET_DOMAIN="example.com" PORT=443 WARNING_DAYS=14 # Fetch expiration date string from OpenSSL client expiration_date=$(timeout 5 openssl s_client -connect "${TARGET_DOMAIN}:${PORT}" \ -servername "${TARGET_DOMAIN}" -showcerts < /dev/null 2>/dev/null \ | openssl x509 -noout -enddate \ | cut -d'=' -f2) if [ -z "${expiration_date}" ]; then echo "Error: Could not retrieve certificate for ${TARGET_DOMAIN}" exit 1 fi # Convert dates to epoch seconds expiry_epoch=$(date -d "${expiration_date}" +%s) current_epoch=$(date +%s) seconds_left=$((expiry_epoch - current_epoch)) days_left=$((seconds_left / 86400)) if [ "${days_left}" -le "${WARNING_DAYS}" ]; then echo "๐จ WARNING: SSL Certificate for ${TARGET_DOMAIN} expires in ${days_left} days! (${expiration_date})" # Hook in Slack, PagerDuty, or mail notification commands here else echo "โ SSL certificate is healthy. Days remaining: ${days_left}" fi
Method 2: Enterprise Monitoring with Prometheus Blackbox Exporter
For containerized services, a centralized prober is much cleaner. Prometheus's blackbox_exporter queries endpoints over HTTP/S, TCP, DNS, and ICMP. It exposes the target's certificate expiration timestamps as scrapeable metrics.
1. Configure the Blackbox Exporter
Define an HTTP module inside your blackbox.yml configuration file to check SSL status during calls.
modules: http_2xx_ssl: prober: http timeout: 5s http: method: GET preferred_ip_protocol: ip4 fail_if_not_ssl: true
2. Configure Prometheus Jobs
Add the job configuration to your prometheus.yml file to pass URLs through the blackbox exporter instance.
scrape_configs: - job_name: 'blackbox_ssl' metrics_path: /probe params: module: [http_2xx_ssl] static_configs: - targets: - https://example.com - https://my-api.com relabel_configs: - source_labels: [__address__] target_label: __param_target__ - source_labels: [__param_target__] target_label: instance - target_label: __address__ replacement: 127.0.0.1:9115 # Blackbox exporter IP
3. Define Prometheus Alerting Rules
We write an Alertmanager rule alerting if the computed remaining certificate duration is less than 14 days.
groups: - name: ssl_rules rules: - alert: SSLCertificateExpiringSoon expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 14 for: 10m labels: severity: warning annotations: summary: "SSL Certificate for instance {{ $labels.instance }} is expiring soon" description: "The SSL certificate served by {{ $labels.instance }} will expire in less than 14 days."
Conclusion
Combining local cron checks for standalone servers with Prometheus's centralized monitoring offers solid coverage for your environment. By monitoring SSL states externally, you ensure that network setups, load balancers, and local renewals are validated correctly. This protects users from certificate errors and keeps service availability high.
Pick the method that best matches your setup size, and ensure your team has visibility into certificate lifecycles!