How to Validate SSL Certificates for Multiple Domains in Python
A Python utility that checks SSL certificate expiry dates for a list of domains using the standard library ssl and socket modules.
Python code
42 linesimport ssl
import socket
from datetime import datetime
def check_ssl_certificate(hostname: str, port: int = 443) -> dict:
"""Validate SSL certificate for a given hostname."""
context = ssl.create_default_context()
with socket.create_connection((hostname, port), timeout=5) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
expiry_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
days_remaining = (expiry_date - datetime.now()).days
return {
'hostname': hostname,
'expires': expiry_date.strftime('%Y-%m-%d'),
'days_remaining': days_remaining,
'valid': days_remaining > 0,
'issuer': dict(cert['issuer'][0][0]),
'subject': dict(cert['subject'][0][0])
}
def validate_domains(domains: list) -> list:
"""Validate certificates for multiple domains."""
results = []
for domain in domains:
try:
result = check_ssl_certificate(domain)
except Exception as e:
result = {'hostname': domain, 'error': str(e), 'valid': False}
results.append(result)
return results
if __name__ == "__main__":
test_domains = ['example.com', 'google.com', 'nonexistent.domain']
ssl_results = validate_domains(test_domains)
for result in ssl_results:
status = "✓" if result.get('valid', False) else "✗"
print(f"{status} {result['hostname']}: "
f"expires {result.get('expires', 'N/A')} "
f"({result.get('days_remaining', 'N/A')} days)")
Output
✓ example.com: expires 2025-XX-XX (XXX days)
✓ google.com: expires 2025-XX-XX (XXX days)
✗ nonexistent.domain: expires N/A (N/A days)
How it works
The script uses ssl.create_default_context() to set up a secure context with default trusted CA certificates. It creates a TCP connection to the hostname on port 443, wraps it in an SSL/TLS socket, and retrieves the peer certificate with getpeercert(). The 'notAfter' field is parsed to a datetime object to calculate days remaining. A timeout of 5 seconds prevents hanging on unreachable hosts. Each domain is processed individually and errors are caught per domain so a single failure does not stop the entire batch.
Common mistakes
- Not setting a timeout on socket.create_connection, causing the script to hang on unreachable hosts.
- Assuming the certificate issuer or subject fields always have a predictable structure without checking for nested tuples.
- Forgetting to close sockets properly, though the 'with' statement handles this.
Variations
- Use aiohttp and asyncio to check many domains concurrently for faster batch validation.
- Leverage the cryptography library to parse and validate certificate chains in more detail.
Real-world use cases
- Automated monitoring of SSL certificate expiry for a portfolio of client websites before renewal deadlines.
- Integrating into a CI/CD pipeline to verify that staging and production endpoints have valid certificates.
- Generating a daily report for IT operations to proactively flag domains with certificates expiring soon.
Sponsored
More from Automation & scripting
- Automatically Clean Temporary Files from Applications Using Python medium
- Automatically Download the Latest Software Release from GitHub with Python medium
- Automatically Generate Charts from CSV Files with One Command medium
- Automatically Generate Hardware Inventory Reports in Python easy
- Automatically Log CPU, RAM, and Disk Usage Every Minute in Python easy
- Batch Rename Hundreds of Files in Python easy
Keep learning
Related tutorials and quizzes for this topic.