Skip to main content

SRE Toolbox

SSL Expiry

Check TLS certificate expiration dates on port 443.

lupaxa-ssl-expiry connects to each host, reads the leaf certificate the server presents, and reports the issuer, the expiration date, and how many days remain. The handshake requires TLS 1.2 or newer. Hostname matching and certificate trust are not checked, so an expired, self-signed, or untrusted leaf is still reported. The TCP port is always 443.

Requirements

  • Python 3.13 or newer
  • Outbound TCP access to port 443

cryptography and prettytable install with the package.

Install

pip install lupaxa-ssl-expiry
ssl-expiry --help

CLI

ssl-expiry example.com example.org
ssl-expiry example.com,example.org
ssl-expiry --file hosts.txt --warn-days 14
printf '%s\n' example.com example.org | ssl-expiry --file -
ssl-expiry --sort days --order descending example.com example.org
python -m lupaxa.ssl_expiry --version

Pass hosts as separate arguments, or separate them with commas. International names are converted to ASCII before the connection, and that form is what the host column prints. IPv4 and IPv6 addresses are accepted. A URL, a port suffix, or any other non-host is invalid and is not connected.

--file reads one hostname per line. Blank lines and # comments are ignored. - reads stdin. Repeat --file to combine lists. Hosts on the command line are checked first, then hosts from each file.

--timeout is the TCP connect and TLS handshake timeout in seconds (default 10). It must be greater than 0.

--warn-days is how close a date can be before the command exits 1 (default 30). The comparison is inclusive: a certificate with 30 days left exits 1 when --warn-days is 30. 0 means only today or earlier.

--sort orders the table by host, issuer, date, or days. --order is ascending (the default) or descending. asc and desc are accepted. Host and issuer order ignore case. Date order uses the expiration date, including hosts that show Expired. Day order uses the day count. Rows with no issuer, date, or day count stay at the end. Without --sort, rows stay in the order the hosts were given. --order without --sort exits 2.

With no hosts, the command prints help and exits 2.

Output

Results print as one table. Every host is a row, including invalid hosts and connection failures.

+--------------+---------------+---------------------+------+
| Host         | Issuer        | Date                | Days |
+--------------+---------------+---------------------+------+
| example.com  | Let's Encrypt | 15th March 2027     |  173 |
| example.org  | DigiCert Inc  | 22nd September 2026 |    0 |
| old.example  | Let's Encrypt | Expired             |  -12 |
| slow.test    | —             | timed out           |    — |
| nope.invalid | —             | Invalid Host        |    — |
+--------------+---------------+---------------------+------+

The date is the day, with st, nd, rd, or th, then the month name and the year, as in 11th November 2026. Expired means that date is already past. Days is the number of UTC calendar days remaining. 0 means the certificate expires today. A negative number is how many days ago it expired.

The issuer is the certificate organization name, or its common name when the organization is absent. When neither is present, the issuer column shows —.

Invalid Host means the value was not connected. A connection failure, including a timeout or a handshake that yields no certificate, puts the cleaned error in the date column. Examples include timed out and no peer certificate.

Exit Codes

Code When
0 Help, version, or every certificate is further out than --warn-days
1 A certificate is due, expired, or the host is invalid
2 Usage failed, a file could not be read, no hosts were given, or a connection failed

When one host needs attention and another connection fails, the command exits 1.

Library

from lupaxa.ssl_expiry import lookup

result = lookup("example.com", timeout=10.0)
if result.status == "expires":
    print(result.issuer, result.expiration, result.days_remaining)
else:
    print(result.status, result.error)

lookup returns a result for invalid hosts and connection failures. status is expires, invalid, or error. days_remaining is set only for expires. error is set only for error, and is a single line. An invalid host is not connected. A timeout that is not greater than 0 raises ValueError.

Pass now to fix the clock used for days_remaining. Pass probe to replace the network call in tests. The callable receives the normalized host and the timeout in seconds, and returns a LeafCert.

Development

make init
make python-install-dev
make python-check
The Lupaxa Project Footer

Metadata

Release files for lupaxa-ssl-expiry 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lupaxa-ssl-expiry 0.1.4
File Size Uploaded
lupaxa_ssl_expiry-0.1.4.tar.gz 10.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lupaxa-ssl-expiry 0.1.4
File Interpreter ABI Platform
lupaxa_ssl_expiry-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 21.9 kB

Release files / lupaxa_ssl_expiry-0.1.4.tar.gz

Download URL lupaxa_ssl_expiry-0.1.4.tar.gz
Size 10.1 kB
Tags Source
SHA-256 checksum
How to use checksums
39cc961b2714a2b2a639317afb072e3c151f5b07b4baf17b1618e96b06e61d34
BLAKE2b-256 checksum
How to use checksums
fcc786428a0bb84f120db7c87edc8a8546eeefb9d9e54f05970256ae2df81ee2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log

Release files / lupaxa_ssl_expiry-0.1.4-py3-none-any.whl

Download URL lupaxa_ssl_expiry-0.1.4-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
27b837c8251052de66911e9bb270374dd512d6cbc2166d116bc7bd9159f8073c
BLAKE2b-256 checksum
How to use checksums
cf0282a8179c9b1f3a230ad28baf0e08991adc41a10f8dd0d795c99360f2a96e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.5

2 release files

This release

0.1.4 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page