Check SSL Certificate Expiry With a Free API
Check SSL Certificate Expiry With a Free API
An expired SSL certificate is one of the most preventable causes of downtime. Your site goes from "secure" to "Your connection is not private" overnight, and users bounce immediately.
Most teams find out when a customer reports it. Here's how to find out before they do.
Quick Check: One Command
curl -s "https://hermesforge.dev/api/ssl?domain=example.com" | python3 -m json.tool
Response:
{
"domain": "example.com",
"valid": true,
"issuer": "DigiCert Inc",
"subject": "*.example.com",
"not_before": "2025-01-15T00:00:00Z",
"not_after": "2026-02-15T23:59:59Z",
"days_until_expiry": 337,
"serial_number": "0A:1B:2C:...",
"san": ["example.com", "*.example.com"]
}
You get the issuer, validity dates, days until expiry, subject alternative names, and whether the cert is currently valid. No API key needed.
Monitor Multiple Domains
#!/bin/bash
# ssl-check.sh — Check SSL expiry for all your domains
DOMAINS=("myapp.com" "api.myapp.com" "docs.myapp.com" "staging.myapp.com")
WARN_DAYS=30
for DOMAIN in "${DOMAINS[@]}"; do
RESULT=$(curl -s "https://hermesforge.dev/api/ssl?domain=${DOMAIN}")
DAYS=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('days_until_expiry', -1))")
VALID=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('valid', False))")
if [ "$VALID" = "False" ]; then
echo "CRITICAL: $DOMAIN certificate is INVALID"
elif [ "$DAYS" -lt "$WARN_DAYS" ]; then
echo "WARNING: $DOMAIN expires in $DAYS days"
else
echo "OK: $DOMAIN ($DAYS days remaining)"
fi
done
Run it daily via cron:
0 9 * * * /home/user/ssl-check.sh >> /var/log/ssl-check.log
Common Scenarios
Let's Encrypt Auto-Renewal Failures
Let's Encrypt certificates expire every 90 days. Certbot usually handles renewal, but it can silently fail:
- Port 80 blocked by a firewall change
- DNS record changed
- Certbot cron removed during an upgrade
- Docker container restarted without renewal volume
A daily SSL check catches these before your users do.
Wildcard Certificates Covering Multiple Services
If you use *.myapp.com, checking just one subdomain isn't enough. The cert might be valid but misconfigured on a specific service:
# Check that all services actually serve the right cert
for SUB in www api docs admin; do
curl -s "https://hermesforge.dev/api/ssl?domain=${SUB}.myapp.com" | \
python3 -c "import sys,json; d=json.load(sys.stdin); print(f'{d[\"domain\"]}: {d[\"days_until_expiry\"]}d, issuer={d[\"issuer\"]}')"
done
Certificate Chain Issues
Sometimes the leaf certificate is valid but intermediate certificates are missing or expired. The API checks the full chain as presented by the server.
Integrating With Other Checks
Combine SSL monitoring with uptime and dead link checks for a complete site health dashboard:
#!/bin/bash
SITE="myapp.com"
URL="https://${SITE}"
BASE="https://hermesforge.dev"
echo "=== Site Health Report: $SITE ==="
echo "Generated: $(date -u)"
echo ""
# SSL Check
SSL=$(curl -s "${BASE}/api/ssl?domain=${SITE}")
DAYS=$(echo "$SSL" | python3 -c "import sys,json; print(json.load(sys.stdin).get('days_until_expiry', '?'))")
echo "SSL: ${DAYS} days until expiry"
# Uptime Check
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$URL")
echo "HTTP: ${STATUS}"
# Dead Links
BROKEN=$(curl -s "${BASE}/api/deadlinks?url=${URL}" | \
python3 -c "import sys,json; print(len(json.load(sys.stdin).get('broken_links',[])))")
echo "Broken links: ${BROKEN}"
# Tech Stack
TECH=$(curl -s "${BASE}/api/techstack?url=${URL}" | \
python3 -c "import sys,json; d=json.load(sys.stdin); techs=d.get('technologies',[]); print(', '.join([t['name'] for t in techs[:5]]))")
echo "Stack: ${TECH}"
Why Use an API Instead of OpenSSL?
The classic way to check SSL expiry:
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
This works, but:
| API | OpenSSL | |
|---|---|---|
| Output format | Structured JSON | Raw text (needs parsing) |
| Days until expiry | Calculated for you | Manual date math |
| SAN list | Included | Extra command needed |
| Chain validation | Automatic | Manual flags |
| Works in CI/CD | Yes (just curl) | Needs openssl installed |
| Scriptable | JSON + jq | sed/awk/grep |
For quick one-off checks, OpenSSL is fine. For automated monitoring scripts, structured JSON saves time.
Rate Limits
The SSL API is free with no signup: 5 requests per minute without an API key, 20 per minute with a free key. For monitoring a dozen domains daily, no key needed.
Try it now: curl -s "https://hermesforge.dev/api/ssl?domain=google.com" | python3 -m json.tool