Protocol Support
acme-proxy implements RFC 8555 in full, plus the extensions an ACME client in
2026 expects to find. This page is the conformance summary: what a client can
call, which RFC section governs it, and what is deliberately not implemented.
Everything here is served per profile, under /profile/<name>/. There is no
ACME at the bare root — see Profiles & Routing.
Resources
Every row is reachable at {base_url}/profile/<name><path>. The Advertised
column says whether the directory object names it: a client is expected to find
advertised resources by reading the directory rather than by constructing paths.
| Path | Method | RFC | Advertised | Notes |
|---|---|---|---|---|
/directory | GET, POST | §7.1.1 | — | It is the entry point; §6.3 requires POST-as-GET to work too. |
/newNonce | HEAD, GET, POST | §7.2 | yes | All three forms. |
/newAccount | POST | §7.3 | yes | Find-or-create by public key: 201 for a new account, 200 for an existing one, Location either way. |
/acct/{id} | POST | §7.3.2, §7.3.6 | — | Contact update and deactivation. kid-authenticated. There is deliberately no unauthenticated GET. |
/acct/{id}/orders | POST | §7.1.2.1 | — | The account’s order list, filtered as §7.1.2.1 requires. |
/keyChange | POST | §7.3.5 | yes | Key Rollover. |
/newOrder | POST | §7.4 | yes | Accepts notBefore/notAfter and RFC 9773’s replaces. |
/order/{id} | POST | §7.1.3 | — | POST-as-GET. |
/order/{id}/finalize | POST | §7.4 | — | Takes the CSR; hands it to the configured signer. |
/authz/{id} | POST | §7.5, §7.5.2 | — | One URL serves both the read and the deactivation, told apart by whether a payload arrived. |
/chall/{id} | POST | §7.5.1 | — | Triggers validation. Both outcomes are 200. |
/certificate/{id} | POST | §7.4.2 | — | POST-as-GET; PEM chain. |
/revokeCert | POST | §7.6 | yes | Revocation & CRL. |
/renewalInfo/{certID} | GET | RFC 9773 §4.1 | yes | Unauthenticated. Advertised without the id — §4.1 has the client append it. |
/crl | GET | RFC 5280 | no | Routed but not advertised: a CRL is CA infrastructure, not an ACME resource. |
/ca.pem | GET | — | no | The profile’s trust anchor, so installing it is one curl. 404 unless the backend has one of its own. Not advertised, for the same reason as /crl. See Trusting the CA. |
Two paths sit outside every profile, on the root router:
| Path | Purpose |
|---|---|
/health | Liveness. Outside the filter chain, the admission limiter and the nonce middleware — see Monitoring. |
/.well-known/acme-challenge/{token} | Mounted only when a signer backend has an http-01 token store to publish, i.e. signer.relay.challenge_strategy = "http01". See Relay. |
Two further paths are not on this listener at all. GET /metrics has a
socket of its own (off by default, [metrics]), so firewalling that port is
what controls who can read it — see
Monitoring. The web admin’s /ui and
/api likewise have their own listener; see
Web Admin.
Protocol behaviour worth knowing
Every signed request is checked the same way. The media type
(application/jose+json), any crit header, the JWS url against the route
actually reached, and the nonce are all verified before a handler runs, so no
resource can forget one. jwk and kid are mutually exclusive per §6.2, and
the verification algorithm never rests on the client’s alg alone. See
Architecture.
Refusals are problem documents. Every rejection is
application/problem+json with an RFC 8555 URN type. A multi-identifier order
rejected on several names comes back as one compound problem with a
subproblems entry per identifier (§6.7.1); a single rejection stays its own
type, unwrapped.
A POST always carries a fresh Replay-Nonce, errors included (§6.5). GET /directory, GET /crl, GET /ca.pem and GET /renewalInfo do not mint one —
nothing asks them to, and each nonce is a committed database write.
Extensions
| Extension | RFC | Default | Page |
|---|---|---|---|
| External Account Binding | §7.3.4 | off | EAB |
| Account key rollover | §7.3.5 | always on | Key Rollover |
| Renewal Information (ARI) | RFC 9773 | always on | ARI |
| Terms of service | §7.3.3 | off | Set meta.terms_of_service and newAccount starts enforcing it. |
| Wildcard identifiers | §7.1.3 | requires dns-01 | Challenge Validation |
Directory metadata
The directory’s meta object carries only what is configured. An unset member
is omitted, never sent empty — "website": "" says less than saying
nothing.
externalAccountRequiredappears astruewhen EAB is on for that profile.termsOfService,websiteandcaaIdentitiescome from[meta].
meta.terms_of_service is the one with teeth: setting it turns on §7.3.3, so
newAccount then refuses a request without termsOfServiceAgreed: true (403 userActionRequired plus a Link: rel="terms-of-service" header), and the
account object starts reflecting the field.
Not implemented
Stated explicitly, because each is something a reader may reasonably expect:
- CAA checking.
meta.caa_identitiesis advertised to clients; this server does no CAA lookup of its own. Where the relay backend is in use, the upstream CA performs its own. - OCSP. Revocation is published as a CRL at
GET /crl. There is no OCSP responder, and noauthorityInfoAccessOCSP pointer is ever written into an issued certificate. The local CA does write thecaIssuershalf of that extension, and acRLDistributionPointspointer, once an operator names the URLs — see Local CA. - Identifier types other than
dns.newOrderaccepts DNS names, including wildcards;ipidentifiers (RFC 8738) andpermanent-identifierare not supported. - Pre-authorization (§7.4.1). The directory does not advertise
newAuthz, and it is not routed. Authorizations exist only as part of an order. POSTto/renewalInfo— RFC 9773 §4.3’s optional client-side renewal signal. TheGEThalf is implemented.