ACME & Let's Encrypt
Free, automated TLS — http-01 vs dns-01 vs tls-alpn-01.
ACME & Let's Encrypt
Until 2015, getting a TLS certificate meant filling in a web form, paying a CA, copying base64 between portals, and remembering to do it all again in a year. Let's Encrypt and the ACME protocol erased that whole experience. Free certs, automated end-to-end, valid for 90 days, renewed by a cron job. The web went from "TLS is annoying and rare" to "TLS is on every site" in a few years.
What ACME actually is
RFC 8555 defines ACME — Automatic Certificate Management Environment — a protocol between an ACME client (your server, certbot, cert-manager) and an ACME CA (Let's Encrypt, ZeroSSL, Buypass, Google Public CA, your enterprise's stepCA).
The protocol exchanges JSON messages over HTTPS. The client says "I'd like a cert for example.com"; the CA says "prove you control example.com by doing X"; the client does X; the CA verifies, signs, returns the cert. All automated.
client ACME CA
│ │
├── newAccount ──────────────────►│
│◄──────────── account URL │
│ │
├── newOrder (CN=example.com) ──►│
│◄──────────── order + auths │
│ │
├── (challenge: serve token at...)│
│ │
├── notify "I'm ready" ─────────►│
│ (CA validates the challenge) │
│◄──────────── status: valid │
│ │
├── finalize (with CSR) ────────►│
│◄──────────── cert chain │
The three challenges
ACME defines three ways for a client to prove it controls a domain. Each fits different operational shapes.
http-01 — easiest, port 80 required
The CA tells the client "serve a specific token at http://example.com/.well-known/acme-challenge/<token>". The CA then fetches that URL, follows redirects (HTTPS is fine), and verifies the response.
- Pros: Trivial — most servers can serve a static file. Works for shared hosting, simple VPS.
- Cons: Doesn't support wildcards (
*.example.com). Requires port 80 to be reachable from the public internet.
dns-01 — only choice for wildcards
The CA tells the client "add a TXT record at _acme-challenge.example.com with value Y". The client (or its DNS API integration) creates the record; the CA queries DNS and verifies.
- Pros: Doesn't need any port open on the server. Supports wildcards. Works for internal services that aren't publicly reachable.
- Cons: Needs DNS API access. DNS propagation can be slow (most automation tools poll until the record is visible from authoritative nameservers).
tls-alpn-01 — port 80 blocked? use 443
The CA does a TLS handshake on port 443 and asks for a special ALPN protocol (acme-tls/1). The server responds with a self-signed cert containing the challenge token in an extension.
- Pros: Only needs port 443 open. No HTTP server needed.
- Cons: Requires careful TLS server configuration — most off-the-shelf web servers don't support tls-alpn-01 natively. Caddy, Traefik, and the
simple_acme_dnslibraries do.
Decision tree
Need a wildcard cert?
YES → dns-01 (only option)
NO ↓
Port 80 open and reachable from the public internet?
YES → http-01 (simplest)
NO ↓
Port 443 open and you control the TLS stack?
YES → tls-alpn-01
NO → can't ACME this domain — use a different CA or workflow
Let's Encrypt — the dominant CA
Let's Encrypt is run by ISRG, a 501(c)(3) non-profit. As of 2024 it issues over half the public-internet TLS certs in existence. Free, automated, no exception classes — the same flow whether you're issuing one cert for a personal site or one million for a CDN edge.
Key parameters:
- Validity period: 90 days. Renew at 60 days remaining (default for most clients).
- Rate limits:
- 50 certs per registered domain per week.
- 5 duplicate certs per identical name set per week.
- 300 new orders per account per 3 hours.
- Staging environment:
acme-staging-v02.api.letsencrypt.org— same flow but issues untrusted certs. Always test there first to avoid burning rate limits. - Revocation: Unlimited and free, via the same ACME API.
- OCSP stapling: Required by Let's Encrypt as of 2025 (in lieu of CRL).
Toolchain
- Certbot — EFF's reference client. Available on every Linux distro. Has plugins for Apache, Nginx, standalone, webroot, DNS providers (Cloudflare, Route53, etc.).
- acme.sh — pure-shell ACME client. Tiny, runs anywhere, supports >100 DNS providers.
- cert-manager — Kubernetes-native. CRDs for Issuer, ClusterIssuer, Certificate. Reconciliation loop handles renewal, secret updates, ingress wiring.
- Caddy — web server with automatic HTTPS built in. One config line and Caddy handles ACME, OCSP, renewal, all transparently.
- Traefik — same idea for reverse proxies. ACME built in.
- lego — Go ACME library + CLI. Embeddable. The internals of cert-manager and Traefik.
For new deployments, Caddy or cert-manager are usually the right choice. Manual certbot is mostly for legacy retrofits.
Operational gotchas
- Test in staging. Burning the production rate limit takes a week to recover from.
- Renew at 30+ days remaining, not at expiry. ACME can fail (DNS hiccup, port 80 firewall change); you need slack.
- Watch the rate limits per "registered domain", which means the eTLD+1.
a.example.comandb.example.comcount against the sameexample.comquota. - Wildcards are dns-01 only. If you can't automate DNS, you can't get wildcards from Let's Encrypt.
- OCSP stapling matters. Without it, browsers do an OCSP lookup themselves — slower, less private. Configure your web server (
ssl_stapling onfor Nginx) to cache and serve OCSP responses. - cert-manager + ingress-nginx is the K8s stack. Annotate the Ingress with
cert-manager.io/cluster-issuer: letsencrypt-prodand you're done. - Don't forget IPv6. http-01 challenges follow DNS — if your AAAA record is broken, the CA may try IPv6 first and fail.
Beyond Let's Encrypt
ACME isn't a Let's Encrypt monopoly. It's a public protocol implemented by:
- ZeroSSL (free + paid tiers; covers some quirks of LE rate limits).
- Buypass (free LE alternative, longer validity period — 180 days).
- Google Trust Services Public CA (Google's public ACME CA).
- stepCA (Smallstep's open-source CA — run your own ACME server for internal services).
- AWS Certificate Manager for ACME via AWS-issued certs (limited scope).
You can configure most ACME clients to point at a different directoryUrl and use any of these. Useful for redundancy: when LE has an outage, having a secondary configured saves you.
The takeaway
If your service has a public TLS endpoint, ACME automation is the right answer in 2024. The tooling is mature, the protocol is stable, and free certs renewed by a cron job is now the baseline expectation. There's no excuse for "I forgot to renew" outages anymore.
If you're not yet using ACME, the cheapest path is:
- Install Caddy. Point it at your service. Done.
If you can't change the web server:
apt install certbot python3-certbot-nginx.certbot --nginx -d example.com.- Verify the cron timer is enabled (
systemctl status certbot.timer).
Five minutes, full automation, no expiry surprises.
Tools in the wild
4 tools- cliCertbotfree tier
EFF's official ACME client. apt/yum/brew packaged. Reasonable defaults; webroot or standalone modes.
- cliacme.shfree tier
Pure-shell ACME client — no Python, no system deps. Works on tiny embedded systems.
- servicecert-managerfree tier
Kubernetes-native cert lifecycle. Ingress annotations → Issuer → Certificate, fully automated.
- serviceCaddyfree tier
Web server with built-in automatic HTTPS via ACME. One config line, certificates handled.