This guide lists ways to check when an SSL/TLS certificate expires, from quick manual checks to automation. With lifetimes dropping to 47 days by 2029, automated verification matters.
Enter a hostname in SSL Checker to see expiry, days remaining, chain validity and hostname match. If the hostname resolves to several addresses, each one is checked and servers presenting a different certificate are flagged.
Click the site information (padlock) icon, then "Connection is secure" → "Certificate is valid" to see the validity period. You only see the certificate of the one server your browser connected to.
echo | openssl s_client -connect www.example.com:443 -servername www.example.com 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
notAfter is the expiry. Always pass -servername (SNI), otherwise a different certificate may be returned. To test the remaining time, use -checkend (seconds):
echo | openssl s_client -connect www.example.com:443 -servername www.example.com 2>/dev/null \
| openssl x509 -noout -checkend $((30*86400)) && echo "OK: 30+ days" || echo "NG: under 30 days"
for ip in $(dig +short www.example.com A); do
printf '%s ' "$ip"
echo | openssl s_client -connect "$ip:443" -servername www.example.com 2>/dev/null \
| openssl x509 -noout -enddate -fingerprint -sha256
done
echo | openssl s_client -connect mail.example.com:587 -starttls smtp 2>/dev/null | openssl x509 -noout -dates
openssl x509 -in /etc/letsencrypt/live/www.example.com/cert.pem -noout -enddate
A new file is not enough if the web server was not reloaded. Always verify from the outside.
- name: Get served certificate
community.crypto.get_certificate:
host: "{{ ansible_host }}"
port: 443
server_name: www.example.com
delegate_to: localhost
register: served_cert
- name: Assert at least 30 days remain
ansible.builtin.assert:
that:
- ((served_cert.not_after | to_datetime('%Y%m%d%H%M%SZ')) - now(utc=true)).days >= 30
The free SSL Checker API returns pass or fail for all addresses of a host. Call it at the end of your renewal job to catch servers that missed the update.
curl -fsS "https://sslcheck.nakayumc.com/api/v1/check?host=www.example.com&min_days=30&nocache=1" | jq -e '.result == "pass"'
Pass the previous expiry as expect_not_after_gt to require that the expiry actually moved forward.