📦 Certbot Domain Bundler
Certbot Domain Bundler automates the creation of Let's Encrypt certificates for multiple domains using SANs (Subject Alternative Names).
It intelligently groups domains and supports both DNS and webroot challenges.
🧭 How it works
flowchart TD
A["certbundle --domains a.example.com,b.example.com,..."] --> B["hash = first 8 hex of sha256 over the sorted domain list"]
A --> C{"--domain-categories given?"}
C -- yes --> D["group by the longest matching category"]
C -- no --> E["group by base domain SLD.TLD"]
D --> F{"group larger than --chunk-size?"}
E --> F
F -- yes --> G["split the group into batches"]
F -- no --> H["one batch per group"]
G --> I
H --> I["cert name = certbundle-HASH-NNNNN"]
B --> I
I --> J["certbot certonly, webroot or dns-PLUGIN"]
J --> K["classify: updated / skipped / failed"]
K --> L{"more batches?"}
L -- yes --> I
L -- no --> M["print the summary"]
M --> N{"any batch failed?"}
N -- yes --> O["exit 1"]
N -- no --> P["exit 0"]
The batch counter runs across all groups, so the numbering is consecutive over the whole run. A failing batch never aborts the remaining ones.
🚀 Installation
pip install certbundle
pip is the single supported installation path.
After installation, usage instructions are available via:
certbundle --help
🔧 Requirements
- Python 3.10+ 🐍
certbotonPATH, plus the DNS plugin matching--certbot-acme-challenge-methodwhen not usingwebroot
If certbot is missing, the command exits with code 127 and a one‑line error instead of a traceback.
🛠 Features
- Group multiple domains into a single SAN certificate
- Supports DNS-01 and HTTP-01 (webroot) ACME challenges
- Control DNS propagation wait time
- Wildcard domain support
- Test mode for Let's Encrypt staging environment
- Fully customizable via CLI parameters
⚙️ Certificate naming
Every certificate is named certbundle-<hash>-<counter>, where <hash> is the first 8 characters of the SHA‑256 over the sorted domain list and <counter> is a five‑digit batch number starting at 00001.
Because the hash covers the whole domain set, changing the set changes every certificate name and causes certbot to issue new certificates rather than renew the existing ones.
📊 Result classification
Each batch is classified from certbot's exit code and output:
| Status | Trigger |
|---|---|
updated |
certbot exited 0 |
skipped:no-change |
certificate not yet due for renewal |
skipped:already-issued |
already issued for this exact set of identifiers |
skipped:rate-limit |
too many certificates |
skipped:service-down |
the service is down for maintenance or had an internal error |
failed:other-error |
any other non‑zero exit |
Every batch runs to completion — a failing batch never aborts the remaining ones.
Exit codes
| Code | Meaning |
|---|---|
0 |
No batch failed. Skipped batches do not fail the run. |
1 |
At least one batch was classified failed. |
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 certbot on PATH, so no certificate is ever requested.
📜 License
This project is licensed under the MIT License.
👤 Author
Developed by Kevin Veen-Birkenbach
🌐 https://www.veen.world
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file certbundle-1.0.0.tar.gz.
File metadata
- Download URL: certbundle-1.0.0.tar.gz
- Upload date:
- Size: 13.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f25bb84c583b14259d3f1afac7c7a10a9daa22b0ed718b5e9eb99f0c3c3aed65
|
|
| MD5 |
5152fff5f89c52d8daecb0dc5e569f0d
|
|
| BLAKE2b-256 |
5f2f0d7f8e21a681706d4d654457a4d12eb42e9bac20b83fbf3958dd2ef6b703
|
File details
Details for the file certbundle-1.0.0-py3-none-any.whl.
File metadata
- Download URL: certbundle-1.0.0-py3-none-any.whl
- Upload date:
- Size: 8.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7394b6c6d6e17a83c7c2c3285979954a83fcf91652a9d62144578c4203145580
|
|
| MD5 |
a643f2fd02dd20ebd2131cf46b4da06f
|
|
| BLAKE2b-256 |
cf7dcf531f9631edbf442b5d7cc44195b4cfa6309394a1bd51eb6caf27ffd128
|