Let’s Encrypt Wildcard Certs With DNS-01 for Internal Services

Terminal showing a successful TLS certificate issuance log with a home network rack behind

A Let’s Encrypt wildcard certificate lets one *.home.example.com certificate cover every internal service you run, and the DNS-01 challenge is what makes it possible without exposing anything to the internet. You prove you control the domain by writing a TXT record, not by opening a port. This is the single highest-leverage certificate move in a homelab: provision once, and every service — present and future — is covered.

I run exactly this on my network: one wildcard, fetched over DNS-01, sitting on the reverse proxy, renewing itself on a schedule I never think about. The reason it matters is that the alternative — a separate certificate per service, each needing its own validation — scales terribly and eventually trips a rate limit. Get the wildcard right once and the whole problem goes quiet.

Terminal on a desk showing a successful TLS certificate issuance log with a network rack behind

Why Do Wildcard Certificates Require the DNS-01 Challenge?

Because Let’s Encrypt will only issue a wildcard certificate when you prove control of the entire domain, and writing a DNS TXT record is the only challenge that demonstrates that. The HTTP-01 challenge proves you control one specific hostname on port 80; a wildcard covers all hostnames under a label, so it demands the stronger, domain-wide proof that only DNS-01 provides.

The flow is precise. Your ACME client asks Let’s Encrypt for a *.home.example.com certificate. Let’s Encrypt returns a token and tells the client to publish it as a TXT record at _acme-challenge.home.example.com. The client calls your DNS provider’s API, writes the record, waits for it to propagate, and signals Let’s Encrypt, which queries that TXT record from the public DNS system to confirm. Note the record name: for a wildcard on home.example.com, the challenge record sits at _acme-challenge.home.example.com, not under each host.

The consequence is the part homelabbers love: nothing on your network needs to be reachable from outside. The only thing Let’s Encrypt ever touches is your public DNS. The actual services can live on a VLAN with no internet ingress at all — my IoT-adjacent segments get certificates this way despite having zero inbound access. This is why DNS-01 is the backbone of the whole homelab internal HTTPS approach, and why it pairs so naturally with the public-domain decision.

What DNS Provider and API Token Do You Actually Need?

You need your domain’s DNS hosted somewhere with an API your ACME client supports, and a scoped API token that can edit only that zone’s records — nothing more. The token is a credential your automation holds indefinitely, so least privilege is not optional. This choice is the one that decides whether the whole thing is a five-minute setup or a weekend of debugging.

Laptop showing a DNS provider dashboard with a TXT record being added

The prerequisite is that your DNS is hosted by a provider with a real API — not your registrar’s basic control panel with no automation. Popular homelab choices are providers with well-documented APIs and broad ACME client support. The critical detail is scope: create a token that can edit DNS records for only the lab domain’s zone, never a global account key. If that token leaks off a homelab box, the blast radius should be “an attacker can mess with one throwaway domain’s DNS,” not “an attacker owns my entire DNS account.”

On my setup the client I reach for is acme.sh — it is a single shell script with support for dozens of DNS-provider APIs and no heavy dependencies, which suits a lightweight LXC container. certbot with a DNS plugin and lego are equally valid; Caddy and Traefik have DNS-01 built straight in, which I cover in the reverse-proxy comparison. Whichever client you pick, it stores that scoped token and uses it on every renewal, so treat the file it lives in like a password.

How Do You Issue Your First Wildcard Certificate?

You point your ACME client at your DNS provider with the scoped token, request *.home.example.com, and let it write and clean up the TXT record automatically. The first issuance is the moment everything clicks, and it takes under a minute once the token is in place. The client handles the token dance; you just watch the log.

Close-up terminal window showing an ACME client output line for a wildcard certificate

The universal rule for a first run: use the staging environment first. Let’s Encrypt’s staging endpoint issues certificates from an untrusted test CA but has far looser limits, so you can hammer it while you debug your token and propagation timing without touching your real quota. Once a staging issuance succeeds cleanly, flip to production and run it once for real. I skipped staging on my very first attempt years ago and burned through validation failures fast — a mistake I will get to below.

After issuance you will have a certificate and a private key. In my setup those land on the reverse proxy, which presents the wildcard for every service.home.example.com name and terminates HTTPS once. The sound of it working is anticlimactic in the best way: a browser loads the service, the padlock is just there, no warning, no click. That silence is the whole goal.

What Are the Let’s Encrypt Rate Limits You Need to Respect?

Let’s Encrypt caps you at 50 certificates per registered domain per week and 5 duplicate (identical-name) certificates per week, and failed validations are throttled too — so a broken automation loop can lock you out for a week. These numbers rarely bite a careful homelab, but they punish a misconfigured renewal loop hard. Knowing them turns a mysterious lockout into an expected, avoidable event.

The two limits that matter for a wildcard setup: the 50 certificates per registered domain per week ceiling, and the 5-per-week cap on issuing the exact same certificate. A single wildcard renewed every 60 days uses a tiny fraction of that, which is precisely why a wildcard is so efficient — one certificate instead of thirty. The danger is a script stuck in a retry loop: fail validation, retry, fail, retry, and you can exhaust the failed-validation limit and be shut out until the window rolls over. Certificates are valid for 90 days, and a healthy client renews at around day 60, leaving a comfortable buffer.

The practical safeguards are simple. Test against staging, not production. Do not script blind retries with no backoff. And if you do hit a wall, read the error — Let’s Encrypt tells you which limit you tripped and when it resets — rather than hammering harder and digging deeper. The limits reset on a rolling weekly window, so patience genuinely fixes it.

How Do You Make Sure Renewal Never Silently Fails?

You automate renewal with the client’s built-in timer and then monitor the certificate’s expiry independently, because the one failure mode that actually hurts is a renewal that broke months ago and surfaces only when the certificate dies. Automation is necessary but not sufficient — you have to watch the watcher. This is the discipline that separates a set-and-forget setup from a Sunday-morning fire drill.

Every serious ACME client installs a scheduled task — a cron job or systemd timer — that checks daily and renews when the certificate is within its renewal window. That part is easy. The trap is that if the DNS token gets rotated, the provider changes its API, or a network path breaks, the renewal fails quietly and the timer just logs an error nobody reads. Then 90 days later the certificate expires and every service goes red at once.

My fix, after getting burned exactly this way, is to graph certificate expiry on the same Grafana dashboard I already stare at, with an alert that fires at 21 days remaining. That gives me three weeks of warning instead of zero. You do not need enterprise monitoring for this — a simple expiry check that pings you is enough. The rule I live by now: never trust an automated renewal you are not also independently watching.

Frequently Asked Questions

Does a wildcard certificate cover subdomains at every level?

No. A wildcard covers exactly one level. A certificate for asterisk-dot-home-dot-example-dot-com covers nas.home.example.com but not a deeper name like app.nas.home.example.com. For a homelab, one flat level of hostnames is almost always all you need, so this is rarely a real constraint.

Can I get a Let’s Encrypt certificate for a service that has no public internet access?

Yes, and that is the whole point of the DNS-01 challenge. Validation happens entirely through your public DNS by writing a TXT record, so the service itself never needs to be reachable from the internet. It can live on a VLAN with no inbound access and still carry a browser-trusted certificate.

How often do Let’s Encrypt certificates need to be renewed?

Let’s Encrypt certificates are valid for 90 days. A healthy ACME client renews automatically at around day 60, leaving a 30-day buffer. You should never renew by hand in a well-set-up homelab, but you should monitor expiry independently so a silently broken renewal does not surprise you.

What happens if I hit a Let’s Encrypt rate limit?

You are temporarily blocked from issuing more certificates until the weekly window rolls over. The main limits are 50 certificates per registered domain per week and 5 duplicate certificates per week, plus a throttle on failed validations. Test against the staging environment and avoid blind retry loops to stay well clear of them.

Do I need to open any ports for DNS-01 to work?

No. Unlike the HTTP-01 challenge, DNS-01 requires no open ports and no inbound connectivity to your services. The only thing that must be reachable is your public DNS zone, which your ACME client updates through the provider’s API using a scoped token.

Small home server rack with glowing status LEDs running several self-hosted services

The Mistake That Ate My First Weekend

My first wildcard attempt went straight to production with a global DNS API key and no staging test, and it went about as badly as that sentence sounds. My propagation timing was too aggressive — I signalled Let’s Encrypt before the TXT record had propagated — so validation failed. I retried. It failed again. Within an hour I had tripped the failed-validation throttle and was locked out, staring at an error I did not yet know how to read.

Two lessons came out of that afternoon, and I have never broken them since. First, always debug against staging, where the limits are generous and a mistake costs nothing. Second, scope the token — that global key I used could have edited every domain in my account, which is exactly the credential you do not want sitting on a lab box. Do those two things and the DNS-01 wildcard is genuinely a set-it-once affair. Skip them and you will meet the rate limiter the hard way, like I did.

What I’d Do Starting Today

Move your lab domain’s DNS to a provider with a real API, mint a token scoped to that one zone, and issue a single *.home.example.com wildcard against the staging endpoint first. Once staging succeeds, run it once in production, drop the certificate on your reverse proxy, and add an expiry alert at 21 days. That is the whole job — and after it, every service you ever add under that domain is already covered.

Related Articles

Leave a Comment

Your email address will not be published. Required fields are marked *