Knowing when an HTTPS certificate expires lets you renew it before clients start rejecting connections. For API checks, site probes, and automation, the useful answer is the expiry date on the certificate the server is presenting right now.
Current cURL builds that support {certs} can expose the server certificate chain through --write-out after the TLS handshake completes. Piping the first PEM block into OpenSSL gives you a dependable notAfter value or renewal-window check without scraping verbose logs, while --output /dev/null keeps the transfer lightweight without depending on HEAD support.
Keep the check strict for normal monitoring so hostname, trust, and expiry problems still fail the request. If the endpoint already has a broken certificate and cURL stops before you can inspect it, use a temporary diagnostic-only run with --insecure to read the presented certificate, then remove that flag again.
Steps to check SSL certificate expiration with cURL:
- Read the subject and expiration date from the certificate currently presented by the HTTPS endpoint.
$ site=api.prod.example.net $ curl --silent --show-error --output /dev/null \ --write-out '%{certs}' "https://$site" \ | awk '/-----BEGIN CERTIFICATE-----/{flag=1} flag{print} /-----END CERTIFICATE-----/{exit}' \ | openssl x509 -noout -subject -enddate subject=CN=api.prod.example.net notAfter=Jun 30 12:00:00 2027 GMT
Extracting only the first PEM block keeps the check focused on the leaf certificate that browsers and API clients validate for the hostname.
- Check whether the certificate is still valid right now before turning the command into a scheduled monitor.
$ site=api.prod.example.net $ curl --silent --show-error --output /dev/null \ --write-out '%{certs}' "https://$site" \ | awk '/-----BEGIN CERTIFICATE-----/{flag=1} flag{print} /-----END CERTIFICATE-----/{exit}' \ | openssl x509 -noout -checkend 0 Certificate will not expire
With -checkend 0, an exit status of 0 means the certificate is not yet expired and a non-zero exit status means it has already expired or could not be read cleanly.
- Warn before renewal becomes urgent by testing whether the certificate expires within the next 30 days.
$ warn_seconds=$((30 * 24 * 60 * 60)) $ site=api.prod.example.net $ curl --silent --show-error --output /dev/null \ --write-out '%{certs}' "https://$site" \ | awk '/-----BEGIN CERTIFICATE-----/{flag=1} flag{print} /-----END CERTIFICATE-----/{exit}' \ | openssl x509 -noout -checkend "$warn_seconds" Certificate will not expire
Adjust warn_seconds to match your renewal policy, such as 7, 14, or 60 days.
- Inspect an already-broken or expired certificate only when a strict run cannot read the date you need.
$ site=legacy.prod.example.net $ curl --silent --show-error --insecure --output /dev/null \ --write-out '%{certs}' "https://$site" \ | awk '/-----BEGIN CERTIFICATE-----/{flag=1} flag{print} /-----END CERTIFICATE-----/{exit}' \ | openssl x509 -noout -subject -enddate subject=OU=Managed TLS, OU=Platform Edge, CN=*.prod.example.net notAfter=Jan 15 23:59:59 2025 GMT
Use --insecure only long enough to inspect the presented certificate. It disables normal TLS verification and should not remain in production scripts or recurring checks.
- Loop through several hosts and print a clear status line that can feed alerting or a daily report.
$ cat check-cert-expiry.sh #!/usr/bin/env bash set -euo pipefail sites=( "api.prod.example.net" "auth.prod.example.net" ) warn_days=30 warn_seconds=$((warn_days * 24 * 60 * 60)) for site in "${sites[@]}"; do cert=$(curl --silent --show-error --output /dev/null \ --write-out '%{certs}' "https://$site" 2>/dev/null \ | awk '/-----BEGIN CERTIFICATE-----/{flag=1} flag{print} /-----END CERTIFICATE-----/{exit}') if [[ -z "$cert" ]]; then echo "$site: unable to read certificate" continue fi expires_on=$(printf '%s\n' "$cert" | openssl x509 -noout -enddate | cut -d= -f2) if printf '%s\n' "$cert" | openssl x509 -noout -checkend "$warn_seconds" >/dev/null; then echo "$site: ok until $expires_on" else echo "$site: expires within $warn_days days ($expires_on)" fi done $ bash check-cert-expiry.sh api.prod.example.net: ok until Jun 30 12:00:00 2027 GMT auth.prod.example.net: ok until Jul 18 09:15:42 2027 GMT
If cURL prints unknown –write-out variable: 'certs', switch to a newer build that supports {certs} before depending on this workflow in automation.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
