Free tools

certwatch: cert, disk and service alerts

One Python file that tells your phone when a TLS certificate is about to expire, a disk fills up, a systemd service fails or a site stops answering. No Docker, no agent to install, no account.

1 filePython 3.8+, standard library only
4 checkscerts, disk, systemd units, URLs
$0MIT licence, no telemetry

Download certwatch.py

Version 1.0.0. Read it before you run it; it is about 180 lines.

Set it up in two minutes

1. Get the file and run its self-test:

curl -o certwatch.py https://raidandev.org/tools/certwatch/certwatch.py.txt
python3 certwatch.py --self-test

2. Try a check. It prints only what is wrong:

python3 certwatch.py --cert example.com --disk / --units --url https://example.com/

3. For phone alerts, install the free ntfy app, subscribe to a long random topic name, and add --ntfy https://ntfy.sh/your-random-topic. For Slack or Discord use --webhook with an incoming webhook URL.

4. Run it every 10 minutes from cron (crontab -e):

*/10 * * * * python3 /opt/certwatch.py --config /etc/certwatch.ini

A config file takes the same options, one per line:

# /etc/certwatch.ini
cert = example.com
cert = mail.example.com:465
warn_days = 21
disk = /
disk_max = 90
units = yes
url = https://example.com/
ntfy = https://ntfy.sh/your-random-topic

What an alert looks like

PROBLEM cert shop.example.com: expires in 9 days
PROBLEM unit nginx.service: failed

certwatch remembers the last result and speaks only when something changes. When the problem clears you get one more message: OK again: unit nginx.service. While anything is wrong it exits with code 1, so other scripts can react.

Share this tool https://raidandev.org/tools/certwatch/
Related tools Email authentication checker SSH key fingerprint checker TOTP code tester

Why one more monitor

Uptime services watch your site from outside, so they see a dead page but not the reason: a full disk, a crashed worker, a certificate that renewal quietly stopped updating. Uptime Kuma can check from inside, but it wants Docker or Node and a web dashboard to look after. certwatch is the small thing in between: one file, run by cron, that checks the four failures that take small servers down most often.

Certificates that renewal forgot

Let's Encrypt certificates last 90 days and renew themselves, until a Python upgrade, a DNS change or a moved web root stops the renewal without telling anyone. certwatch connects to each host the way a browser does and reads the real expiry date, so it catches a broken renewal while there are still weeks left. It also flags a certificate that is already invalid or does not match the name.

Disks that fill at night

Logs, backups and uploads fill disks slowly and then all at once. A full disk stops databases from writing and can corrupt them. The default alert is at 90% full; change it with disk_max.

Services that died quietly

With units = yes, certwatch asks systemd for every failed unit, including timers and one-shot jobs like backups, which no outside monitor can see.

Frequently asked questions

Does certwatch need Docker or Node?

No. It is one Python file that uses only the standard library, so it runs on any Linux server with Python 3.8 or newer, which includes every current Ubuntu, Debian and Fedora release.

Will it spam me every time cron runs?

No. It remembers what was wrong last time and only speaks when something changes: a new problem, or a problem that cleared. A disk going from 91% to 92% full is not a new alert.

How do alerts reach my phone?

Install the free ntfy app, subscribe to a topic name nobody can guess, and pass that topic URL with --ntfy. certwatch also posts to Slack or Discord with --webhook, and prints to stdout so cron can email you.

Does it send anything to raidandev?

No. It talks only to the hosts and URLs you list and to the alert address you give it. There is no telemetry and no update check. Read the file before you run it; it is short.

What if the alert itself cannot be sent?

certwatch prints the error, exits with code 2 and keeps its old state, so the same alert is tried again on the next run instead of being lost.