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.
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.
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
- Create
targets.txtwith onehost:portper line, such aswww.example.com:443andvpn.example.com:443. Add internal services too. - If internal services use a private CA, export its root certificate to
internal-ca.pemand load it into the context. - Write and run the script below. Compare one result with your browser’s certificate viewer.
- 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()?
Why might an expired certificate show as TLS-ERROR rather than EXPIRED?
Why also monitor intermediate certificates?
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.
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.