No description
- Python 100%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| docs | ||
| src/certbot_manager | ||
| tests | ||
| .gitignore | ||
| pyproject.toml | ||
| README.md | ||
| sonar-project.properties | ||
certbot-manager
A reliability-focused TUI for managing Let's Encrypt certificates and the nginx virtual hosts that consume them, on a single host.
┌─ certbot-manager — let's encrypt lineage & nginx vhost management ─┐
│ ┌─Certs─┐ VHosts New Templates │
│ ┃Lineage Days Algo Names Status ┃
│ ┃expired.example -3d ecdsa 256 expired.example EXPIRED ┃
│ ┃paused.example 45d ecdsa 256 paused.example DISABLED ┃
│ ┃bc1bb.foo 42d ecdsa 256 bc1bb.foo, www… OK ┃
│ ┃orphan.example 12d ecdsa 256 orphan.example NO-VHOST ┃
├────────────────────────────────────────────────────────────────────┤
│ server up: 47d 03h • nginx: active • for: 12d 05h • reloaded: 6h ago │
└─ 1:Certs 2:VHosts 3:New 4:Templates ?:help q:quit ───────────────┘
Four tabs
| Tab | What you can do |
|---|---|
| Certs | Browse every lineage. Open a detail view. Delete (certbot delete), revoke+delete, soft-disable auto-renewal. Jump straight to $EDITOR on any vhost that references the cert. |
| VHosts | Browse every server { } block parsed from /etc/nginx/sites-available/. Edit in $EDITOR (writes back atomically). Toggle enabled/disabled. Delete. Test+reload nginx. |
| New | Issue a certificate via certbot certonly --webroot. Optionally then drop a vhost from a template. Supports --dry-run so you can rehearse without burning LE quota. |
| Templates | Browse 5 bundled vhost recipes (acme-only, redirect-to-https, proxy-pass, static, php-fpm). Live preview. Save into sites-available/ — opens $EDITOR first for any tweaks. |
Reliability + security posture
- Three architectural layers with hard boundaries.
core/is pure logic + tests (no I/O).infra/is the audited subprocess + filesystem surface.tui/is a thin view. - Every privileged op routes through one binary,
certbot-manager-helper, with its own sudoers entry. It re-validates every argument before doing anything privileged. Nosudo mv, nosudo tee, no wildcards over generic tools. - No automatic editing of foreign config files.
certbotis only ever invoked incertonly,delete,revokemodes — never with--nginx. All vhost edits go through your$EDITORand the helper's atomicvhost-write. - Strict input validation at every boundary. Lineage names, vhost names, domain names, path segments — all pinned by hypothesis tests against shell metas, path traversal, uppercase, and
... - 11 lineage health flags computed by the cross-referencer:
EXPIRED,EXPIRING_SOON,ORPHAN_NO_VHOST,ORPHAN_NO_RENEWAL_CONF,ARCHIVE_MISSING,LIVE_SYMLINK_BROKEN,RENEWAL_DISABLED,SAN_MISMATCH,WEAK_KEY,BROKEN_VHOST_REF,UNPARSEABLE.
Architecture
src/certbot_manager/
core/ pure datamodels, parsers (X.509, renewal conf, nginx vhost),
inventory cross-referencer. NO I/O. 95%+ coverage.
infra/ filesystem reader, certbot subprocess wrapper, helper wrapper
(nginx_ops), systemd status, /proc/uptime. Audited allowlist.
tui/ Textual app: tabs, widgets, modal screens, editor shell-out.
validation.py central validators (lineage, vhost, domain, path segment).
config.py sudoers/exec allowlist + Paths.
cli.py `certbot-manager` entry point.
helper_cli.py `certbot-manager-helper` entry point (the privileged binary).
Status
v0.2 (shipped):
- Read-only inventory with all 11 health flags
- Cert delete (hard / revoke+delete / soft-disable auto-renew)
- Cert detail screen
- VHost browser with
$EDITORshell-out, toggle, delete - Cert issuance wizard (
certbot certonly --webroot) - 5 bundled vhost templates with live preview + save flow
nginx -t+systemctl reload nginxvia helper- Server / nginx uptime + last-reload display
- 256 tests, 74% coverage
Roadmap (not yet shipped):
- DNS-01 challenge support
- Renewal-hook editor (
renewal-hooks/deploy/etc.) - Bulk operations (renew all, delete all expired)
- Cert detail: chain validation against Mozilla CA bundle
Install
See docs/SETUP.md for a least-privilege deploy (ACLs + narrow sudoers entry — TUI never runs as root).
Test
.venv/bin/pytest
# 256 tests in ~8 seconds
Develop
See docs/DEVELOPMENT.md.