Explain why a Certbot renewal failed, or quietly never ran, from files you pass.
Let's Encrypt stopped expiration-notification emails in June 2025, so a failed renewal or a timer that quietly stops is easy to miss until the certificate expires.
The cause sits in one of three layers: the scheduler, the ACME validation or the deployment. acme-renew-doctor reads the evidence you saved and names that layer, with the line that proves it.
$ acme-renew-doctor example.com --from-log tests/fixtures/certbot/http01-timeout-repeated.log --from-timer-status tests/fixtures/timer/certbot-timer-disabled.txt acme-renew-doctor 0.1.0 (read-only, nothing was changed) target: example.com · client: auto inputs: log=tests/fixtures/certbot/http01-timeout-repeated.log · timer status=tests/fixtures/timer/certbot-timer-disabled.txt · cert disk=(none) · cert live=(none) ✗ LAYER1_TIMER_DISABLED confidence=high layer=scheduler evidence: • [timer] UnitFileState=disabled • [timer] ActiveState=inactive ✗ LAYER2_HTTP01_TIMEOUT confidence=high layer=validation evidence: • [log] line 68: 203.0.113.10: Fetching http://example.com/.well-known/acme-challenge/timeouttoken0000000000000000001: Timeout during connect (likely firewall problem) • [log] 2 attempts in this log (ACME response and Certbot summary of one attempt count as one), first on line 20
cargo install --locked acme-renew-doctor