Let's Encrypt for Self-Hosted
Let's Encrypt made browser-trusted TLS free and automated. For a self-hosted service the choice is no longer "self-signed or buy a cert" but "HTTP-01 or DNS-01 for the Let's Encrypt automation." For internal-only homelab services that aren't reachable from the public internet, DNS-01 makes valid TLS achievable without exposing anything — and wildcard certs make managing many subdomains painless.
How Let's Encrypt issues a cert
- Your ACME client (certbot, Caddy, etc.) asks Let's Encrypt for a cert for a specific domain.
- Let's Encrypt issues a challenge — "prove you control this domain by doing X."
- Your client completes the challenge (serving a file, publishing a DNS record).
- Let's Encrypt validates the challenge response from its servers.
- Let's Encrypt issues the certificate, valid for 90 days.
- Your client saves the cert and key, deploys to whatever needs it.
- Roughly 60 days later, the client renews automatically.
HTTP-01 challenge
The simplest challenge. Let's Encrypt asks you to serve a file at:
http://yourdomain.com/.well-known/acme-challenge/<random-token>
The file contains a response that proves you control the private key. Let's Encrypt's servers fetch the URL and validate the response.
Requirements:
- Port 80 reachable from the internet on the validated hostname.
- A web server (or ACME client built-in) that serves the challenge file when asked.
Limitations:
- Can't issue wildcard certs via HTTP-01.
- Doesn't work for internal-only services that aren't reachable from the internet.
- Each subdomain needs its own validation (no wildcard).
DNS-01 challenge
Let's Encrypt asks you to publish a TXT record at:
_acme-challenge.yourdomain.com TXT "<random-string>"
The TXT record value is derived from the account key and the challenge. Let's Encrypt's servers query DNS for the record and validate.
Requirements:
- API access to your DNS provider so the ACME client can create/delete TXT records automatically.
- The DNS provider must propagate quickly enough that Let's Encrypt sees the record within validation timeouts.
Advantages:
- Works for internal-only domains. The validation is via DNS; nothing needs to be reachable from the internet.
- Issues wildcard certs.
*.lab.example.comcovers all subdomains in one cert. - One challenge for many hostnames. A single TXT record validates a wildcard.
Which challenge for which scenario
| Scenario | Use |
|---|---|
| Public web server on port 80 | HTTP-01 (simplest) |
| Public service with proxy | HTTP-01 via the proxy |
| Internal-only homelab service | DNS-01 (HTTP-01 won't work) |
| Need wildcard cert | DNS-01 (HTTP-01 doesn't support wildcards) |
| Behind CGNAT / no port 80 | DNS-01 |
ACME client choices
- Certbot — official Let's Encrypt client. Comprehensive; supports many DNS providers via plugins.
- acme.sh — shell-based, no Python dependency. Supports many DNS providers.
- lego — Go-based ACME client. Single binary; large DNS provider list.
- Caddy — web server with built-in ACME. Automatic HTTPS for everything it serves.
- Traefik — reverse proxy with built-in ACME. Auto-issues certs as services come up.
- Nginx Proxy Manager — web UI on top of nginx with built-in Let's Encrypt support.
For homelab use, the reverse-proxy options (Caddy, Traefik, NPM) handle ACME so you don't run a separate certbot service.
Wildcard cert workflow
- Choose a DNS provider with an API your ACME client supports (Cloudflare, Route53, DigitalOcean, etc.).
- Generate an API token scoped to just the zone(s) for the domain — minimum privileges.
- Configure the ACME client with the API credentials.
- Request a wildcard cert for
*.lab.example.compluslab.example.com(the bare domain isn't matched by the wildcard). - Client publishes the TXT record, waits for propagation, asks Let's Encrypt to validate, gets the cert.
- Renew every 60 days automatically.
Storing and deploying the cert
The cert is just files (a public certificate chain and a private key). The reverse proxy reads them on startup or on reload. Operational concerns:
- Permissions. The private key should be readable only by the service that uses it. Don't world-read it.
- Renewal reload. After renewal, the proxy may need to reload to pick up the new cert. Most ACME-integrated proxies handle this automatically.
- Distribution. If multiple services need the same cert (e.g., reverse proxy + dedicated app), the ACME client or a separate distribution mechanism copies the cert to each location.
Rate limits
Let's Encrypt has rate limits to prevent abuse:
- 50 certificates per registered domain per week.
- 5 duplicate certificates per week (same exact set of hostnames).
- 300 new orders per account per 3 hours.
Use the staging environment (https://acme-staging-v02.api.letsencrypt.org/directory) for testing — the staging CA has higher limits but issues untrusted certs.
Multiple short SAN list vs one wildcard
Two patterns for covering many subdomains:
- SAN cert — one cert listing every specific hostname. Easy to issue; needs renewal when you add a new subdomain.
- Wildcard cert —
*.lab.example.comcovers any current or future subdomain. One renewal per wildcard, regardless of how many services.
For internal homelab services with many changing subdomains, wildcards win. For public-facing apex+www, a SAN cert is fine.
Common pitfalls
- Forgetting CAA records. If your domain has a CAA record specifying a different CA, Let's Encrypt won't issue. Either remove the CAA or include Let's Encrypt.
- DNS propagation slower than ACME validation timeout. Use a DNS provider with fast propagation or configure longer waits in the ACME client.
- Renewal cron not running. Cert expires; service breaks. Monitor renewal success.
- Wildcard cert applied to apex.
*.example.comdoesn't coverexample.com. Request both in the SAN list. - Private key compromised in deployment. Revoke immediately via ACME; re-issue.
Frequently Asked Questions
What is Let's Encrypt?
A free, automated, browser-trusted certificate authority that issues TLS certificates valid for 90 days. Certificates are issued via the ACME protocol — a request, a challenge (proving domain control), and a signed certificate. Used by most modern self-hosted services because it removes both the cost and the manual-renewal burden of traditional CAs.
What is the difference between HTTP-01 and DNS-01?
HTTP-01 proves domain control by serving a specific file at a specific path on port 80 of the domain. Works for any domain whose web server you control, but requires port 80 to be reachable from Let's Encrypt's validators. DNS-01 proves control by publishing a specific TXT record in the domain's DNS. Works for internal-only services and supports wildcard certificates, but requires DNS API access.
How do I get a wildcard certificate?
Only via DNS-01 challenge. Let's Encrypt requires DNS validation for wildcard certs because the wildcard covers an indefinite number of hostnames; the only practical way to prove control over "*" is to control DNS for the parent domain. ACME clients with API access to your DNS provider automate the TXT record creation.
What is ACME?
Automatic Certificate Management Environment — the IETF-standardized protocol Let's Encrypt uses for certificate issuance and renewal. ACME clients (certbot, acme.sh, lego, Caddy's built-in, traefik's built-in) implement the protocol. Other CAs (ZeroSSL, Buypass, Google Trust Services) also support ACME; the protocol is portable across CAs.
How often do Let's Encrypt certs need to be renewed?
Every 60 days, ideally — certs are valid for 90 days but renewing at 60 leaves margin for failures. All major ACME clients automate this; properly configured, you set up renewal once and forget about it. Failed renewals usually surface as a service outage when the cert expires, so monitoring renewal success is important.
Related Guides
More From This Section
All Homelab Guides
Proxmox, pfSense vs OPNsense, Docker vs VMs, VLANs, and self-hosted apps.
Container Networking Basics
How container networking actually works — Docker bridge, host mode, macvlan, overlay networks, and the difference…
DNS for Homelab
How to run DNS for a homelab — local-only domain names, split-horizon between internal and external resolution, Pi-hole…
Run a Speed Test
Measure download, upload, ping, and jitter in your browser.