Skip to content
Issue docs

SSL certificate expires within 30 days

Importantssl_certificate_expiring_soonIssue 169

What is this issue?

The site's SSL/TLS certificate is valid today, but it runs out within the next 30 days and has not been replaced yet.

Nothing is broken at the moment. Browsers still trust the certificate, the padlock still shows, and visitors notice nothing. The problem is the date: when it passes, every browser stops loading the site and shows a full-page security warning instead.

For a page to pass this check:

  • The certificate it is served with has more than 30 days of validity left.

Short-lived certificates are judged by their own lifetime. Some certificate authorities now issue certificates that last 45 days, or even 6 days, and renew them automatically long before they expire. Such a certificate spends most or all of its life inside "30 days", so for these the window is one third of the certificate's lifetime instead — the point at which automatic renewal is normally due. For the common 90-day and one-year certificates the window is exactly 30 days.

An already expired certificate is a different finding. Once the date has passed (or before the start date has arrived), the page is reported as "SSL certificate expired" instead. The two are never reported together.

Why it matters

  • An expired certificate takes the whole site offline. Chrome, Safari, Firefox and Edge all replace the page with a full-screen "Your connection is not private" warning. Most visitors leave; many cannot get past it at all.

  • Search engines see the same failure. Crawlers that hit a certificate error cannot fetch the page. A long outage means pages drop out of results, and rankings can take time to recover after the fix.

  • Thirty days is the normal renewal point. Automated clients such as certbot renew a 90-day certificate when 30 days remain. A certificate still inside that window usually means renewal failed silently — a broken cron job, an expired DNS credential, a load balancer that never picked up the new file.

  • It is cheap to fix now and expensive to fix later. Today it is a routine renewal. After expiry it is an incident, often discovered by customers.

Effect on the health score

This is an important issue. It deducts from the Delivery & Trust score for each affected page until the certificate is renewed.

How to fix it

  1. Renew the certificate now. With Let's Encrypt and certbot:

    sudo certbot renew
    sudo systemctl reload nginx   # or apache2, haproxy, ...

    With a commercial certificate authority, request a new certificate, install it, and reload the server.

  2. Make sure the server actually uses the new file. A renewed certificate on disk does nothing until the web server, load balancer or CDN reloads it. Check what is being served:

    echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null      | openssl x509 -noout -dates
  3. Find out why automatic renewal did not run. Check the renewal timer or cron job (systemctl list-timers | grep certbot), its logs, DNS API credentials used for DNS-01 challenges, and that port 80 is reachable for HTTP-01 challenges.

  4. Check every place the certificate lives. CDNs, load balancers, and separate servers for www and the bare domain each hold their own copy.

  5. Add monitoring. An alert at 21 days remaining catches the next failure before this check does.

Examples

Example 1: A one-year certificate with 12 days left

Valid from:  2025-10-12
Valid until: 2026-10-13
Scan date:   2026-10-01

Reported: 12 days remain, which is inside the 30-day window.

Example 2: A 90-day certificate that renewed on time

Valid from:  2026-09-20
Valid until: 2026-12-19
Scan date:   2026-10-01

Passes: 79 days remain.

Example 3: A 6-day certificate in the middle of its life

Valid from:  2026-09-28
Valid until: 2026-10-04
Scan date:   2026-10-01

Passes: 3 days remain, but the certificate only lasts 6 days. Its window is one third of its lifetime (2 days), and it is not there yet. Reporting it would flag a site whose automated renewal is working perfectly.

Example 4: A certificate that has already expired

Valid until: 2026-09-29
Scan date:   2026-10-01

Not this issue: it is reported as "SSL certificate expired" instead.

How PixyScan detects this

  1. Only HTTPS pages are checked. A page served over plain HTTP has no certificate; that is reported separately as "Page not served over HTTPS".

  2. Reads the certificate the server presents with a TLS handshake to the page's host. The result is cached per host for the scan, so a 10,000-page site costs one handshake, not 10,000.

  3. Says nothing if the certificate could not be read. A timeout or refused connection is not evidence about the certificate, so no finding is raised.

  4. Leaves expired and not-yet-valid certificates to the expiry check. Only a certificate that is valid right now can be "expiring soon".

  5. Measures the time left from now until the certificate's "valid until" date, and the certificate's total lifetime from its "valid from" date.

  6. Reports when the time left is at most 30 days, or at most one third of the lifetime if that is shorter. A 398-day or 90-day certificate is reported at 30 days; a 45-day certificate at 15; a 6-day certificate at 2.

  7. Records the whole days remaining (rounded down), the expiry date and the issuer on the finding.

What we store

Storage Level

Page Level


Database Table / Prisma Model

PageSecurityHeader, and the finding on audit_issues.details


Fields Used

Field Type Description
page_security_headers.ssl_certificate_issuer String Who issued the certificate
page_security_headers.ssl_valid_from DateTime Start of the validity window, used for the certificate's lifetime
page_security_headers.ssl_valid_until DateTime End of the validity window

Stored Fields on the finding

Field Type Description
message String The days remaining and the expiry date
sslCertificateIssuer String The issuer
sslValidFrom DateTime Start of the validity window
sslValidUntil DateTime End of the validity window
daysRemaining Int Whole days left at scan time, rounded down

Detection Dependencies

  • TLS handshake with the page's host (cached per host for the scan)

Further reading