Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Monitor Certificate Expiry Before It Bites

By Kokil Thapa | Last reviewed: September 2026

You wake up to a Slack ping, then a client email: the site shows a red browser warning. The root cause is almost always the same — an expired TLS certificate nobody tracked. To monitor certificate expiry before it bites, you need automated checks, threshold-based alerts, and a renewal path that does not depend on someone's calendar. On production stacks I maintain — Laravel apps on Ubuntu with Apache and PHP-FPM, plus SSL/TLS certificate fundamentals baked into every deploy — expiry monitoring is as basic as disk-space checks. This guide covers the checks, scripts, and alert thresholds that actually work in 2026.

Why do TLS certificates expire and take production sites offline?

Public CAs issue certificates with fixed lifetimes. Let's Encrypt currently caps at 90 days. Commercial CAs often offer 397 days or less under browser policy. Expiry is intentional — it limits compromise windows and forces key rotation.

Outages happen when renewal automation breaks and nobody notices. Common failure modes include stale cron paths after a Deployer symlink swap, Certbot hitting rate limits, DNS validation records removed early, or a wildcard cert renewed on one server but not another behind a load balancer.

I've seen this on sister legal-tech sites sharing the same GitLab CI pipeline. One server renewed fine. A second node still served the old cert. Users on that node got hard browser blocks. No revenue, no lead forms, no trust.

Certificate Expiry TimelineValid (90 days)WarnExpired30 daysFirst alert14 daysEscalate7 daysPage on-callAfter Expiry: Browser BlockForms fail, API clients reject, SEO crawlers dropRevenue and trust lost in minutes
Monitor certificate expiry before it bites using tiered alerts at 30, 14, and 7 days before the notAfter date.

Expired certificates break more than browsers. Payment gateway callbacks over HTTPS fail silently. Mobile apps with certificate pinning reject connections outright. Webhooks from Stripe, Khalti, or eSewa never arrive. Your certificate lifecycle management plan must cover every hostname — apex, www, API subdomain, staging, and admin panels.

How do you check certificate expiry from the command line on Linux?

Before you automate anything, confirm what the world actually sees. Local file dates lie. Always check the live endpoint.

OpenSSL one-liner for any hostname

This returns the notAfter date from the certificate the server presents on port 443:

echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates -subject -issuer

Expected output includes notAfter=.... Parse it in a script to compute days remaining. The OpenSSL s_client documentation covers SNI flags you need when multiple vhosts share one IP.

Certbot inventory on Ubuntu

If you use Let's Encrypt via Certbot, list every managed cert on the box:

sudo certbot certificates

Compare Certbot's expiry column against the live OpenSSL check. They should match. When they do not, Apache or Nginx may still point at an old fullchain path. I've hit this after manual edits to vhost files on Ubuntu SSL installs.

Batch check from a host list

Keep a plain-text file of hostnames — one per line — and loop:

#!/usr/bin/env bash
THRESHOLD=30
while read -r host; do
  [[ -z "$host" || "$host" =~ ^# ]] && continue
  enddate=$(echo | openssl s_client -servername "$host" -connect "${host}:443" 2>/dev/null \
    | openssl x509 -noout -enddate | cut -d= -f2)
  expiry_epoch=$(date -d "$enddate" +%s)
  now_epoch=$(date +%s)
  days=$(( (expiry_epoch - now_epoch) / 86400 ))
  if (( days < THRESHOLD )); then
    echo "WARN: $host expires in $days days ($enddate)"
  fi
done < /etc/ssl-monitored-hosts.txt

Run it daily from cron. Pipe warnings to email, Slack, or your incident channel. Store the host list in version control alongside your Linux server administration runbooks.

What tools automatically monitor TLS certificate expiration?

Shell scripts work for five to twenty hostnames. Beyond that, dedicated monitoring pays for itself. Pick based on what you already run.

ToolBest forHow it checksAlert channels
Cron + OpenSSL scriptSmall VPS fleets, solo devsLive TLS handshake per hostEmail, webhook, exit code
Certbot + systemd timerSingle-server Let's EncryptLocal cert files + renew hookCertbot mail plugin, logs
Prometheus Blackbox ExporterKubernetes, multi-node stacksProbe module over HTTPSAlertmanager → PagerDuty, Slack
Uptime Kuma / Healthchecks.ioAgencies, client sitesExternal HTTPS monitorTelegram, Discord, email
Cloudflare / CDN dashboardProxied domainsEdge cert + origin certBuilt-in email alerts

External monitors matter even when you have internal checks. They catch DNS mispointing, partial load-balancer drift, and CDN origin mismatches that local Certbot never sees.

Certificate Monitoring PipelineProbeOpenSSL / HTTPEvaluateDays leftAlertSlack / emailRenewCertbot / ACMEPost-Renew Verification (do not skip)Reload web serverApache / NginxRe-probe HTTPSConfirm new dateLog successAudit trailSkip verify = silent outage on next deploy
End-to-end flow to monitor certificate expiry: probe, evaluate, alert, renew, and verify the new certificate is live.

For Prometheus, the blackbox exporter's probe_ssl_earliest_cert_expiry metric gives you seconds-until-expiry per target. Alertmanager rules at 30, 14, and 7 days mirror the timeline above. Pair this with application-level monitoring — similar to how Laravel Horizon monitors queues — so infrastructure alerts live in one place.

How do you set up alerts before certificates expire?

Alerts fail when they fire too late or too often. Use tiered thresholds and separate warning from critical.

  1. 30 days — informational. Create a ticket. Verify auto-renewal is enabled. Check DNS validation records for wildcard certs.
  2. 14 days — action required. Run a manual dry-run renewal. Inspect Certbot logs at /var/log/letsencrypt/.
  3. 7 days — critical. Page whoever can run certbot renew and reload PHP-FPM plus Apache. Block other deploys until HTTPS is green.
  4. 1 day — all hands. Every hour, re-probe from an external monitor until notAfter moves forward.

Certbot renew dry-run

Test renewal without changing live certs:

sudo certbot renew --dry-run

If dry-run fails, fix it immediately. Common causes include port 80 blocked by UFW, missing webroot path after a Deployer release swap, or expired API credentials for DNS plugins. The Certbot renewal documentation lists plugin-specific requirements.

Cron versus systemd timer

Certbot on Ubuntu installs a systemd timer by default. Verify it is active:

systemctl list-timers | grep certbot

After migrating deploy paths, confirm cron and timers still reference the current symlinked current/ release — not a retired directory. Stale paths are the top reason auto-renewal silently stops on zero-downtime setups I maintain with Deployer 7.

Webhook alert example

Send a Slack-compatible webhook when days remaining drop below threshold:

curl -s -X POST "$SLACK_WEBHOOK" \
  -H 'Content-Type: application/json' \
  -d "{\"text\":\"TLS WARN: ${host} expires in ${days} days\"}"

Include the hostname, days left, issuer, and a link to your renewal runbook. Vague alerts get ignored. Precise ones get fixed.

Sites like Notary Nepal and Court Marriage In Nepal depend on HTTPS for lead capture and document uploads. A cert outage there is not a minor ops ticket — it stops client intake entirely.

What certificates beyond public HTTPS do you need to track?

Teams obsess over the main www cert and forget the rest. A complete inventory includes every trust anchor your stack presents or validates.

  • Apex and www — browser-facing site cert, often Let's Encrypt or commercial CA.
  • API subdomainsapi.example.com for mobile apps and SPA frontends.
  • Staging and preview — easy to skip; still indexed if robots.txt fails.
  • Origin certs behind CDNs — Cloudflare origin certificates expire too.
  • Internal mTLS certs — microservice meshes, database TLS, Redis TLS.
  • Client certificate auth — B2B APIs where partners present their own certs.
  • Code-signing and document signing — see Nepal digital signature certificates for web apps for local PKI context.

Parse the full chain when probing. An expired intermediate in the certificate chain of trust breaks older Android clients even when the leaf cert is valid. Use openssl s_client -showcerts and inspect each link.

Internal vs External MonitoringInternal (on server)+ Sees local Certbot state+ No extra SaaS cost+ Fast cron execution- Misses DNS drift- Blind to LB node skew- False OK if vhost wrongExternal (third party)+ Tests real user path+ Catches DNS errors+ Multi-region view- Extra monthly cost- Rate limits on free tier- Alert fatigue if noisyUse both — internal for renewal, external for truth
Combine internal Certbot checks with external HTTPS probes to monitor certificate expiry from every angle.

How do you automate renewal without hiding failures?

Auto-renewal is necessary but not sufficient. Renewal can succeed on disk while the running web server still serves the old PEM files. Always reload after renew and verify from outside.

Deploy hook pattern for Certbot

#!/bin/bash
certbot renew --quiet --deploy-hook "systemctl reload apache2 && systemctl reload php8.4-fpm"

Adjust service names for your PHP version. On PHP 8.3 or 8.4 stacks — common on Laravel 12 and 13 hosts — FPM reload clears opcache tied to stale HTTPS upstream configs.

For deeper automation, read automate certificate rotation and anatomy of an X.509 certificate so your hooks rotate fullchain, privkey, and any intermediate bundles together.

Multi-server and zero-downtime deploys

When two or more nodes sit behind a load balancer, renew on each node or terminate TLS at the edge with a shared cert store. Never assume rsync happened. After Deployer 7 symlink swaps on shared EC2 infrastructure, I verify cert paths inside the active current release and run an external probe per node IP.

WordPress and WooCommerce shops — like florist sites in our Petals Qatar portfolio — often mix CDN SSL with origin certs. Monitor both layers. A valid edge cert does not fix a broken origin handshake during cache miss.

Multi-Server Cert GotchasNode ACert OKNode BCert EXPIREDLoad Balancer50% of users see browser warning — intermittent nightmareStale cron pathAfter deploy swapNo reload hookFile renewed onlyDNS only on 1 nodeACME TXT missingFix: per-node probe + central host inventory in git
Load-balanced setups need per-node certificate expiry checks — one expired node causes intermittent TLS failures.

What should your certificate expiry runbook include?

A runbook turns a 2 a.m. alert into a fifteen-minute fix instead of a multi-hour outage.

  1. Identify the hostname and which server terminates TLS.
  2. Run the OpenSSL probe and certbot certificates on that host.
  3. If expired, run certbot certonly or certbot renew --force-renewal after fixing the root cause.
  4. Reload Apache or Nginx plus PHP-FPM.
  5. Re-probe from an external monitor and confirm notAfter moved forward at least 60 days for Let's Encrypt.
  6. Document the failure — stale cron, DNS, firewall — in your post-incident log.

Store CA account emails and API tokens in your secrets manager. Losing access to the Let's Encrypt account email slows recovery during rate-limit windows. For internal CA setups, see run an internal certificate authority with step-ca and track those certs on the same schedule.

Revocation checks belong in security audits, not daily expiry cron. Understand CRL vs OCSP revocation separately from expiration monitoring. Pinning adds another layer — review certificate pinning pros and cons before mobile apps hard-code SPKI hashes.

Fold cert checks into broader testing and optimization and support and maintenance contracts. Clients paying Rs 8,000–15,000/month (~USD 60–110) for maintenance expect HTTPS to stay invisible. Expiry monitoring is part of that promise.

When planning new sites, bake monitoring into launch checklists alongside essential pre-launch website steps. Generate strong staging credentials with a password generator — but never confuse secret rotation with cert rotation. They share a schedule cadence, not the same tooling.

Key Takeaways

  • Probe live HTTPS endpoints daily — file mtimes and Certbot rows are not enough on their own.
  • Alert at 30, 14, and 7 days; page on-call at seven days for production domains.
  • Run certbot renew --dry-run monthly and fix failures before they block real renewal.
  • Reload web server and PHP-FPM after every renew, then verify with an external check.
  • Track every hostname — API, staging, origin, internal mTLS — in a version-controlled inventory.
  • On multi-node fleets, probe each node individually; load balancers hide partial expiry.

People Also Ask

How many days before expiry should I alert on SSL certificates?

Start at 30 days for visibility, escalate at 14 days, and treat seven days as critical for production. Let's Encrypt's 90-day lifetime means 30 days is roughly one-third through the cert — enough time to fix DNS, firewall, or plugin issues without panic.

Does Certbot automatically renew Let's Encrypt certificates?

Certbot installs a scheduled renew job on most Linux systems, but it only works when port 80 or DNS validation remains reachable and vhost paths stay correct. Monitor the outcome, not the assumption — verify with certbot renew --dry-run and external HTTPS probes.

Can an expired certificate affect SEO and Google indexing?

Yes. Crawlers that hit HTTPS URLs receive connection errors or certificate warnings. Indexing stalls, Search Console reports spike, and users bounce. Technical SEO work — covered in our search engine optimization service — includes cert uptime as a baseline requirement, not an optional extra.

What is the fastest way to check all domains on a server?

Run certbot certificates for the Let's Encrypt inventory, then loop your full hostname list with the OpenSSL s_client one-liner. Compare both outputs. Any mismatch means the active vhost is not serving the cert you think it is.

Build certificate monitoring into your ops stack before the outage

TLS expiry is predictable. Every outage is a process failure, not a surprise. Monitor certificate expiry before it bites by combining daily probes, tiered alerts, tested renewal, and post-reload verification across every node and subdomain. Whether you run a Laravel booking platform, a WooCommerce shop, or a legal-tech portal, the pattern is identical — know the date, automate the renew, prove it live.

Need help wiring this into your Deployer pipeline, Ubuntu fleet, or client maintenance plan? Review our domain registration and hosting and Mijar Law Associates portfolio for examples of production HTTPS done properly, then contact us to audit your certificate inventory before the next expiry window closes.

Frequently Asked Questions

Public CAs issue certificates with fixed lifetimes. Let's Encrypt currently caps at 90 days, and commercial CAs often offer 397 days or less under browser policy. Expiry is intentional—it limits compromise windows and forces key rotation. Outages happen when renewal automation breaks and nobody notices. Common failure modes include stale cron paths after a Deployer symlink swap, Certbot hitting rate limits, DNS validation records removed early, or a wildcard cert renewed on one server but not another behind a load balancer. I've seen sister legal-tech sites where one node renewed fine and a second still served the old cert, causing hard browser blocks for users routed to that node.

Start at 30 days, escalate at 14, and treat seven as critical for production. On 90-day Let's Encrypt certs, 30 days allows time to fix DNS or firewall blocks.

Always check the live endpoint—local file dates lie. Pipe echo to openssl s_client with -servername and -connect on port 443, then to openssl x509 -noout -dates to read notAfter. On Ubuntu with Let's Encrypt, also run sudo certbot certificates and compare its expiry column against the live OpenSSL result. They should match. When they do not, Apache or Nginx may still point at an old fullchain path, which I've hit after manual vhost edits. Keep a plain-text hostname list and loop the OpenSSL check daily from cron, piping warnings to email or Slack.

Certbot schedules renewal on most Linux systems, but only if port 80 or DNS validation works and vhost paths stay correct. Verify with certbot renew --dry-run, not assumptions.

Run certbot certificates, then loop your hostname list with OpenSSL s_client on port 443. Compare outputs—mismatch means the vhost serves the wrong cert.

Shell scripts with cron and OpenSSL suit small VPS fleets of five to twenty hostnames. Single-server Let's Encrypt setups can use Certbot plus a systemd timer. Kubernetes and multi-node stacks benefit from Prometheus Blackbox Exporter, which exposes probe_ssl_earliest_cert_expiry for Alertmanager rules. Agencies monitoring client sites often use Uptime Kuma or Healthchecks.io for external HTTPS probes with Telegram or Discord alerts. CDN-proxied domains can use Cloudflare dashboard alerts for edge and origin certs. Pick based on what you already run—dedicated monitoring pays for itself beyond a small hostname count.

Use tiered thresholds so alerts fire early enough but not constantly. At 30 days, treat it as informational: create a ticket, verify auto-renewal is enabled, and check DNS validation records for wildcard certs. At 14 days, run sudo certbot renew --dry-run and inspect logs at /var/log/letsencrypt/. At seven days, page whoever can renew and reload Apache plus PHP-FPM, and block other deploys until HTTPS is green. At one day, re-probe hourly from an external monitor until notAfter moves forward. Send Slack webhooks with hostname, days left, issuer, and a runbook link—vague alerts get ignored.

Auto-renewal is necessary but not sufficient. Renewal can succeed on disk while the web server still serves old PEM files. Use a deploy hook that runs certbot renew --quiet, then reloads Apache and PHP-FPM—adjust the PHP version to match your stack; on PHP 8.3 or 8.4 hosts common for Laravel 12 and 13, the FPM reload clears opcache tied to stale configs. After every renew, verify from outside that notAfter moved forward. On multi-node fleets behind a load balancer, renew on each node or terminate TLS at the edge with a shared cert store—never assume rsync happened across nodes.

Teams obsess over www and forget the rest. Your inventory should cover apex and www browser certs, API subdomains for mobile apps and SPA frontends, staging and preview hosts that may still be indexed, origin certs behind CDNs like Cloudflare, internal mTLS for microservices and Redis TLS, client certificate auth on B2B APIs, and code-signing certificates. Parse the full chain with openssl s_client -showcerts—an expired intermediate in the certificate chain breaks older Android clients even when the leaf cert is valid. Combine internal Certbot checks with external HTTPS probes to catch mismatches at every layer.

Start by identifying the hostname and which server terminates TLS. Run the OpenSSL live probe and certbot certificates on that host. If expired, fix the root cause—stale cron, DNS, or firewall—then run certbot certonly or certbot renew --force-renewal. Reload Apache or Nginx plus PHP-FPM, re-probe from an external monitor, and confirm notAfter moved forward at least 60 days for Let's Encrypt. Document the failure in a post-incident log. Store CA account emails and API tokens in your secrets manager, because losing Let's Encrypt account access slows recovery during rate-limit windows. Fold cert checks into maintenance contracts where clients expect HTTPS to stay invisible.

Yes. Crawlers hitting HTTPS URLs receive connection errors or certificate warnings. Indexing stalls, Search Console reports spike, and users bounce. Technical SEO treats certificate uptime as a baseline requirement, not an optional extra layered on after launch. On production legal-tech portals where lead capture and document uploads depend on HTTPS, a cert outage stops client intake entirely—it is not a minor ops ticket you can defer. Monitor certificate expiry before it bites by treating HTTPS availability the same way you treat disk space or database connectivity on every production hostname you care about indexing.

When sudo certbot certificates shows a valid expiry date but the live OpenSSL probe against port 443 returns a different notAfter, the running web server is almost certainly still pointing at an old fullchain or privkey path. I've encountered this after manual edits to vhost files on Ubuntu SSL installs. File mtimes and Certbot rows alone are not proof of what browsers see. Always trust the live TLS handshake when deciding whether production is safe, then fix the vhost to reference the renewed certificate files and reload the web server before closing the incident.

Payment gateway callbacks over HTTPS fail silently—your application may never know the callback was rejected. Mobile apps with certificate pinning reject connections outright with no graceful fallback. Webhooks from Stripe, Khalti, or eSewa never arrive, breaking order confirmation and payment reconciliation. On load-balanced setups, one expired node causes intermittent TLS failures while others work, making the problem harder to diagnose. Users on the bad node see hard browser blocks with no revenue, no lead forms, and no trust. That is why tiered alerts at 30, 14, and seven days matter before you reach expiry day.

Probe each node individually—load balancers hide partial expiry, and one stale node is enough for intermittent outages. After Deployer 7 symlink swaps on shared EC2 infrastructure, confirm cron and systemd timers still reference the current release directory, not a retired path. Verify cert paths inside the active current release and run an external probe per node IP. Either renew on every node or terminate TLS at the edge with a shared cert store. WordPress and WooCommerce shops mixing CDN SSL with origin certs need both layers monitored—a valid edge cert does not fix a broken origin handshake during a cache miss.

External monitors matter even when internal checks exist. They catch DNS mispointing, partial load-balancer drift, and CDN origin mismatches that local Certbot on the server never sees. End-to-end monitoring means probe, evaluate, alert, renew, and verify the new certificate is live from outside the network—not just confirm files updated on disk. For agencies managing multiple client sites, Uptime Kuma or Healthchecks.io adds an independent view that complements cron-based OpenSSL scripts. Pair infrastructure cert alerts with application-level monitoring so HTTPS warnings land in the same incident channel as queue or deployment failures.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: