Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Renewal Information (ARI)

acme-proxy implements the ACME Renewal Information extension (RFC 9773). ARI allows a CA to signal to ACME clients when they should ideally renew their certificates. This prevents the “stampede” effect where thousands of certificates expire simultaneously, and allows the CA to orchestrate graceful mass-revocations by shortening the renewal window.

GET /renewalInfo/{certID}

This is an unauthenticated endpoint clients use to ask “when should I renew this certificate?”. The response provides a time window (Start and End).

The window is resolved in this order:

  1. Revoked certificates win. If the certificate is known to be revoked locally (looked up by its serial), the answer is a window entirely in the past, prompting a compliant client to renew immediately. This is checked before the signer backend is consulted, so a locally revoked certificate is never talked out of renewing by an upstream CA that has not noticed yet.
  2. The backend’s own opinion, if it has one. The relay backend relays the upstream CA’s answer verbatim, including RFC 9773 §4.2’s optional explanationURL — so if Let’s Encrypt signals early renewal, that reaches your internal clients unchanged. The custom backend can do the same through its renewal_info hook, but only when signer.custom.supports_renewal_info = true; otherwise the hook is never invoked.
  3. A local estimate, when the backend has no opinion — always the case for local_ca. The certificate’s notBefore and notAfter are read by parsing the certificate itself, and the suggested window runs from ⅔ to ¾ of the validity period. For a 90-day certificate that is roughly day 60 to day 67, leaving a comfortable margin before expiry rather than running up to it.

Spreading clients across that window is what prevents the “stampede” effect where a whole fleet renews at the same moment.

The replaces field

During a newOrder request, an ARI-aware client can include a replaces field containing the certID of the certificate it intends to replace.

acme-proxy validates it against all three of RFC 9773 §5’s correspondence rules. The certID is decoded into an Authority Key Identifier and a serial number, the predecessor order is looked up, and then:

  1. The AKI must match the predecessor’s issuer — the serial alone is not enough, since serials are only unique per issuer. (A certificate stored before this check existed may have no recorded AKI; that case falls back to matching on serial alone, for backwards compatibility.)
  2. The predecessor must belong to the requesting account. You cannot claim to replace someone else’s certificate.
  3. The new order must share at least one identifier with the predecessor. A renewal that covers none of the same names is not a replacement.

Failing any of them is malformed; an unknown certID likewise.

Concurrency guard: a client cannot have two orders replacing the same predecessor. A second newOrder naming a replaces value already claimed gets 409 alreadyReplaced. An order that later becomes invalid releases its claim, so a failed attempt does not permanently block a retry.

The accepted replaces value is stored and reflected back on the 201 response and on every subsequent poll of the order.