Securing Home Assistant’s Android App with Cloudflare Zero Trust & mTLS

A step-by-step recipe for locking down the Home Assistant Android companion app behind Cloudflare Zero Trust using mutual-TLS (mTLS). We’ll generate a client certificate, install it on the phone, and apply precise Cloudflare rules so that only your trusted devices can reach your smart-home—even when Single-Sign-On (SSO) would otherwise kick you out.

Why bother with mTLS if I already use Zero Trust SSO?

Using Cloudflare Access/Zero Trust with SSO is great for browsers, but the Android companion app doesn’t maintain its session reliably. After a few hours or days it stops sending authenticated requests, and the only workaround is to wipe the app’s data and sign in again.

mTLS fixes that by authenticating the device itself with a unique client certificate. The phone doesn’t have to refresh a web session, so you stay connected and your dashboards, sensors, and push notifications keep flowing.

What you’ll need

  • A working Home Assistant instance already fronted by Cloudflare tunnel.
  • A second sub-domain pointing to the same Home Assistant instance —for example ha-app.example.com—reserved exclusively for mTLS traffic.
  • An Android device running the Home Assistant companion app.

Step-by-step guid

Create a dedicated sub-domain for the app

In Cloudflare DNS add ha-app.example.com, pointing it at the same origin/tunnel as your usual Home Assistant hostname.

Keeping mTLS traffic on its own hostname ensures browsers and external automations keep working while the Android app gains extra protection.

Generate a client certificate

Cloudflare Dashboard → SSL/TLS → Client Certificates → Create certificate.

Download the certificate (cf.pem) and private key (cf.key).

Set on Cloudflare Dashboard → SSL/TLS → Client Certificates also the host so that mTLS gets enabled on ha-app.example.com.

Convert the certificate to the PFX format Android likes

openssl pkcs12 -export -out cf.pfx -inkey cf.key -in cf.pem

You will be asked for an export password—remember it for installation.

Copy the PFX file to your phone

Copy via USB.

Install the certificate on Android

Settings → Security & privacy → More security settings → Credential storage → Install from device storage → VPN and app certificate.

Pick cf.pfx, enter the export password, and give it a memorable name such as “HA mTLS”.

Block every request that lacks a certificate

Cloudflare Dashboard → SSL/TLS → Client Certificates -> create mTLS Rule.

Leave first field to Client Certificate Verified to false and on second select Hostname and equals to the new domain ha-app.example.com.

Choose action Block so that you don't allow going to this domain without the certificate installed.

Point the Home Assistant app at the new hostname

Sign in once via your regular domain (still behind Access SSO).

Inside the app go to Settings → Companion app → Servers & devices → Your device → Home Assistant URL.

Replace the URL with https://ha-app.example.com.

Back out: Android pops up a certificate chooser. Select the one you installed.

The app reconnects, stays logged in, and Zero Trust reports traffic as authenticated via mTLS.

Problems along the way

The only problem that I ran into is that I wasn't prompted by android to select the certificate. It turns out that I didn't set the host for mTLS on Cloudflare Dashboard → SSL/TLS → Client Certificates, so I just saw the unauthorized cloudflare page.

Wrap-up

By combining Cloudflare Zero Trust with device-level mutual-TLS, you solve the Android companion app’s session-expiry headache while hardening your Home Assistant instance against unwanted traffic. Huge thanks to Alex Silcock, whose original post was a huge help with this setup (https://www.alexsilcock.net/notes/protecting-home-assistant-with-cloudflare-access-and-mtls/). This article is primarily for my own documentation!