v2.40.0 (what the settings say, and the certificate that lost its key)
Two kinds of change. First, settings and actions that did less than they said:
a renewal threshold above 30 days, a reissue that dropped its configuration or
its CA account, events announced twice, a restore into another directory, a
batch that used the wrong DNS account. Second, a state that had no name: a
certificate with no private key anywhere, which is what restoring a share-safe
backup leaves. It now has a name, a code, a place on the dashboard and one
action that repairs all of them.
The API contract moves to 2.29, from 2.23. Read it from
X-CertMate-API-Version on any response, or api_contract_version in
/api/health. Six MINOR steps, each written down beside the constant in
modules/core/constants.py; nothing was removed or retyped.
| step | what grew |
|---|---|
| 2.24 | auth_mode and assume_role_arn on the S3-compatible and AWS Secrets Manager storage backends (#971)
|
| 2.25 | reissue_required and next_step on a successful restore (#982)
|
| 2.26 | a new renewal error code, REISSUE_REQUIRED (#981)
|
| 2.27 | a new endpoint, POST /api/certificates/reissue-keyless (#985)
|
| 2.28 | reissue_required on every certificate record (#988)
|
| 2.29 | challenge_type accepts prevalidated (#983)
|
Read this before upgrading
A renewal threshold above 30 days now renews when it says
certbot has a renewal gate of its own: without being forced, it renews only
inside 30 days of expiry. CertMate asked it unforced, so a
renewal_threshold_days of 45 behaved as 30, and the sweep booked the gap as
skipped_not_due every night. Measured with the real binary: 60, 45 and 31
days left all came back "not yet due".
When the threshold, and only the threshold, calls a certificate due while
certbot would refuse, the renewal is now forced (#991), as the CA's renewal
window already was in v2.39.0. If your threshold is above 30, expect
renewals to start earlier after the upgrade, spread by two guards:
- at most
early_renewals_per_sweepforced renewals per nightly sweep
(default 10, between 1 and 50); the rest wait for the next night and are
counted asearly_deferred; - a certificate issued less than 7 days ago is never forced, so a threshold at
or above the certificate's lifetime costs at most one renewal a week.
A threshold of 30 or less changes nothing. A certificate that needs attention
for another reason, a served key that is missing or does not match, is not
forced: it is repaired from its lineage without a new key.
Since v2.36.0, actions from the dashboard announced everything twice
An issuance or renewal started from the dashboard published its event twice,
so deploy hooks, webhooks and notifications ran twice for one certificate
(#975). One issuance is now one event.
Edit & Reissue kept less than it should
- It rewrote the certificate's metadata from the request alone, so a reissue
in a default install dropped the deployment configuration (#976). Create,
reissue and renew now share one commit step that keeps what the certificate
already had. - It used the CA's default account instead of the one the certificate was
issued under (#983). A certificate issued under a second account of the same
CA, a second ZeroSSL or Sectigo EAB account, came back issued under the
first. The recorded account is now kept while the CA does not change.
Other things that did less than they said
- A backup restored into another directory failed every renewal: certbot's
renewal/<domain>.confcarries absolute paths, which now follow the lineage
(#973). - Batch create bypassed the service: no audit record, no event, and the
issuance used the default DNS account instead of the one named (#984). - Issuance with a DNS alias on another provider waited for the primary
provider's propagation, not the alias zone's, as renewal already did (#977). - The copy in an external storage backend carried a storage warning about
itself after a successful store (#979). - A healthy container logged two ERROR lines at every start (#972).
A certificate with no private key anywhere
Restoring a share-safe backup brings certificates back without their private
keys, by design. Before this release that was discovered at the first nightly
sweep, as a generic certbot parse failure, and repaired one certificate at a
time.
| where | what it says now |
|---|---|
| the restore | lists them at once, as reissue_required, with the next step (#982)
|
| the renewal | REISSUE_REQUIRED (422), not a failure of certbot, and the notification says what to do (#981)
|
| the dashboard | a banner naming them, with Reissue all for operators (#988); each row reads Needs reissue with a key instead of a padlock, and it leaves the Valid count, chip and filter (#992) |
| the API | reissue_required on every certificate, and POST /api/certificates/reissue-keyless (#985)
|
Reissue all is paced. It queues at most limit reissues per call
(default 10, at most 50), two at a time, and answers what was queued, what
remains and what was refused, so a restore of forty certificates is not forty
orders against the CA in one minute.
Unattended instances can opt in. With "auto_reissue_keyless": true in
settings.json, off by default, the nightly sweep reissues at most
auto_reissue_keyless_per_sweep of them itself (default 5). It is off by
default because a reissue changes the key, and deploy hooks ship it.
New
- Sectigo prevalidated authorizations (#983, contributed by QuentinBtd).
challenge_type: prevalidatedissues from a Sectigo SCM account whose names
are already authorized, with no DNS or HTTP challenge. A name the account
has not authorized fails cleanly without touching DNS. See
CA providers. - AWS IAM roles for certificate storage (#971, contributed by
QuentinBtd). The S3-compatible and AWS Secrets Manager backends can use the
AWS credential chain and STS AssumeRole instead of static keys. - Extra volumes in the Helm chart (#994, contributed by QuentinBtd).
extraVolumesandextraVolumeMountsmount existing ConfigMaps, Secrets or
claims; the chart README shows how to mount deploy-hook scripts executable.
Clearer when something fails
- A certbot killed mid-order (the out-of-memory killer in a small
container) says so: "certbot was killed by SIGKILL before it reported an
error", with the last thing it printed. It used to say only "Saving debug
log to …", on create and on renew alike (#987). - Renewals run from the API or the dashboard reach Prometheus:
certmate_certificate_renewals_total, the duration histogram and the
rate-limit counter were fed by the nightly sweep only (#990).
Dependencies
ip-address10.7.2 in the MCP server's lockfile (GHSA-2vr4-cq9g-pvrc,
#980).
How it was checked
Every behaviour change above was reproduced before it was fixed, and verified
after, against Let's Encrypt staging with the real certbot and Cloudflare
DNS-01:
- the keyless path: two certificates, a share-safe backup, a wipe, a
restore that listed both,reissue-keylesswithlimit: 1reissuing one
(new serial, key matches) and the sweep withauto_reissue_keyless
reissuing the other; - the threshold: at 100 days,
mainanswered "not yet due" for both
certificates; this release deferred both while they were fresh, then with
the age guard satisfied renewed one and deferred one under a cap of 1; - Sectigo prevalidated, through Let's Encrypt's own authorization reuse,
which puts certbot in the same state: a validated name issued with no
challenge, a new one failed without touching DNS; - the killed certbot: a real order killed with SIGKILL, and the message
built from what it actually left behind; - the manual renewal metric: a forced renewal through the API, then
/metrics.
The dashboard changes were checked in a browser, as admin and as viewer.