<!-- https://pkizerotohero.com/handbook/acme/ | Markdown mirror of the HTML page | PKI Zero to Hero, by Duyutech BV -->

> How ACME (RFC 8555) works: orders, HTTP-01, DNS-01 and TLS-ALPN-01 challenges, ARI renewal timing, rate limits, clients such as certbot and cert-manager.

Source: https://pkizerotohero.com/handbook/acme/ · Last reviewed: 2026-10-20

Part VI: Running PKI · Chapter 20

# ACME and the 47-day schedule

**In one sentence:**

ACME lets software prove control of a name, then fetch, renew and install certificates automatically: the only practical way to live with very short certificate lifetimes.

## Who is this for

- [IT ops](https://pkizerotohero.com/start/#itops)
- [Developer](https://pkizerotohero.com/start/#developer)
- [Expert](https://pkizerotohero.com/start/#expert)
- [Leader](https://pkizerotohero.com/start/#leader)
- [Beginner](https://pkizerotohero.com/start/#beginner)

Level: **Practitioner**

- [New to this? Start with The idea](https://pkizerotohero.com/handbook/acme/#the-idea)
- [Developer? Jump to How it really works](https://pkizerotohero.com/handbook/acme/#how-it-really-works)
- [IT ops? At work](https://pkizerotohero.com/handbook/acme/#at-work)
- [Leader? Why it matters](https://pkizerotohero.com/handbook/acme/#why-it-matters-to-the-business)

## The idea

- Beginner

Getting a certificate by hand takes many steps. You create a key and a [CSR](https://pkizerotohero.com/handbook/csr/), paste the CSR into a CA’s web portal, prove that you control the domain, download the certificate, install it with its chain, reload the server and set a reminder for next time. Done once a year, that is tolerable. Done at least eight times a year for every name, across hundreds of names, it is not.

[ACME](https://pkizerotohero.com/handbook/glossary/#acme), the Automatic Certificate Management Environment, is an open protocol that lets software do all of it. A program on your side, the **ACME client**, talks to the CA’s **ACME server**. The client:

1. creates an account with the CA;
2. orders a certificate for one or more names;
3. proves it controls those names by answering a [challenge](https://pkizerotohero.com/handbook/glossary/#acme-challenge), for example by publishing a token at a web address or in DNS;
4. sends a CSR and downloads the signed certificate;
5. installs it, reloads the service and starts again before the certificate expires.

The private key never leaves your server. ACME was built for Let’s Encrypt and is now an internet standard, RFC 8555. Many public CAs support it, and so do private CA products, so the same tools work for internal certificates too.

ACME does not remove the need for care. A renewal robot that fails quietly is worse than a person with a calendar, because everyone assumes it works. Automation and monitoring go together (see [Inventory, expiry and renewal](https://pkizerotohero.com/handbook/certificate-lifecycle/)).

In the game

The renewal robot

In the game, Ken builds a robot in the Robot Workshop. It walks to the Notary, proves the castle belongs to Rosa by placing a token at the castle gate, and brings back a fresh certificate before the old one runs out. Where it stops being true: the robot is a small program, the “token” is a file or DNS record that the CA checks over the internet, and nobody hears a robot that has broken down. You still need monitoring to notice.

## How it really works

- Developer
- Expert

### What happens in an ACME exchange?

Every ACME request is an HTTPS POST whose body is signed with the client’s **account key**, a key pair that belongs to the ACME account and is separate from the certificate’s key. Each request also carries a fresh one-time value, a nonce, so that a recorded request cannot be replayed ([RFC 8555 section 7.2](https://www.rfc-editor.org/rfc/rfc8555#section-7.2)). The client finds every endpoint in the server’s directory ([section 7.1.1](https://www.rfc-editor.org/rfc/rfc8555#section-7.1.1)). This is Let’s Encrypt’s real directory:

```bash
curl -s https://acme-v02.api.letsencrypt.org/directory
```

```json
{
  "Gzv7tmjYRzs": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417",
  "keyChange": "https://acme-v02.api.letsencrypt.org/acme/key-change",
  "meta": {
    "caaIdentities": [
      "letsencrypt.org"
    ],
    "profiles": {
      "classic": "https://letsencrypt.org/docs/profiles#classic",
      "shortlived": "https://letsencrypt.org/docs/profiles#shortlived",
      "tlsserver": "https://letsencrypt.org/docs/profiles#tlsserver"
    },
    "termsOfService": "https://letsencrypt.org/documents/LE-SA-v1.8-July-06-2026.pdf",
    "website": "https://letsencrypt.org"
  },
  "newAccount": "https://acme-v02.api.letsencrypt.org/acme/new-acct",
  "newNonce": "https://acme-v02.api.letsencrypt.org/acme/new-nonce",
  "newOrder": "https://acme-v02.api.letsencrypt.org/acme/new-order",
  "renewalInfo": "https://acme-v02.api.letsencrypt.org/acme/renewal-info",
  "revokeCert": "https://acme-v02.api.letsencrypt.org/acme/revoke-cert"
}
```

The odd first entry is deliberate: Let’s Encrypt adds a random key so that clients learn to ignore fields they do not know. Then the exchange runs like this:

1. **Account** ([section 7.3](https://www.rfc-editor.org/rfc/rfc8555#section-7.3)). The client registers its account key with a POST to `newAccount`. Commercial CAs often link this to an existing customer account with External Account Binding ([section 7.3.4](https://www.rfc-editor.org/rfc/rfc8555#section-7.3.4)).
2. **Order** ([section 7.4](https://www.rfc-editor.org/rfc/rfc8555#section-7.4)). The client lists the names it wants. An order moves through the states `pending`, `ready`, `processing` and `valid`, or ends as `invalid` ([section 7.1.6](https://www.rfc-editor.org/rfc/rfc8555#section-7.1.6)).
3. **Authorization** ([section 7.5](https://www.rfc-editor.org/rfc/rfc8555#section-7.5)). For each name, the server offers one or more challenges.
4. **Challenge** ([section 7.5.1](https://www.rfc-editor.org/rfc/rfc8555#section-7.5.1)). The client publishes a key authorization, the challenge token joined to a hash of its account key ([section 8.1](https://www.rfc-editor.org/rfc/rfc8555#section-8.1)), and tells the server it is ready. The CA checks it from the internet.
5. **Finalize.** Once every authorization is valid and the order is `ready`, the client sends its CSR to the order’s finalize URL.
6. **Download** ([section 7.4.2](https://www.rfc-editor.org/rfc/rfc8555#section-7.4.2)). The client fetches the certificate with its chain in PEM format.

*Diagram: Two lifelines, the ACME client on your server and the ACME server at the CA. 1: the client creates an account with its account key. 2: it sends a new order for the names. 3: the server returns authorizations and challenges. 4: the client says the challenge is ready. 5: the CA checks the file, the TXT record or TLS-ALPN. 6: the client finalizes by sending the CSR. 7: it downloads the certificate chain, marked with a tick. For renewal, the client asks renewalInfo when to renew, then repeats from step 2.*

One ACME issuance, from account to certificate.

### How does the CA check that you control the name?

There are three standard challenge types:

| Challenge | What the CA checks | Port | Wildcards | Good fit |
| --- | --- | --- | --- | --- |
| HTTP-01 ([RFC 8555 section 8.3](https://www.rfc-editor.org/rfc/rfc8555#section-8.3)) | A file at `http://<name>/.well-known/acme-challenge/<token>` | 80 | No | One web server, or a load balancer that serves the file |
| DNS-01 ([section 8.4](https://www.rfc-editor.org/rfc/rfc8555#section-8.4)) | A TXT record at `_acme-challenge.<name>` holding the base64url SHA-256 digest of the key authorization | none | Yes | Wildcards, many servers, names that are not reachable from the internet |
| TLS-ALPN-01 (RFC 8737) | A special certificate offered on a TLS connection that negotiates the protocol `acme-tls/1` | 443 | No | When port 80 is closed and the client controls the TLS endpoint |

Let’s Encrypt’s [FAQ](https://letsencrypt.org/docs/faq/) is explicit: “Wildcard issuance must use the DNS-01 challenge.” Its [challenge-types page](https://letsencrypt.org/docs/challenge-types/) lists the trade-offs, and warns that “Keeping API credentials on your web server is risky”. You can limit that risk: the same page says “you can use CNAME records or NS records to delegate answering the challenge to other DNS zones”. Point `_acme-challenge` at a small zone that holds nothing else, and give the client an API key for that zone only.

Publicly trusted CAs must also check domain control from several network locations, not just one (Baseline Requirements section 3.2.2.9). This makes it much harder to fool the CA by hijacking the network path to a single location.

### When should a client renew?

Old clients renewed on a fixed schedule, such as a monthly cron job, or a fixed number of days before expiry. ACME Renewal Information, [ARI](https://pkizerotohero.com/handbook/glossary/#ari), replaces that guesswork. It is RFC 9773, on the IETF standards track. The CA publishes a `renewalInfo` endpoint, and for each certificate it suggests a renewal window. [RFC 9773](https://www.rfc-editor.org/rfc/rfc9773) explains why: a CA “could suggest that clients renew prior to a mass-revocation event to mitigate the impact of the revocation”, or spread out a coming spike of renewals. The recommended client behaviour is to “select a uniform random time within the suggested window”.

Anyone can ask. The certificate is identified by its Authority Key Identifier and serial number, both base64url-encoded and joined with a dot. This is the real answer for the letsencrypt.org certificate seen in this handbook:

```bash
curl -s https://acme-v02.api.letsencrypt.org/acme/renewal-info/uVnyjs8i8IbTN0j_dhQYuoLYVYc.BUOTO-OGs6KzrdU08hA7yLZf
```

```json
{
  "suggestedWindow": {
    "start": "2026-11-02T17:18:36Z",
    "end": "2026-11-04T12:29:25Z"
  }
}
```

The certificate runs from 4 September to 3 December, so the window falls about two-thirds of the way through its life. Let’s Encrypt’s [integration guide](https://letsencrypt.org/docs/integration-guide/) asks clients to check ARI “at least twice a day”. Without ARI, it recommends renewing “when they have a third of their total lifetime left”, or halfway through for very short-lived certificates.

*Diagram: A timeline for a real Let's Encrypt certificate. Issued on 4 September, in service until the ARI window of 2 to 4 November, marked with a tick, followed by time to retry and fix problems until it expires on 3 December. The client checks renewalInfo twice a day and renews inside the window. The CA may move the window.*

Renewing at about two-thirds of the lifetime leaves a third for retries.

### What does the shrinking schedule change for ACME?

Two limits shrink together. Certificates will last at most 47 days from 15 March 2029, and a CA may reuse a domain validation for only 10 days from 15 March 2029. So nearly every renewal will need a fresh challenge. Your challenge path, whether the web root, the DNS API or port 443, must work every single time, not just on the day you set it up.

Let’s Encrypt has published its own path ([announcement](https://letsencrypt.org/2025/12/02/from-90-to-45)). Today its default is 90 days. It offers 45-day certificates in its opt-in tlsserver profile from 13 May 2026. The default falls to 64 days from 10 February 2027, then to 45 days from 16 February 2028, when its authorization reuse also drops to 7 hours. It also offers six-day certificates to those who opt in. The real directory above shows the three profiles, `classic`, `tlsserver` and `shortlived`, and a client picks one when it orders.

### What are rate limits?

Public CAs limit how often one account or domain may request certificates, to protect the service. Let’s Encrypt’s current limits ([rate limits](https://letsencrypt.org/docs/rate-limits/)) include up to 50 certificates per registered domain every 7 days, up to 5 certificates for the exact same set of names every 7 days and up to 5 failed validations per name, per account, per hour. A healthy client renewing on time never comes close. A broken script that retries in a tight loop hits them fast. Two habits avoid trouble:

- **Test against staging.** Let’s Encrypt recommends its staging environment “when testing or troubleshooting your applications”.
- **Use ARI.** “Renewals coordinated by ARI offer the unique benefit of being exempt from all rate limits.”

### Can I run ACME for internal names?

Yes. A private CA can speak ACME too. For example, smallstep’s step-ca “works with any ACME-compliant (specifically, ACMEv2; RFC8555) client”, and by default it issues certificates with “much shorter 24 hour lifetimes” ([smallstep](https://smallstep.com/docs/tutorials/acme-protocol-acme-clients/)). You point the same clients at your own directory URL. The CA can still validate names your public DNS never sees, as long as it can reach them. The [private CA](https://pkizerotohero.com/handbook/private-ca/) chapter covers when that is a good idea.

## At work

- Developer
- IT ops

### Which client should I use?

| Client | Where it fits | ARI support |
| --- | --- | --- |
| [certbot](https://eff-certbot.readthedocs.io/) | Linux servers, with nginx and Apache plugins | Yes, since certbot 4.1.0 |
| [acme.sh](https://github.com/acmesh-official/acme.sh) | Any Unix shell, no dependencies, many DNS APIs. Its default CA is ZeroSSL, so set the CA you want explicitly | Yes, on by default since acme.sh 3.1.4 |
| [lego](https://go-acme.github.io/lego/) | A single Go binary, and a Go library | Yes (RFC 9773 listed) |
| [cert-manager](https://cert-manager.io/docs/) | Kubernetes: certificates as resources, stored in secrets | Experimental: off by default, behind the `ACMEUseARI` feature gate (alpha since v1.21) |
| [win-acme](https://www.win-acme.com/) | Windows and IIS; it creates a scheduled task for renewal | Yes, based on a draft of the ARI specification |

### How do I test certbot safely?

```bash
sudo certbot renew --dry-run
```

`--dry-run` performs “a test run against the Let’s Encrypt staging server, obtaining test (invalid) certificates but not saving them to disk”. Run it after every change to DNS, firewalls or web server configuration. Most packages install a timer or cron job that runs `certbot renew` regularly. Check that it exists with `systemctl list-timers`.

Then make sure the service picks up the new certificate. A deploy hook runs “once for each successfully issued certificate, including on subsequent renewals”:

```bash
sudo certbot renew --deploy-hook "systemctl reload nginx"
```

Point your server at `fullchain.pem`, not `cert.pem`. The certbot documentation says `fullchain.pem` “is what Apache >= 2.4.8 needs for SSLCertificateFile, and what Nginx needs for ssl\_certificate”. Serving `cert.pem` alone leaves out the intermediate. Browsers often hide that mistake, but curl, Java and Python fail with errors like [unable to get local issuer certificate](https://pkizerotohero.com/errors/curl-unable-to-get-local-issuer-certificate/) or [verify error 21](https://pkizerotohero.com/errors/openssl-verify-error-21/).

### How do I do it in Kubernetes?

With cert-manager, you declare an issuer once and a `Certificate` per name. This example uses Let’s Encrypt’s staging directory and the HTTP-01 challenge through an nginx ingress:

```yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: pki-team@example.com
    privateKeySecretRef:
      name: letsencrypt-staging-account-key
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: www-example-com
  namespace: my-app
spec:
  secretName: www-example-com-tls
  dnsNames:
    - www.example.com
  issuerRef:
    name: letsencrypt-staging
    kind: ClusterIssuer
```

cert-manager stores the key and certificate in the secret `www-example-com-tls` and renews by default “2/3 through the X.509 certificate’s duration” ([cert-manager](https://cert-manager.io/docs/usage/certificate/)). Switch the `server` to the production directory once staging works. Check progress with `kubectl get certificate -n my-app` and `kubectl describe certificate www-example-com -n my-app`.

### How do I point a client at a private ACME server?

Most clients take a directory URL. With certbot, add `--server`:

```bash
sudo certbot certonly --webroot -w /var/www/html \
  --server https://ca.internal/acme/acme/directory -d app.internal.example
```

The client host must trust the private CA’s root to talk to that server over HTTPS.

The lifetime calendar shows how often your certificates renew under each step of the schedule:

*Interactive tool: Lifetime calendar (runs in the browser at [/tools/lifetime/](https://pkizerotohero.com/tools/lifetime/))*

## Common mistakes

- **“ACME is a Let’s Encrypt thing.”** It is an internet standard. Many public CAs and private CA products speak it, so one set of tools covers all your certificates.
- **“HTTP-01 can get me a wildcard.”** Wildcards need DNS-01.
- **“The renewal job runs, so we are covered.”** Only if the service reloads the new certificate and your monitoring checks the live endpoint.
- **“I’ll test against production.”** Use staging or `--dry-run`. A broken script that loops against production quickly hits the rate limits.
- **“Renew on the first of every month.”** Fixed schedules cluster load and ignore the CA’s advice. Check ARI often and renew inside the suggested window.
- **“Give every web server full DNS API access.”** Delegate `_acme-challenge` to a small zone with a narrowly scoped key.

## Why it matters to the business

- Leader

Why it matters to the business

ACME is how you survive short lifetimes

ACME turns certificate renewal from a recurring manual task into a background process, using free, standard tools. As lifetimes shrink towards 47 days, it is the practical way to keep services online without growing the team. The costs sit in the edges: DNS API access, legacy appliances that cannot run a client, and the monitoring that catches failures. Decisions to make: require ACME support when you buy appliances and hosting, standardise on a few clients, and make the ability to switch CA by changing one URL part of your continuity plan.

## Check yourself

Check yourself

You need a certificate for \*.example.com. Which ACME challenge can you use?

1. HTTP-01
2. DNS-01
3. TLS-ALPN-01

Show answer

Answer B DNS-01

What happened

Wildcard certificates can only be validated with DNS-01.

Why

A wildcard covers names that do not exist yet, so the CA checks control of the DNS zone itself, through a TXT record at \_acme-challenge.

The rule

Wildcards need DNS-01. Delegate \_acme-challenge to keep DNS credentials narrow.

Check yourself

What does ACME Renewal Information (ARI) give an ACME client?

1. A window of time in which the CA suggests renewing
2. A copy of the CA's private key for faster signing
3. A list of revoked certificates

Show answer

Answer A A window of time in which the CA suggests renewing

What happened

ARI returns a suggested renewal window for each certificate.

Why

The CA can spread renewals out, or ask for early renewal before a mass revocation.

The rule

Check ARI regularly and renew at a random time inside the window.

Check yourself

You changed your firewall and want to know whether certbot can still renew. What is the safe check?

1. Delete the certificate and request a new one
2. Run certbot renew --dry-run
3. Wait for the expiry email

Show answer

Answer B Run certbot renew --dry-run

What happened

A dry run performs the full exchange against the staging server without saving anything.

Why

It exercises the challenge path you just changed, without touching production certificates or rate limits.

The rule

Test every change to DNS, firewalls or web servers with a dry run.

## Go deeper

- [RFC 8555](https://www.rfc-editor.org/rfc/rfc8555): the ACME protocol, including HTTP-01 and DNS-01.
- [RFC 8737](https://www.rfc-editor.org/rfc/rfc8737): the TLS-ALPN-01 challenge.
- [RFC 9773](https://www.rfc-editor.org/rfc/rfc9773): ACME Renewal Information (ARI).
- [Let’s Encrypt: challenge types](https://letsencrypt.org/docs/challenge-types/): the trade-offs of each challenge, and DNS delegation.
- [Let’s Encrypt: rate limits](https://letsencrypt.org/docs/rate-limits/) and [profiles](https://letsencrypt.org/docs/profiles/): current limits and certificate profiles.
- [Let’s Encrypt: integration guide](https://letsencrypt.org/docs/integration-guide/): when to renew and how to build a reliable client.
- [certbot documentation](https://eff-certbot.readthedocs.io/en/stable/using.html) and [cert-manager: Certificate resources](https://cert-manager.io/docs/usage/certificate/): the two most common clients in detail.

The crash course covers ACME in [lesson 9, Running PKI](https://pkizerotohero.com/course/running-pki/).

**Early edition.** Checked against the standards; an independent expert review is in progress. Found a mistake? [Tell us](https://pkizerotohero.com/contact/?topic=content-error&page=/handbook/acme/).

Last reviewed 20 October 2026Edition 0.9

## Keep going

Crash course: [Lesson 9: Running PKI](https://pkizerotohero.com/course/running-pki/)

### Error pages for this chapter

- [SSL certificate problem: unable to get local issuer certificate](https://pkizerotohero.com/errors/curl-unable-to-get-local-issuer-certificate/)
- [verify error:num=21:unable to verify the first certificate](https://pkizerotohero.com/errors/openssl-verify-error-21/)

### How-to guides

- [How to check when a certificate expires, and monitor it](https://pkizerotohero.com/guides/check-certificate-expiry/)
- [How to get and renew Let's Encrypt certificates with certbot](https://pkizerotohero.com/guides/certbot-lets-encrypt/)
- [How to automate certificates in Kubernetes with cert-manager](https://pkizerotohero.com/guides/kubernetes-cert-manager/)
- [How to automate certificates on Windows with win-acme](https://pkizerotohero.com/guides/win-acme-windows/)
- [How to get a wildcard certificate with DNS-01](https://pkizerotohero.com/guides/wildcard-dns-01/)
- [How to run a small private CA with step-ca (lab)](https://pkizerotohero.com/guides/private-ca-step-ca/)
- [How to prepare for short-lived certificates: a checklist](https://pkizerotohero.com/guides/prepare-47-day-certificates/)

### Tools

- [Lifetime calendar](https://pkizerotohero.com/tools/lifetime/): See how long a certificate may live on any date, and when to renew.

### Topics

- [Lifecycle and automation](https://pkizerotohero.com/topics/lifecycle-and-automation/)
