CloudFlare showing mtls or mutual tls authentication between client and website
Home ยป Blog

The Blueprint: Locking Down Home Assistant With mTLS โ€” So Hackers Can’t Even Find the Door


๐Ÿ“… Published: April 2026 | โœ๏ธ By Brad Andrews | โฑ๏ธ 9 min read


This is part two of the remote access security series. If you haven’t set up your Cloudflare Tunnel yet, start with The Blueprint: How to Set Up a Cloudflare Tunnel for Home Assistant, this guide picks up where that one ends.

With your tunnel running, https://home.yourdomain.ca is already far more secure than port forwarding. But your Home Assistant login page is still publicly reachable. Anyone who types in that URL sees it. That matters more than most people realise.


Why a Login Page Is Not Enough

I’ve spent over 15 years in IT infrastructure and cybersecurity. One thing that never changes: if something is reachable on the internet, it gets probed. Not by people, by automated bots running 24 hours a day, cataloguing every exposed service they can find.

A reachable login page tells attackers several things at once. It tells them something is running at that URL. It tells them what software it is. Home Assistant has a recognisable login page. It tells them which version you’re running if they look at the response headers. And it gives them a surface to test against: credential stuffing, brute force, known CVEs.

None of that happens if they can’t reach the login page in the first place.

That’s what mTLS does. Mutual TLS means both sides of a connection have to prove their identity with a certificate. Your server proves it’s your server, that’s normal TLS. Your device proves it’s your device, that’s the mutual part. No valid certificate on the connecting device means no connection. Cloudflare intercepts the request at the edge and returns an access denied screen. Nothing reaches your network. Nothing loads. Your server doesn’t even know the attempt happened.

From a cybersecurity standpoint this is a meaningful reduction in attack surface. It removes the login page as a target entirely. It prevents server fingerprinting. It eliminates failed login attempts consuming CPU cycles. And it costs nothing.

The Home Assistant Companion App added mTLS certificate support recently, as of April 2026 it’s a Labs feature, meaning it works but isn’t considered fully polished yet. That’s what made this setup viable for daily use. Before that, you could lock down browser access but the mobile app would break.


What You Need Before You Start

  • A working Cloudflare Tunnel pointing at Home Assistant, set that up first if you haven’t already
  • A Cloudflare Zero Trust account (free tier, same one from the tunnel setup)
  • The devices you want to grant access, in my case: iPhone, iPad, and laptop. My kitchen dashboard tablet stays local-only intentionally. More on that below.

How This Works. The Short Version

Cloudflare generates a Certificate Authority (CA) inside your Zero Trust account. You use that CA to issue a client certificate. You install the certificate on every device that should have access. You create an Access policy on your tunnel hostname that requires a valid certificate from your CA. Anyone without the cert gets denied before they reach your network.

Simple in principle. Let’s walk through the execution.


Step 1: Generate Your Client CA in Cloudflare Zero Trust

  1. In the CloudFlare dashboard, navigate to your domain โ†’ SSL/ TLS โ†’ Client Certificates
  2. Click Add mTLS Certificate
  3. Click Continue leaving defaults (Cloudflare Managed CA, RSA 2048, 10 Years)
  4. Save the Certificate as client.crt and Private Key as client.key for use in the command below
  5. Under Associated Hostnames, add YourDomain.ca
  6. Click Save

Cloudflare will generate a root CA and display it as Active along with an Expiry date you will need a new certificate by using the same steps in 10 years or whichever validity period of time you gave it.


Step 2: Convert the Client Certificate for use

  1. You’ll need to combine the 2 client.crt and client.key files into a .pfx (PKCS#12) file for installation on your devices. On a Mac or Linux machine, for Windows the command will work only after installing OpenSSL on your device:

bash

# Combine certificate and private key into a .pfx file
# You will be prompted to set a password, use a strong one and remember it
# You'll need to enter it during installation on each device

openssl pkcs12 -export 
  -out home-assistant-client.pfx
  -in client.crt 
  -inkey client.key 

Keep this .pfx file somewhere safe. You’ll need it every time you add a new device. A password manager with file attachment support works well, 1Password and Bitwarden both handle this. Every new device means finding this file again and remembering how to install it. It’s a minor one-time task per device, but worth being organised about. The security gain is worth the admin overhead many times over.


Step 3: Create the Security Rules

This is the step that enforces certificate checking on your tunnel hostname.

  1. In the dashboard, navigate to Security โ†’ Security Rules
  2. Click Create rule
  3. Choose Custom rules
  4. Fill in:
FieldOperatorValue
Hostnameequalshome.YOURDOMAIN.ca
Client CertificateequalsOn
Choose actionSkip
Place at orderFirst
Cloudflare Security rule allowing traffic to skip rules with a valid client certificate installed
  1. Ensure the Place at Select order is set to First
  2. Click Deploy
  3. Now you need a block rule after that:
FieldOperatorValue
Hostnameequalshome.YOURDOMAIN.ca
Choose actionBlock
Place at orderLast
Cloudflare security rule blocking all traffic to a set hostname in the last position for all rules to catch remaining traffic and deny it access

Your tunnel hostname is now protected. Anyone without a valid client certificate from your CA will see a Cloudflare access denied page. They won’t see your login page. They won’t see anything that identifies what’s running at that URL.

Note: You will be blocked yourself until you install the Client certificate on your devices you wish to allow!


Step 4: Install the Client Certificate on Your Devices

iOS (iPhone and iPad)

iOS refers to certificates as Profiles. The install process is straightforward but has a few steps across multiple settings screens.

  1. Transfer the .pfx file to your iPhone or iPad. AirDrop works well, or email it to yourself
  2. Tap the file to open it. iOS will say it has been downloaded and prompt you to go to Settings to install it.
  3. Open Settings โ†’ General โ†’ VPN & Device Management
  4. You’ll see the profile listed under Downloaded Profile, tap it
  5. Tap Install in the top right, enter your device passcode, and tap Install again to confirm
  6. You’ll be prompted for the .pfx password you set when exporting, enter it
  7. Tap Done

The certificate is now installed. You can verify it under Settings โ†’ General โ†’ About โ†’ Certificate Trust Settings.

Reboot if it doesn’t work. After installing the profile I found that Safari on iOS sometimes doesn’t pick up the new certificate until the device is restarted. If you install the cert and still get a Cloudflare access denied page in Safari, reboot the device first before troubleshooting anything else.

Android

  1. Transfer the .pfx file to your Android device
  2. Open Settings โ†’ Security โ†’ Encryption & Credentials โ†’ Install a Certificate
  3. Choose CA Certificate or VPN & app user certificate depending on your Android version, select the .pfx file
  4. Enter the password when prompted
  5. Give the certificate a name and save

Chrome on Android will use the certificate automatically once installed. Other browsers may handle this differently.

Laptop / Desktop

On macOS, double-click the .pfx file and add it to your login keychain. Enter the password when prompted. Chrome and Safari will use it automatically.

On Windows, double-click the .pfx file and follow the Certificate Import Wizard. Choose Current User store. Chrome and Edge will pick it up automatically.


Step 5: Configure the Home Assistant Companion App

This is where things get slightly tricky, mTLS support in the Companion App is currently a Labs feature as of April 2026. It works, but it’s not considered fully production-ready yet. Expect it to improve.

Enabling the Labs Feature

  1. Open the Home Assistant Companion App
  2. Go to Settings โ†’ Companion App โ†’ Debugging
  3. Scroll to Labs and enable mTLS Client Certificate support

Adding the Certificate to the App

  1. Go to Settings โ†’ Companion App โ†’ [your server name]
  2. Tap Connection
  3. Scroll to find the mTLS certificate option
  4. Import your .pfx file and enter the password

The Cache Bug. And the Fix

When I set this up, I ran into a specific issue: editing my existing server connection to add the mTLS domain and certificate just refused to work. The app would not connect no matter what I tried. The fix was simple once I found it, delete the server connection entirely and re-add it from scratch.

Something gets stuck in cache when you modify an existing server entry. Adding it fresh resolved it immediately. If you hit the same wall, don’t spend time troubleshooting the certificate, delete the server and re-add it.

If you’re still stuck after re-adding: Try rebooting your iOS device. The combination of the Labs feature and a fresh server entry resolved it cleanly in my setup, but a reboot cleared lingering issues on one of my devices.


The Dashboard Tablet Exception. A Deliberate Choice

My kitchen runs a Samsung Tab S9 FE+ locked into the Home Assistant Companion App as the home launcher. It handles announcements, runs a voice satellite for local voice control, and gives the kids access to YouTube, Sonos, and their drawing app from the media view of the dashboard. Home Assistant controls exactly which apps they can open from there.

That tablet does not have a client certificate installed. It uses local network access only.

This was deliberate from day one. The tablet lives at home. It doesn’t need remote access, it’s always on the local network. Requiring a certificate on a shared family device that also functions as a kids’ tablet adds complexity with no security benefit for that specific use case.

There’s also a travel dimension to this. When we take long trips, that tablet comes with us as the kids’ entertainment device. The moment it leaves home Wi-Fi, Home Assistant goes completely dark on it, no controls, no voice, no automations. It becomes a plain tablet. That’s exactly the right behaviour. No certificate to manage, no access to revoke, no risk surface when it’s away from home.

The rule is simple: devices that need remote access get certificates. Devices that should only work at home don’t get certificates and don’t get remote access. Clean separation.


What Bad Actors Actually See

With mTLS enforced, anyone who visits https://home.yourdomain.ca without a valid client certificate sees a Cloudflare access denied page. That’s it. No Home Assistant branding. No login form. Nothing that identifies what software is running or what’s on your network.

The request never reaches your server. It never reaches your tunnel. Cloudflare handles the rejection at the edge, and your infrastructure never knows the attempt happened.

CloudFlare blocking a request from getting to your website thanks to Mutual TLS Authentication

This matters for a few reasons beyond the obvious:

  • No fingerprinting. Attackers can’t identify Home Assistant as the target.
  • No brute force surface. There’s nothing to submit credentials to.
  • No server load. Failed attempts don’t consume CPU or memory on your machine.
  • No log noise. Your Home Assistant logs stay clean because the traffic never arrives.

From a cybersecurity standpoint, this is about as clean a solution as you can get for home use. You’ve moved the authentication boundary from your server to Cloudflare’s global network, and you’ve made the authentication invisible to anyone who doesn’t already have a certificate.


Known Limitations

The Tesla browser problem. My Tesla’s browser doesn’t support mTLS, which means it can’t access home.yourdomain.ca directly. For now I’m using Nabu Casa as a fallback for that specific use case. My plan is to create a narrow Cloudflare Access bypass rule using the ISP cellular range from Tesla’s network and the Tesla browser user agent, essentially an allow rule that’s specific enough to be low-risk. I haven’t implemented it yet and I won’t publish instructions for it until I have it running and tested. That will be a follow-up post.

New devices require re-finding the certificate. Every new phone, laptop, or tablet means locating your .pfx file, remembering the password, and going through the install process again. This is genuinely the only friction point in this entire setup. The solution is to store the .pfx and its password in your password manager from day one. One file, one password, accessible everywhere. The one-time install on each new device is a small price for what you get in return.

mTLS in the Companion App is a Labs feature. It works well, but it’s not finished. The cache bug I mentioned is one example. Expect the experience to smooth out as development continues, the fact that it’s in Labs at all is recent, and the team is actively working on it.


The Bottom Line

A login page is not a security boundary. It’s a door with a lock that every bot on the internet can knock on.

mTLS turns your Home Assistant into a building that doesn’t appear on any map. No door. No sign. No address that unauthorized visitors can find. Just a Cloudflare access denied screen and a dead end.

It’s free. It runs entirely within your existing Cloudflare Zero Trust account. Setup takes under an hour. The protection is permanent.


Smart Home Secrets is reader-supported. We may earn a commission if you buy through our links.