Error: certificate has expired (CERT_HAS_EXPIRED)
Diagnose and fix CERT_HAS_EXPIRED errors in HTTPS API requests and webhooks. Check cert validity dates, renew Let’s Encrypt certs, and avoid insecure rejection disabling.
Root Cause Mechanical Summary
The TLS certificate presented by the remote server has passed its `notAfter` validity expiration date. Modern HTTP clients and web browsers immediately terminate TLS handshakes to protect users from stale keys.
During the TLS handshake, the client verifies `cert.valid_to >= current_time`. If the timestamp has elapsed, OpenSSL triggers X509_V_ERR_CERT_HAS_EXPIRED.
// Insecure anti-pattern: disables all TLS certificate verification
const agent = new https.Agent({ rejectUnauthorized: false });// Best practice: maintain verified certificates and monitor expiry
// Renew certificate on the host machine:
// sudo certbot renew --dry-run
// Node.js client with proper CA trust
import https from 'https';
const req = https.request('https://api.wtool.dev', (res) => {
console.log('TLS handshake succeeded, status:', res.status);
});Resolution Note: Never disable `rejectUnauthorized: false` in production; renew the server certificate.
Step-by-Step Triage Checklist
Inspect certificate expiration date: `echo | openssl s_client -servername domain.com -connect domain.com:443 2>/dev/null | openssl x509 -noout -dates`.
Check if intermediate certificate bundle (fullchain.pem) is being served.
Verify if automated cron / systemd certbot timers are actively running.
Automated TLS Expiry Monitoring Script
Prevent recurrence by enforcing this verification check in staging or pre-commit hooks:
DOMAIN="wtool.dev"
EXPIRY_DAYS=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN:443" 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
echo "Certificate for $DOMAIN expires on $EXPIRY_DAYS"
Quick CLI Fix / Diagnosis
sudo certbot renew --force-renewal && sudo systemctl reload nginxDevFlow Diagnostic Workbench Tools
Frequently Asked Questions
- Why does my updated certificate still appear expired in Node.js?
- Node.js connection pools reuse keep-alive TLS sessions. You must restart the Node.js application process or reload the reverse proxy (Nginx/Caddy) to pick up newly issued certs.