So there I was, sipping a late coffee while a production deploy ticked away, when a message popped up: “Wildcard cert needed in 10 minutes. Any chance?” You know that feeling—you can almost hear the clock ticking. I smiled because, years ago, that would’ve sent me into panic mode. Now? I’ve learned when to reach for HTTP‑01, when DNS‑01 saves the day, and when TLS‑ALPN‑01 is the quiet hero nobody talks about. And yes, we hit the deadline, and the world kept spinning.
Ever had that moment when you’re staring at an SSL error, a countdown in your head, and you’re not sure which ACME challenge to use? You’re not alone. The good news is you don’t have to guess. Each challenge type fits a different shape of problem—you just need to know the shapes. In this post, we’ll walk through the three main ACME validation methods, how they feel in real life, and the kinds of situations where each one shines. No drama, no jargon for the sake of jargon—just the real talk I wish someone had given me earlier.
The ACME Story in Plain English
Here’s the simple picture: certificate authorities need proof that you control a domain before they hand you a shiny TLS certificate. The ACME protocol is the handshake that automates this trust dance. You ask for a cert, they challenge you to prove control, you respond the right way, and boom—certificate issued. There are three main ways to prove it: by serving a special file over HTTP, by placing a special TXT record in DNS, or by presenting a special certificate over a specific TLS protocol on port 443. Those are HTTP‑01, DNS‑01, and TLS‑ALPN‑01.
Think of it like delivery options. HTTP‑01 knocks on your front door at port 80 and asks for a note you taped to the inside of the glass. DNS‑01 checks your mailbox at the registrar and reads a note you tucked in there. TLS‑ALPN‑01 walks straight to the garage on port 443 and asks to see your special parking pass. Same goal, different paths.
In my experience, the biggest challenge isn’t the theory—it’s the messy, real-world stuff. Load balancers. CDNs. Kubernetes Ingress. Multi-tenant SaaS. Split-horizon DNS. WAFs that mean well but get in the way. And, of course, the tiny window between “certificate expiring soon” and “someone DMing you that the app looks untrusted now.” The trick is knowing which method steps around those obstacles instead of tripping over them.
One more thing: there’s no “best” challenge in the abstract. There’s the one that’s simplest for your setup today, and the one that scales for your setup tomorrow. Sometimes they’re the same. Sometimes you switch—and that’s fine. I do it all the time when a system grows up and needs something sturdier.
HTTP‑01: The Straight Shot (When the Web Server Is the Star)
When someone says, “I just need a cert for my site,” nine times out of ten, HTTP‑01 is what they actually want—even if they haven’t heard the name. It’s the simplest to picture: the CA visits http://yourdomain/.well-known/acme-challenge/some-token, and your server returns a tiny file with precisely the right content. If they can fetch it at port 80, you win.
There’s a reason HTTP‑01 feels so natural. You’re proving control via the same pathway people already use to reach your site. It’s easy to automate with a webroot or a small on-server helper. On a single server with vanilla Nginx or Apache, you can have it humming in minutes. Certbot, lego, or acme.sh can drop the token in a special folder; your web server is configured to serve that folder precisely as-is; certificate issued; renewals on autopilot.
But here’s the thing: the world is rarely “single server and nothing else.” The first bump in the road is port 80 itself. HTTP‑01 requires port 80 to be reachable from the public internet. If you’ve disabled port 80 entirely for security or aesthetics, HTTP‑01 won’t work. Redirecting 80 to 443 is fine—ACME will happily follow a redirect—but the initial knock still has to happen on 80. If a firewall slams the door, the CA can’t even start the conversation.
The second bump is anything that changes or filters the request before it hits your server. A WAF, CDN, or load balancer can get too clever and rewrite, compress, or block the challenge path. Reverse proxies sometimes handle that well with pass-through exceptions; sometimes not. I’ve had a CDN cache a 404 and stubbornly serve it for the challenge path until I purged it. Fun times. In those cases, a simple rule that bypasses caching and security for the challenge endpoint usually fixes it.
Then there’s the multi-server dance. If you’re running multiple web servers behind a load balancer, the challenge file has to be served consistently from whichever server gets the request. That means shared storage for the challenge folder, sticky sessions, or a small helper that intercepts the challenge and responds directly. I’ve done all three. The cleanest pattern is often having your reverse proxy or Ingress controller answer the challenge centrally, so you don’t have to sync files across nodes.
One random gotcha: some redirect rules accidentally swallow the challenge path. A global “redirect everything to HTTPS and www” can cause the challenge file to disappear or be rewritten. Whenever I set up HTTP‑01, I double-check two things: that /.well-known/acme-challenge is served as-is with no auth, and that the request doesn’t get rerouted to an app or a different hostname.
Where HTTP‑01 shines is the common case: a typical website or API served from a publicly reachable web server, no wildcard domains needed. It’s easy, it’s familiar, and it’s fast. If you’re using a CDN or WAF, it still works—you just have to make sure the challenge path is excluded from the fancy stuff. When I’m onboarding a simple site, HTTP‑01 is usually the first thing I try, because production likes boring and predictable.
When does HTTP‑01 not feel right? If you need wildcard certificates, you can stop reading this section: HTTP‑01 can’t do it. If your site is always behind a CDN that terminates TLS and refuses to pass challenge traffic to the origin, it can get awkward. And if port 80 is blocked or intentionally disabled, you’ll be happier with one of the other methods.
DNS‑01: The Scaler’s Favorite (Wildcard, SaaS, and Off-Path Control)
DNS‑01 is the proof that lives in your domain’s DNA. Instead of serving a file, you publish a TXT record named _acme-challenge.yourdomain with a specific value. The CA does a DNS lookup for that record, verifies it matches what they expect, and issues the certificate. You don’t need any web server at all—and that’s exactly why it’s powerful.
If you’ve ever needed a wildcard certificate—like *.example.com—DNS‑01 is your only option among the main challenges. I still remember my first wildcard rollout for a client who had apps popping up like mushrooms after rain. One certificate, one renewal system, and we were done. No chasing every subdomain. That was the day DNS‑01 earned a permanent spot in my toolkit.
Beyond wildcard, DNS‑01 is gold when your app sits behind layers: CDNs that terminate TLS, zero-trust networks, private origins, or environments where port 80 simply isn’t reachable. Since validation happens at the DNS layer, it doesn’t care about your web routing. I’ve used it to issue certs for services that weren’t even listening on the public internet—think internal dashboards published through tunnels or access gateways. The CA only needs to read your TXT record, and you’re good.
Now, the trade-off: automation depends on your DNS provider’s API. If your provider exposes a solid API, DNS‑01 is as smooth as HTTP‑01. If not, you end up clicking around in a dashboard every 60–90 days, which is exactly the kind of thing we forget until alerts start blinking. I’ve been there at midnight, adding TXT records by hand with a mug of tea and a sense of impending doom. These days, I try to avoid any setup that requires manual DNS.
Propagation is another subtlety. Your ACME client will create the _acme-challenge TXT record and immediately ask the CA to check it. Most good clients pause long enough for propagation, and many providers publish changes within seconds. But some providers have a lag or a form of eventual consistency. In those cases, a slightly longer wait before verification is your friend. Keeping the TTL on challenge records short also helps keep things snappy.
In multi-tenant SaaS, DNS‑01 scales beautifully. If you offer “bring your own domain” and want auto-SSL for every customer domain, HTTP‑01 quickly becomes a maze of routing and per-domain exceptions. With DNS‑01, you hook into DNS provider APIs—or use a delegated validation zone—and you can issue certs without touching the tenant’s web traffic path. I wrote about this model in detail in Bring Your Own Domain, Get Auto‑SSL: How DNS‑01 ACME Scales Multi‑Tenant SaaS Without Drama, and it still might be the single biggest quality-of-life upgrade for SaaS teams trying to avoid certificate chaos.
DNS architecture matters, too. If you’re using multiple DNS providers for redundancy or migration safety, automate thoughtfully. I run multi-provider DNS with octoDNS specifically so I can flip providers without breaking automation, and I covered the playbook in How I Run Multi‑Provider DNS with octoDNS (and Sleep Through Migrations). The reality: your ACME client needs to know which provider actually answers authoritative queries and how to write TXT records there. Keep that source of truth crystal clear.
Last thought here: CAA records. They decide which CAs are allowed to issue for your domain. If you lock that down (which you should), remember to update CAA when you change CAs or add a backup. I dug into that in The CAA Records Deep Dive. DNS‑01 and CAA are old friends—get them to play nicely, and your automation becomes both flexible and safe.
TLS‑ALPN‑01: The Quiet Specialist (When 443 Is Your Only Door)
TLS‑ALPN‑01 is the one most folks hear about last, but it’s a lifesaver when the other doors are shut. Here’s the gist: the CA connects to your server over TLS on port 443 and uses ALPN (Application-Layer Protocol Negotiation) to ask for a special protocol called acme-tls/1. Your server responds with a special, temporary certificate that proves you control the domain. No HTTP needed. No DNS changes needed. Just 443.
Why does this matter? Some environments never expose port 80. Others don’t want to touch DNS or can’t automate it easily. In tightly controlled networks, or where you’ve locked everything down to HTTPS only, TLS‑ALPN‑01 slides right through. I’ve used it in setups where a reverse proxy or Ingress could terminate TLS with a tiny helper that knows how to speak ALPN correctly, answer only for the challenge, and then disappear. It feels almost sneaky—in a good way.
But here’s the catch: if something terminates TLS in front of your server—like a CDN or a managed WAF that doesn’t pass through ALPN or SNI the way you need—TLS‑ALPN‑01 can’t work. The CA needs to see that special acme-tls/1 exchange all the way to the origin. With a fully proxied CDN, that’s usually a no. In those cases, DNS‑01 is your friend, because it sidesteps the traffic path entirely.
The other subtlety is that TLS‑ALPN‑01, like HTTP‑01, doesn’t do wildcard certificates. If you’re aiming for *.example.com, head back to DNS‑01. That’s not a bug; it’s just how the spec works. When I have a cluster or app that forbids port 80 and doesn’t need wildcards, I reach for TLS‑ALPN‑01 because it’s elegant and self-contained. It also plays nicely with immutable infrastructure because you don’t need to coordinate file writes to webroots.
If you want to peek under the hood, the ACME base protocol is documented in RFC 8555, and the TLS‑ALPN‑01 extension lives in RFC 8737. And if you prefer a friendlier overview, the Let’s Encrypt challenge types guide maps the lay of the land nicely.
Real-World Scenarios: Which One Fits?
Let me walk you through a few moments where picking the right challenge made all the difference. These aren’t contrived; they’re the kind of situations that show up on a Tuesday afternoon when you’re juggling three other priorities.
Scenario one: a single WordPress site on a VPS. No CDN in front, Nginx serving with a standard config, and port 80 is open. I’d go with HTTP‑01 every time. It’s the fewest moving parts, easy to debug, and renewals just work. If I’m already using something like acme.sh or certbot, I’ll point it to a webroot or use a small standalone server that spins up only for validation. Keep it boring, keep it reliable.
Scenario two: a site behind a CDN that proxies everything and refuses to pass the challenge cleanly to the origin. I tried poking holes for /.well-known/acme-challenge, but the CDN kept “helping” by caching and inspecting the request. Rather than fight it, I switched to DNS‑01. Now the certificate lifecycle is independent of the traffic path, which is exactly what you want when the network layer is opinionated.
Scenario three: wildcard needed by yesterday. The team wanted *.example.com for subdomains that spun up on demand. This is where DNS‑01 is the only sane choice. I wired the DNS provider API into the ACME client, set the TTLs low, and made sure propagation windows were long enough before the CA checked. On renewal day, no one had to be awake at 3 a.m. to paste a TXT record.
Scenario four: a private origin behind a tunnel and strict HTTPS-only policy. There was no incoming 80, and I didn’t want to open it even briefly. TLS‑ALPN‑01 was perfect here. The Ingress layer spoke ALPN, served the temporary validation cert, and nobody had to fiddle with DNS or console logins. If you’re experimenting with zero-trust networking and private publishing, you might enjoy how gentle that flow feels. If that topic interests you, I’ve also written about a related pattern in The Calm, Zero‑Trust Way to Publish Apps Without Opening a Single Port, which pairs nicely with thoughtful ACME automation.
Scenario five: multi-tenant SaaS with bring-your-own-domain onboarding. The team wanted to issue certificates as soon as a customer pointed their domain. Doing that with HTTP‑01 meant fancy routing and per-tenant exceptions—a headache that grows geometrically with every new domain. With DNS‑01, we built a clean, automated flow with delegated validation and job queues. The payoff was huge: onboarding felt instant, and certificate renewals became background noise. If you want the deeper playbook, the SaaS article I linked earlier breaks down the moving parts.
Scenario six: clusters and CAs. In Kubernetes, I’ve used cert-manager with both HTTP‑01 and DNS‑01. If your Ingress controller has a built-in solver for HTTP‑01, it’s lovely for conventional apps. But once you start serving many hostnames or wildcards, DNS‑01 simplifies the picture. I’ve also paired this with a backup CA strategy so rate limits don’t surprise me at scale, as I describe in Redundant ACME Automation That Just Works: acme.sh Fallback from Let’s Encrypt to ZeroSSL. Nothing like sleeping through renewals because your automation already knows Plan B.
Automation That Doesn’t Wake You Up at 3 a.m.
Let’s talk process, because the best challenge choice still fails if the automation is brittle. My north star is simple: if a renewal fails once, I don’t just fix the symptom—I make sure that failure can’t happen again without me hearing about it early and loudly. Here’s how that plays out with each challenge, woven into real workflows rather than theory.
With HTTP‑01, I prefer a single, predictable path for challenge files that bypasses application logic. In Nginx, that means a dedicated location for .well-known/acme-challenge that returns files directly from disk or a tiny memory-backed handler. No auth, no redirects, no headers that mangle content. In multi-node layouts, I’ll let the load balancer or Ingress intercept and answer the challenge itself, so I’m not syncing files across boxes. It’s one less moving part.
With DNS‑01, the heart of reliability is the DNS API integration. I keep credentials scoped tightly—just enough privileges to create and delete TXT records in the validation zone—and I store those secrets outside the app repo. If the provider supports it, I use a sub-zone like _acme-challenge.example.com delegated to a separate authoritative server or token management service. That way the validation plumbing stays separate from the “real” DNS, and teams don’t trip over each other. If you’re on multiple providers, make the source of truth explicit and keep the client pointed at the one actually answering queries. If you want a blueprint for multi-provider sanity, the octoDNS article I linked earlier shows exactly how I avoid surprises.
With TLS‑ALPN‑01, I test in the exact network path that production will use, because tiny differences in TLS termination can break validation. If there’s a CDN in front, TLS‑ALPN‑01 probably won’t work; I default to DNS‑01 instead. If the path is direct to the origin through a load balancer or Ingress you control, it’s usually smooth sailing. Keep an eye on SNI handling and make sure your ALPN helper only answers for the domains under validation, then gets out of the way.
No matter the challenge, I run a staging environment with a staging CA first. It’s astonishing how many “works on my machine” stories vanish when you point at a staging CA that behaves like the real one but doesn’t burn your rate limits. Once the flow is solid, I flip to production. I also keep a backup CA ready to go. If you’ve ever tripped rate limits or hit a temporary outage, having a fallback already integrated is priceless. I outlined a concrete approach in my acme.sh fallback guide, and it’s saved me more than once.
Alerting is the last part of the puzzle. I don’t want to hear about expirations a day before they happen—I want to know the first time a renewal fails, even if it still has weeks left. That means parsing logs, watching exit codes, or wiring a health check that verifies the live certificate on critical endpoints. For teams that value sleep, this is the difference between “Oh, that’s interesting” and “Why are we on a call at 2 a.m.?”
Now a quick word about policy and posture. If you lock down CAA records (please do), remember to include every CA you actually use, including the fallback. If you rotate providers, update CAA first. I’ve seen teams spend an hour debugging a perfectly good automation because CAA quietly said “nope.” Also watch your DNS TTLs for _acme-challenge; short TTLs make retries faster and keep you from waiting on propagation when something goes sideways.
One practical pro-tip: keep your ACME account key safe and backed up. If you rebuild automation from scratch and accidentally create a new account without realizing it, you might hit “too many new orders” limits and wonder why a flow that used to be fine is suddenly flaky. The account is part of your identity with the CA—treat it like a credential.
A Quick Mental Checklist (No Tables, Just Gut Checks)
When I’m choosing between HTTP‑01, DNS‑01, and TLS‑ALPN‑01 on a new project, I ask a few gentle questions. Is port 80 open and straightforward? If yes, HTTP‑01 is probably the least effort. Do I need wildcards or want the validation to be totally independent of traffic routing? DNS‑01 starts to look really attractive. Is port 80 closed but 443 is clean all the way to an origin I control, and no wildcard needed? TLS‑ALPN‑01 might be the sweet spot.
If the app sits behind a forceful CDN or WAF that I don’t fully control, DNS‑01 usually wins by sidestepping the path. If we’re talking bring-your-own-domain SaaS, DNS‑01 scales better than anything else. And if I’m in a place where I can’t—or don’t want to—touch DNS, but I do control how TLS terminates, TLS‑ALPN‑01 keeps things elegant.
That’s it. No scoring chart, no complicated matrix. Just a few sensible questions that match the messy reality of your setup. Your goal isn’t to pick the “fanciest” method—it’s to pick the one that won’t wake you up later.
The Human Bits: Stories From the Trenches
One of my clients had a global launch with region-specific subdomains on a tight deadline. They planned to use HTTP‑01 across multiple regions, but a last-minute CDN rule started caching 404s for the challenge path. Rather than fight the clock, we switched to DNS‑01, automated the TXT records, and the rollout finished while the CDN folks were still reading the change tickets. Sometimes the best fix is the one that avoids the argument entirely.
Another time, a security-conscious team insisted on no open port 80 anywhere. They were right to be cautious—compliance demanded it. We implemented TLS‑ALPN‑01 at the edge, validated cleanly on 443, and kept the auditors happy. They didn’t need wildcards, and we controlled the TLS termination layer, so it felt like slipping the key into exactly the right lock.
And of course, the late-night wildcard story. I can’t tell you how nice it is to create *.example.com once with DNS‑01 and be done with it. The team spun up new subdomains like they were adding routes in the app. Certificates never crossed their minds, which is how it should be. The success criteria for ACME, in my book, is that nobody on the feature team ever has to think about certificates again.
Wrap‑Up: Pick the Calm Path, and Make It Boring
If you remember one thing from this deep dive, let it be this: choose the ACME challenge that keeps your architecture boring. HTTP‑01 is the straight shot when port 80 is open and the traffic path is simple. DNS‑01 is the powerhouse when you want wildcards, clean SaaS onboarding, or you’re behind layers that you don’t fully control. TLS‑ALPN‑01 is the elegant specialist for HTTPS-only environments where you control the TLS handshake but don’t want to touch DNS. None is “better” in isolation; each is right for its moment.
From there, make your automation resilient. Test with a staging CA, wire in alerts for the first failure, keep a backup CA ready, and make sure your CAA and DNS are in sync with your plans. If you’re curious about resilient DNS or multi-CA strategies, I shared my playbooks in my octoDNS guide and the redundancy article, and they pair beautifully with DNS‑01 at scale.
Alright—take a breath. Certificates don’t have to be dramatic. Pick the path that matches your world today, set it up so failures are loud and early, and then let it fade into the background while you build the things your users actually see. Hope this was helpful! See you in the next post, and may your renewals be blissfully boring.
