Free tech learning for everyone, from basics to pro

Automation ProjectsProgramming and Application SecurityBeginner

Project: TLS certificate expiry checker

In short: Expired certificates still cause outages at well-run organisations, because renewal dates are easy to forget. This project connects to each of your TLS services, reads the certificate expiry date and reports how many days remain, with warnings at 30 days. It uses only the Python standard library and is easy to schedule.

Goal and what you will build

Every HTTPS site, VPN portal, wireless controller and firewall management page uses a TLS (Transport Layer Security) certificate with a fixed end date. When it passes, browsers show errors, VPN clients fail and APIs stop working. Certificate lifetimes are also getting shorter: public CAs (Certificate Authorities) already issue certificates valid for well under a year, and the industry has agreed to shorten them further over the next few years. Manual tracking does not scale. You will build a checker that reads the real certificate from each service, so the result reflects what users actually see.

Only scan services you own or manage. Connecting to a TLS port is harmless, but scanning other people’s systems at scale is not appropriate.

Certificate expiry checkerTarget listhost:portpairsTLS connectwith SNIRead certnotAfter dateDays leftcompare totodayReportwarn at 30days
Figure 1. The checker connects to each service, reads the certificate expiry date and reports how many days remain.

Design

The script reads a list of host:port targets, opens a TLS connection to each with SNI (Server Name Indication) so the server returns the right certificate, and reads the notAfter field. Using the default secure context means the certificate is also verified against trusted CAs and the hostname, so you discover untrusted and mismatched certificates as well as expiring ones.

Result categoriesCheck resultper endpointOKover 30 daysWarning30 days or fewerExpiredpast notAfterTLS erroruntrusted or failed
Figure 2. Every endpoint falls into one of four states, and each state needs a different response.

For a quick manual check, OpenSSL shows the same date from the command line:

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

Build it step by step

  1. Create targets.txt with one host:port per line, such as www.example.com:443 and vpn.example.com:443. Add internal services too.
  2. If internal services use a private CA, export its root certificate to internal-ca.pem and load it into the context.
  3. Write and run the script below. Compare one result with your browser’s certificate viewer.
  4. Schedule a daily run and send warnings to email or chat.
#!/usr/bin/env python3
import socket, ssl, sys, time
from pathlib import Path

WARN_DAYS = 30

def check(host, port, ctx):
    try:
        with socket.create_connection((host, port), timeout=10) as sock:
            with ctx.wrap_socket(sock, server_hostname=host) as tls:
                cert = tls.getpeercert()
    except ssl.SSLCertVerificationError as e:
        return "TLS-ERROR", None, e.verify_message
    except OSError as e:
        return "UNREACHABLE", None, type(e).__name__
    expires = ssl.cert_time_to_seconds(cert["notAfter"])
    days = int((expires - time.time()) // 86400)
    if days < 0:
        return "EXPIRED", days, cert["notAfter"]
    state = "WARNING" if days <= WARN_DAYS else "OK"
    return state, days, cert["notAfter"]

def main():
    ctx = ssl.create_default_context()
    if Path("internal-ca.pem").exists():
        ctx.load_verify_locations("internal-ca.pem")
    worst = 0
    for line in Path("targets.txt").read_text().split():
        host, _, port = line.partition(":")
        state, days, info = check(host, int(port or 443), ctx)
        print(f"{state:12} {host}:{port or 443:<6} {days if days is not None else '-':>5}  {info}")
        if state != "OK":
            worst = 1
    sys.exit(worst)

if __name__ == "__main__":
    main()

Tip: a certificate that is already expired fails verification, so it appears as TLS-ERROR with a message such as "certificate has expired". To read details of broken certificates too, fetch them without verification in a separate diagnostic function and parse them with the cryptography library, but never use an unverified connection for real data.

How to extend it and show it

  • Check the whole chain, not just the leaf: an expiring intermediate certificate causes the same outage.
  • Record the key type and size, signature algorithm and TLS version, and flag weak values.
  • Read targets from your inventory or DNS records, and add STARTTLS checks for mail servers.
  • Better still, automate renewal with ACME (Automatic Certificate Management Environment) clients, and keep this checker as the safety net.

For your portfolio, show sample output with a mix of states, explain the four categories and why the default context is used, and link it to certificate lifecycle management. A short section on what happens when certificates expire, and how your tool would have prevented it, makes the business value clear. Read PKI and certificates for the background theory.

Practice

Why does the script pass server_hostname to wrap_socket()?
It sends SNI so the server returns the right certificate for that name, and it lets Python verify that the certificate matches the hostname.
Why might an expired certificate show as TLS-ERROR rather than EXPIRED?
The default context verifies certificates during the handshake, and an expired certificate fails verification before the script can read it.
Why also monitor intermediate certificates?
If an intermediate CA certificate in the chain expires, clients cannot build a valid chain and the service fails even though the leaf is still valid.

Key takeaways

  • Expired certificates cause avoidable outages; automate the tracking.
  • Connect with SNI and a verifying context to see what users see.
  • Report four states: OK, warning, expired and TLS error.
  • Warn at least 30 days ahead and check intermediates too.
  • Pair the checker with automated renewal such as ACME.
Tracks your learning on this device only. See your progress on the learning paths.

About the author

Mohamed Fayas

Founder of FM TecHub. CCNA certified, with a BTEC HND in Network Engineering, and BEng (Hons) in Computer Networking and Cloud Security. He writes practical, plain-English guides on networking, security and cloud.

More about the author

Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.

Stay up to date by email

New notes, tools and security news from FM TecHub, explained simply. Free.

We only use your email to send these updates. See our privacy policy.