☠️ Certbot Reaper
Certbot Reaper is a Python utility that finds, revokes, and deletes unused Let's Encrypt certificates from your system – so you stay clean and secure. It compares existing certificates with active NGINX configurations and safely removes those that are no longer in use.
🧭 How it works
flowchart TD
A["certreap"] --> B["walk the nginx config tree for *.conf"]
B --> C["collect every domain-like string found"]
A --> D["list the subdirectories of the cert dir"]
D --> E["openssl x509 -text on cert.pem"]
E --> F["read the DNS: entries"]
F --> G{"any of them still referenced by nginx?"}
C --> G
G -- yes --> K["keep the certificate"]
G -- no --> H{"--force?"}
H -- no --> I{"confirm at the prompt?"}
I -- no --> K
I -- yes --> J
H -- yes --> J["certbot revoke --delete-after-revoke"]
J --> L["remove the certificate directory"]
A revoke that certbot rejects is reported, and the directory is removed anyway.
🚀 Features
- 🔍 Scans
/etc/letsencrypt/livefor all installed certificates - 🧠 Checks if domain names are referenced in NGINX configs under
/etc/nginx/ - 🗑️ Offers interactive or forced cleanup of unused certificates
- 🔁 Can be run manually or scheduled with
systemdtimers - ⚙️ Supports
--forceand--helpviaargparse
📦 Installation
pip install certreap
pip is the single supported installation path.
🔧 Requirements
- Python 3.10+ 🐍
opensslonPATH— reads the DNS names out of each certificatecertbotonPATH— performs the revocation
If either is missing, the command exits with code 127 and a one‑line error instead of a traceback. A missing openssl is never silently treated as "no certificates found".
🛠️ Usage
certreap # Interactive mode (asks before deleting)
certreap --force # Deletes unused certificates without confirmation
certreap --help # Shows help message
Both scanned locations can be pointed elsewhere, which is what the integration tests use:
certreap --cert-dir /etc/letsencrypt/live --nginx-conf-dir /etc/nginx
Exit codes
| Code | Meaning |
|---|---|
0 |
Finished. A certificate certbot failed to revoke is reported and its directory is still removed. |
2 |
Invalid command line arguments. |
127 |
A required command is not installed. |
🧪 Development
make lint # ruff check + ruff format --check
make format # apply ruff format
make test # unit + integration tests
make test-unit
make test-integration
make test-e2e # install the package in a container and exercise the CLI
Tests run against the working tree — the Makefile puts src/ on PYTHONPATH, so no install is needed. The integration tests stub openssl and certbot on PATH, so nothing real is ever revoked.
👤 Author
Developed by Kevin Veen-Birkenbach 🧠 Feedback and contributions welcome!
📄 License
This project is licensed under the MIT License. Feel free to use, modify, and share it as you wish.
Metadata
Release files for certreap 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| certreap-1.0.0.tar.gz | 10.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| certreap-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.4 kB
Release files / certreap-1.0.0.tar.gz
| Download URL | certreap-1.0.0.tar.gz |
|---|---|
| Size | 10.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d900f91328df11567160f3cd08771a5a6d4ad080ada11212cee743e471e14f43
|
|
BLAKE2b-256 checksum How to use checksums |
37f2d5a877133437acd54380ed83a54f8d1f20cf4ffdc9b81e3823771d5d6957
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|
Release files / certreap-1.0.0-py3-none-any.whl
| Download URL | certreap-1.0.0-py3-none-any.whl |
|---|---|
| Size | 6.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
267034f3d7613b3a1d9f30cb771276c96041db7cd846e7ebf75d9ac5c82427cf
|
|
BLAKE2b-256 checksum How to use checksums |
2a44e54cec31f062f1a9fc99c40e10aa5e97586d6e10edceca556beae4cc8117
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|