HTTPS and an SSL Certificate for Home Assistant with Let's Encrypt (DNS-01 Challenge)
By default, Home Assistant runs on unencrypted HTTP, and sooner or later your browser greets you with an annoying warning about an insecure connection. In this article we'll show you how to put a valid HTTPS/SSL certificate on it for free using Let's Encrypt - and above all we'll take a proper look at the DNS-01 challenge, a verification method that lets you obtain a certificate even when you have no public IP address or don't want to open any ports to the internet.
I'll focus on what most often fails for people following other guides: I'll give you the verified, working configuration of the official Let's Encrypt add-on, because this is exactly where bad guides do the most damage.
Why HTTPS for Home Assistant at all?
Without an encrypted connection, your login credentials and all traffic between the browser and Home Assistant travel across the network in plain text. HTTPS solves two things:
- 🔒 Traffic encryption - nobody on the network (neither in your home nor along the way through the internet) can see what you're sending.
- ✅ No browser warning - with a valid certificate the browser won't say "Your connection is not private", and the mobile app and add-ons behave reliably.
Let's Encrypt is a non-profit certificate authority that issues trusted SSL certificates for free and fully automatically. The certificate has a short validity (90 days), but the add-on takes care of automatic renewal for you, so you don't have to lift a finger.
If all you want is remote access and you'd rather not deal with certificates at all, there are simpler routes - for example Home Assistant Cloud (Nabu Casa). You'll find a detailed comparison of the methods in the article Remote Access to Home Assistant. This article goes one level deeper and focuses directly on certificates.
HTTP-01 vs. DNS-01 challenge
Before Let's Encrypt issues a certificate, it must verify that you really own the domain. There are two main ways (challenges):
HTTP-01 challenge
- Let's Encrypt tries to reach your domain on port 80.
- It therefore requires a publicly reachable port 80 from the outside.
- Doesn't work behind CGNAT or without port forwarding.
- Cannot issue a wildcard certificate.
DNS-01 challenge
- Verification happens via a TXT DNS record that the add-on creates automatically at your DNS provider.
- Needs no open port and no public IP.
- Works behind CGNAT and for purely local deployments.
- It's the only one that can issue a wildcard certificate (
*.yourdomain.com).
For the vast majority of home installations the DNS-01 challenge is far more practical - which is why we focus on it the most in this article.
When the DNS-01 challenge makes sense
DNS-01 is the right choice for you if at least one of the following applies:
- ✅ You're behind CGNAT or have no public IP address (typically mobile/4G/5G internet or some ISPs).
- ✅ Port forwarding won't work for you, or you don't want to do it on principle.
- ✅ You don't want to open ports 80/443 to the internet for security reasons.
- ✅ You only want local access with a valid certificate - Home Assistant reachable under your own domain on the home network, but without the self-signed certificate warning.
- ✅ You want a wildcard certificate (
*.yourdomain.com) covering multiple services at once - which can be obtained exclusively via DNS-01.
A popular scenario: Home Assistant runs at home, you want to reach it at https://ha.yourdomain.com without a browser warning, but you don't want to expose it to the internet. All you need is a certificate obtained via DNS-01 and a local DNS record (or a Cloudflare one) pointing the domain to the local IP. The certificate is valid, the browser is happy, and you don't open a single port anywhere.
Overview of ways to get HTTPS onto Home Assistant
Before we dive into the concrete guide, let's put the options in order. There are several paths to HTTPS, and each suits a slightly different person.
| Method | User-friendliness | Cost | Own domain | Opening ports | Complexity |
|---|---|---|---|---|---|
| Home Assistant Cloud (Nabu Casa) | Very high | $6.50 / month | ❌ | ❌ | Very low |
| DuckDNS + Let's Encrypt add-on | Medium | Free | ❌ (DuckDNS subdomain) | ✅ (for remote access) | Medium |
| Let's Encrypt add-on (DNS-01) | Medium | Free | ✅ | ❌ | Medium |
| Reverse proxy (NPM / Traefik / Caddy) | Medium | Free | ✅ | Depends | Higher |
| Cloudflare Tunnel | High | Free | ✅ | ❌ | Medium |
Home Assistant Cloud (Nabu Casa)
The simplest path to everything at once. For a $6.50/month subscription you get remote access, a valid certificate, and a domain (https://xxxxx.ui.nabu.casa) fully automatically - you don't manage anything, and on top of that you support Home Assistant's development.
Choose it if: you want everything done without technical tinkering and don't mind paying.
DuckDNS + Let's Encrypt add-on
A classic among free solutions. The DuckDNS add-on gives you a free subdomain, keeps your IP up to date, and issues a Let's Encrypt certificate right away - via the DNS-01 challenge (verification runs through the DuckDNS token, so you don't have to open any port for the certificate). The catch is elsewhere: DuckDNS is typically the route to remote access, and for that you do need an open port and port forwarding (usually 443/8123). So remote access via this route doesn't work behind CGNAT - the certificate is issued fine, but you can't reach Home Assistant from the outside.
Choose it if: you have a public IP, don't mind port forwarding, and a DuckDNS subdomain is enough.
Let's Encrypt add-on with DNS-01 challenge
The main topic of this article. You get the certificate directly on Home Assistant, under your own domain and without opening any port - verification runs over DNS. Ideal behind CGNAT and for purely local access, and it's the only add-on variant that can also do wildcards.
Choose it if: you want your own domain, a valid certificate directly on HA, and you don't want (or can't) open ports.
Reverse proxy (NGINX Proxy Manager / Traefik / Caddy)
A reverse proxy is a standalone service that sits in front of Home Assistant (and possibly other services too) and handles TLS/certificates on their behalf. The client connects to the proxy over an encrypted connection, and the proxy forwards traffic to HA over the internal network.
I use NGINX Proxy Manager (NPM) on my own homelab, and I have to say that for more than one service it's a great solution.
Advantages:
- ✅ Centralizes certificates for all services, not just HA (Node-RED, Grafana, Frigate...).
- ✅ NPM can do the Let's Encrypt DNS challenge itself - it has built-in DNS plugins including Cloudflare, so it handles wildcards and DNS-01 without the HA add-on.
- ✅ Separates TLS from Home Assistant - you handle certificates in one place.
- ✅ Easy to add more services and set up access lists (restricting access).
Disadvantages:
- ⚠️ Another component to maintain - you have to run and update the proxy.
- ⚠️ In Home Assistant you must correctly set
trusted_proxiesanduse_x_forwarded_for: trueso HA knows a proxy sits in front of it (otherwise it sees the wrong client IPs and login may not work).
When to choose a proxy vs. the direct add-on? If you're only dealing with Home Assistant and want the simplest setup, reach for the Let's Encrypt add-on with DNS-01 directly on HA. But as soon as you have multiple services, multiple domains, or want to manage certificates and access centrally, a reverse proxy makes far more sense.
Cloudflare Tunnel
Cloudflare Tunnel creates a secure tunnel between HA and Cloudflare, and Cloudflare handles the certificate for you - no ports, no certificates on your side. I cover it in detail in the article Remote Access to Home Assistant.
Hands-on guide: Let's Encrypt add-on with DNS-01 challenge (Cloudflare)
Now for the main event. We'll walk through deploying the official Let's Encrypt add-on with the DNS-01 challenge, using Cloudflare as the DNS provider (the most common choice). The procedure is nearly identical for other providers - only the provider name and credentials differ.
You'll need your own domain with its DNS managed at a supported provider. With Cloudflare, a free account and a domain added to Cloudflare (nameservers pointed to Cloudflare) are enough.
Step 1: Create a Cloudflare API token
The add-on needs permission to create a verification TXT record at your DNS. With Cloudflare the recommended way is a single scoped API token with minimal rights:
- Log in to the Cloudflare dashboard and open My Profile → API Tokens.
- Click Create Token and use the Edit zone DNS template, or create a custom token.
- Set the permission exactly to Zone → DNS → Edit.
- In Zone Resources, restrict the token to the specific zone (your domain) - not to all of them.
- Create the token and copy it (it's shown only once).
The token needs only the Zone → DNS → Edit permission for the given zone. Don't give it Full Access or global rights - the add-on doesn't need more, and you'd be raising the risk for nothing.
Older guides use the cloudflare_email + cloudflare_api_key pair (a global key to the whole account). This method is marked as "NOT RECOMMENDED" in the add-on documentation, and I mention it only for completeness - stick with the scoped token above.
Step 2: Install the Let's Encrypt add-on
- In Home Assistant, go to Settings → Add-ons → Add-on Store.
- Find Let's Encrypt (the official add-on) and click Install.
- After installation, don't start the add-on yet - we'll configure it first.
Step 3: Configure the add-on (DNS-01)
Open the add-on's Configuration tab and set it exactly as follows (switch the editor to YAML mode):
domains:
- ha.yourdomain.com
certfile: fullchain.pem
keyfile: privkey.pem
challenge: dns
dns:
provider: dns-cloudflare
cloudflare_api_token: <scoped-token>
# propagation_seconds: 60 # increase for slower providers (e.g. Netcup >= 630)
What to watch out for:
- ✅
challenge: dnsswitches the add-on into DNS-01 mode (no ports). - ✅ The provider name must have the
dns-prefix - that is,dns-cloudflare. Without the prefix the add-on won't find the provider (see troubleshooting below). - ✅
cloudflare_api_tokenis the scoped token from step 1. - ✅
propagation_secondsis commented out - for Cloudflare the default is fine. For slower providers (e.g. Netcup) uncomment and increase it (630 or more for Netcup), so the DNS record has time to propagate before Let's Encrypt verifies.
The add-on supports dozens of providers via the lego library - for example dns-route53, dns-hetzner, dns-duckdns, dns-google, or dns-godaddy. You only change provider: and the corresponding credentials (the key names differ per provider; you'll find them in the add-on documentation). The dns- prefix applies to all of them.
Step 4: Start and check the log
- Save the configuration and start the add-on.
- Open the Log tab. The add-on creates a temporary TXT record at Cloudflare, waits for it to propagate, and then obtains the certificate.
- In the log you should see that the certificate was successfully issued and saved to
/ssl/.
Step 5: Wire the certificate into Home Assistant
Now we tell Home Assistant to use the issued certificate. Open configuration.yaml and add (or complete) the http section:
http:
ssl_certificate: /ssl/fullchain.pem
ssl_key: /ssl/privkey.pem
A lot of incorrect configurations circulate online. Stick exactly to what's above:
- ❌ The key
ssl_redirectdoes not exist - don't use it. - ❌
trusted_proxiesanduse_x_forwarded_fordon't belong here - they only apply to the reverse-proxy scenario, not a direct certificate on HA. - ❌
hass: trueandnginx: trueare not Let's Encrypt add-on options - don't put them anywhere.
Step 6: Restart Home Assistant
Save configuration.yaml and restart Home Assistant (Settings → System → Restart). After the restart, HA will be reachable at https://ha.yourdomain.com with a valid certificate.
The NGINX Proxy Manager variant
If you go the reverse-proxy route, the roles shift. In this scenario the certificate is not handled by the HA add-on but by NGINX Proxy Manager - it requests and renews the certificate itself via its built-in Let's Encrypt (which can also use the DNS challenge with the Cloudflare plugin).
The principle is as follows:
- Home Assistant runs without SSL on port 8123 (so you omit the
http:section withssl_certificate/ssl_key). - NPM sits in front of HA, accepts HTTPS traffic on port 443, terminates TLS, and forwards requests to
http://<home-assistant-ip>:8123. - In Home Assistant you need to declare that a proxy sits in front of it, otherwise HA would see all requests as coming from the proxy's IP:
http:
use_x_forwarded_for: true
trusted_proxies:
- <nginx-proxy-manager-ip-address>
A detailed click-by-click NGINX Proxy Manager setup is a topic for a separate article (I'm working on it). What matters here is the principle: the proxy handles the certificate, HA runs without SSL, and you just tell it whom to trust via trusted_proxies. Into trusted_proxies put the IP address the proxy uses to reach HA.
Automatic renewal and verification
Let's Encrypt certificates are valid for 90 days, but renewal is automatic - the add-on renews the certificate roughly 30 days before expiration. You don't have to do anything, just keep the add-on running.
How to verify everything is fine:
- 🔍 In the browser, click the padlock icon in the address bar and view the certificate details - you'll see the issuer (Let's Encrypt) and the validity date.
- 📋 Check the add-on Log - after renewal you'll find a record of the new certificate being issued.
- ⏱️ If you want the exact expiration from the command line, you can use
opensslagainst your domain and port 443.
Troubleshooting
Error "Selected DNS Provider: null"
The most common cause is an incorrect provider name - typically a missing dns- prefix. It must be dns-cloudflare, not cloudflare. It definitely does not mean a missing plugin - the add-on has the providers built in via lego.
The certificate isn't issued or renewed Check the API token permissions. With Cloudflare the token must have the Zone → DNS → Edit permission for the given zone. Without the right to write DNS records, the add-on can't create the verification TXT record.
Verification times out with a slower provider
Some DNS providers propagate TXT records more slowly. Uncomment and increase propagation_seconds (e.g. 630 or more for Netcup) so Let's Encrypt waits until the record propagates.
The browser still reports an untrusted certificate
Make sure you restarted Home Assistant after the certificate was issued and that in configuration.yaml ssl_certificate/ssl_key point to the correct files in /ssl/.
Related articles
- Remote Access to Home Assistant - a comparison of Home Assistant Cloud, Cloudflare Tunnel, and a public IP
- Amazon Alexa - requires public access on port 443 with a valid certificate
- Terminal & SSH - managing Home Assistant from the command line
Conclusion
Getting a valid HTTPS certificate for Home Assistant is free these days and, above all, sustainable without manual work - you set it up once and Let's Encrypt handles the rest. In my view the DNS-01 challenge is the most versatile choice for home use: it works behind CGNAT, needs no open port, and it's the only one that can do wildcards.
If you're only dealing with Home Assistant, reach for the Let's Encrypt add-on with DNS-01 directly on HA - it's the most direct path. But once you have more services, a reverse proxy like NGINX Proxy Manager makes more sense - I use it myself, and it unifies certificates and access in one place. And if you don't want to deal with certificates at all, Home Assistant Cloud remains the most convenient option. 💚