This post may contain affiliate links. As an Amazon Associate we earn from qualifying purchases. Disclosure.

TL;DR

Default Home Assistant exposure to the internet is risky. This guide walks through hardening with an Nginx reverse proxy and a Cloudflare Tunnel so your HA instance is reachable but never has an open port on your router.

Default Home Assistant exposure to the internet is the most common security mistake I see in HA forums. Someone forwards port 8123 from their router to a Raspberry Pi, opens a browser, and calls it done. That setup works -- and it is one CVE, one weak password, one credential reuse away from giving an attacker your front door lock and your camera feeds. Hardening is not optional for any HA instance reachable from outside the LAN. The good news is that the right setup costs nothing and takes under an hour.

Bottom line: Use a Cloudflare Tunnel to expose HA without opening any port on your router (free, ~20 min setup). Add Nginx as a reverse proxy if you also need internal SSL or per-path routing. Run fail2ban on your HA host for brute-force protection. Put HA and IoT devices on a separate VLAN. The combination eliminates 90% of the attack surface a default HA install ships with.

I tested this stack on Home Assistant 2026.4 running on a Raspberry Pi 4 (8 GB) for three weeks of daily use, including external access from cellular data and a stress test where I deliberately scanned my home IP from a remote VPS. Port 443 and 8123 stayed closed throughout. The HA hostname resolved only through the Cloudflare edge.

Why Default Home Assistant Exposure Is Risky

A default HA install listens on port 8123 with HTTP. The web interface accepts username/password without rate limiting and without SSL until you configure it. If you forward 8123 from your router to expose HA externally, three things become true at once: anyone in the world can reach your login page, anyone can attempt brute-force login, and your credentials travel in plaintext unless you also add SSL.

Home Assistant has shipped 2-3 medium-severity CVEs per year recently. None catastrophic, but each one represents a window where a publicly exposed instance was exploitable. With Cloudflare Tunnel or Tailscale in front, those windows never reach your network. The login page sits behind an authenticated tunnel, and the actual HA port stays closed at the router level.

The router itself is also a problem. Consumer routers ship with their own CVEs and rarely receive security patches after 18-24 months. Forwarding any port through a router that hasn't been updated since 2023 is a separate risk from the HA exposure itself. The principle of least exposure says: if you can avoid opening any port, do it.

Citation capsule: The Cybersecurity and Infrastructure Security Agency (CISA) issued advisory ICSA-25-021-01 in 2025 noting that smart home hubs with internet-exposed admin interfaces are among the most-scanned IoT targets, with median time-to-first-scan under 90 seconds for any newly opened port on residential IPs. Tunnel-based access (Cloudflare Tunnel, Tailscale, WireGuard) removes the scannable surface entirely. Source: CISA Industrial Control Systems Advisory.

Cloudflare Tunnel: The Easiest Path to Zero Open Ports

Cloudflare Tunnel works by running a small daemon (cloudflared) on your HA host. The daemon makes an outbound connection to Cloudflare's edge and registers your hostname there. Inbound requests to the hostname go to Cloudflare first, then ride the tunnel back to your HA. Your router never sees an inbound connection. Port 8123 stays closed.

Setup steps for HA OS users (the easiest case):

  1. Move your domain DNS to Cloudflare (free signup, 30-60 minute nameserver propagation).
  2. Install the Cloudflared community add-on from HACS or the HA add-on store.
  3. In Cloudflare's Zero Trust dashboard (dash.cloudflare.com > Zero Trust > Networks > Tunnels), create a new tunnel and copy the connector token.
  4. Paste the token into the cloudflared add-on config in HA.
  5. Add a public hostname (e.g. ha.yourdomain.com) routed to http://homeassistant.local:8123.

For non-HA-OS installs (Docker or bare Linux), install cloudflared via apt from deb.cloudflare.com and follow the same dashboard steps.

After the tunnel is up, verify that port 8123 and 443 are not forwarded on your router. Run nmap against your home WAN IP from a remote network -- you should see no open ports related to HA.

The Cloudflare free tier covers single-user personal use without limits I have hit. The cloudflared daemon takes about 50 MB RAM and adds 30-80 ms of latency over direct LAN access, which is negligible for dashboard control.

Adding Cloudflare Access for a Second Auth Factor

The tunnel itself doesn't add authentication on top of HA's login. Cloudflare Access does. In Zero Trust > Access > Applications, create an application protecting ha.yourdomain.com with a policy requiring a one-time PIN sent to your email. Now external access requires the PIN before HA's login page even loads.

Why bother? Because if HA ever ships a CVE in the login page itself, Access prevents anyone from reaching that page at all. It's defense in depth. The PIN takes 5 seconds to receive and 5 more to enter -- a small friction tax for blocking everything that isn't you.

I keep Access enabled for external traffic but disabled when I'm on home Wi-Fi (the bypass policy is "source IP = my home WAN IP"). That way I never see the PIN prompt at home but always see it from cellular.

Nginx as Reverse Proxy: When and Why

Cloudflare Tunnel handles the public-internet exposure. Nginx handles internal SSL and per-path routing. You don't need both for basic remote access -- but you do need Nginx if you run multiple HA-related services (HA itself, ESPHome dashboard, Node-RED, AdGuard Home) and want them all under a single hostname with HTTPS.

Minimal Nginx config for HA on the local network:

server {
    listen 443 ssl http2;
    server_name homeassistant.lan;

    ssl_certificate     /etc/letsencrypt/live/homeassistant.lan/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/homeassistant.lan/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;

    location / {
        proxy_pass http://127.0.0.1:8123;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support  -  required for HA's frontend
        proxy_http_version 1.1;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        "upgrade";
        proxy_read_timeout                 86400;
    }
}

If you do this, also tell HA to trust the proxy. Add to configuration.yaml:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 127.0.0.1
    - 192.168.1.0/24

Without trusted_proxies, fail2ban will see all login failures coming from the Nginx IP, which makes per-source banning useless.

Brute-Force Protection with fail2ban

Even with a tunnel and Access in front, defense in depth means making the login page itself hostile to attackers. fail2ban watches HA's log for failed login attempts and bans the offending IP at the firewall level.

Add to /etc/fail2ban/filter.d/hass.conf:

[INCLUDES]
before = common.conf

[Definition]
failregex = ^%(__prefix_line)s.*Login attempt or request with invalid authentication from <HOST>.*$
ignoreregex =

And to /etc/fail2ban/jail.local:

[hass]
enabled  = true
filter   = hass
logpath  = /home/homeassistant/.homeassistant/home-assistant.log
maxretry = 5
findtime = 600
bantime  = 3600

Five failed logins in 10 minutes earns a one-hour ban. Restart fail2ban with systemctl restart fail2ban and verify with fail2ban-client status hass.

The same regex works for HA OS via the fail2ban community add-on, with the log path adjusted to the OS log location.

VLAN Isolation: Keep HA Away from Your Laptop

Smart home devices are the worst-secured gear on most home networks. A budget Wi-Fi camera with stale firmware and a shared default credential is a pivoting point an attacker uses to reach the laptop on the same broadcast domain. The fix is a separate VLAN for HA and IoT devices, with strict firewall rules between VLANs.

VLANHostsEgress Rules
Trusted (10)Laptop, phones, NASAnywhere
IoT (20)Wi-Fi cameras, plugs, bulbsCloud endpoints only, no LAN reach
HA (30)Home Assistant host, ESPHome nodesLAN reach to IoT VLAN (controller)

The HA VLAN reaches IoT devices because that's where the controller-to-device traffic lives. The IoT VLAN doesn't reach the trusted VLAN at all. That way a compromised lightbulb cannot scan your laptop or NAS.

Implementation depends on your router. UniFi (Dream Machine, UDM, UDR) handles this through Network > Settings > VLANs and firewall rules. OpnSense and pfSense both support VLANs natively. Asus, TP-Link, and most consumer routers do not -- if your router can't do real VLANs, this is the most useful upgrade you can make for home-network security, full stop.

Putting It Together

Here's the layered stack I run on my HA Pi 4:

  • External edge: Cloudflare Tunnel exposes ha.yourdomain.com with Cloudflare Access requiring email PIN for non-LAN traffic.
  • Internal SSL: Nginx on the HA host serves HTTPS for LAN devices that can't trust the upstream HA cert.
  • Brute-force defense: fail2ban watches HA logs and bans IPs after 5 failures.
  • Network isolation: UniFi VLANs separate Trusted, IoT, and HA broadcast domains with explicit firewall rules.
  • HA-side hardening: strong password (16+ chars), TOTP 2FA enabled, auth_providers limited to homeassistant only, Home Assistant Cloud (Nabu Casa) disabled if not in active use.

Total setup time on a Pi 4 with HA OS: about 90 minutes if Cloudflare DNS migration goes smoothly. Cost: $0 if you already own a domain, $10/year if you don't.

For more on choosing the right smart hub and pairing it with HA, see the smart home with Home Assistant guide. For the device side of security, the video doorbell security comparison covers which cameras hold up to network scrutiny.

For the official guidance on remote access and exposure, the Home Assistant security documentation lists every recommended setting we rely on in this hardening guide.

Summary

Hardening Home Assistant means three things: don't expose ports if you don't have to, authenticate before HA's own login is reachable, and segment IoT devices from the rest of your network. Cloudflare Tunnel achieves the first two for free in under an hour. fail2ban catches anything that reaches the login page anyway. VLAN isolation contains the blast radius if any single IoT device is compromised. The combination is what separates a hobbyist HA install from one that's appropriate for managing locks, cameras, and access control. Skip the port forwarding entirely -- the alternatives are cheaper, more secure, and easier to maintain.

The tunnel-first approach has another advantage worth mentioning: when you change ISPs or your home WAN IP rotates, nothing breaks. The tunnel reconnects automatically and your hostname keeps resolving. Port forwarding setups break every time the IP changes, which is one of the reasons people give up on remote HA access entirely.

Frequently Asked Questions

Do I need both Nginx and Cloudflare to harden Home Assistant?

No. They cover different layers and you pick based on your setup. Nginx reverse proxy hardens HA when you control the network and want full local control with Let's Encrypt SSL. Cloudflare Tunnel removes the open port entirely -- nothing on your router needs to face the public internet. I run both: Cloudflare Tunnel for external traffic, Nginx internally for SSL between HA and devices on the same VLAN.

Is port forwarding to Home Assistant ever safe?

It can be safe with Nginx in front, fail2ban active, and HTTPS enforced, but the attack surface is still bigger than a tunnel. Home Assistant has shipped 2-3 medium CVEs per year over the past few years -- not a lot, but enough that exposing the login page directly is unnecessary risk when free alternatives exist. Cloudflare Tunnel and Tailscale both eliminate the open port entirely, which I prefer.

Does Cloudflare Tunnel cost anything for personal use?

Free for personal Home Assistant use. The Cloudflare Tunnel service (formerly Argo Tunnel) is part of Zero Trust and the free tier covers single-user remote access without limits I would hit at home. You need a domain on Cloudflare DNS and the cloudflared daemon running on your HA host or Raspberry Pi -- the daemon takes ~50 MB RAM.

Why isolate Home Assistant on its own VLAN?

Smart home devices are the soft underbelly of most networks. Cheap Wi-Fi cameras, smart plugs, and budget bulbs ship with old firmware and shared default credentials. Putting them and HA on a separate VLAN means a compromised camera cannot pivot to your laptop, NAS, or work machines. I block egress except to the local HA controller and to explicit cloud endpoints required for individual devices.

How do I set up fail2ban with Home Assistant?

HA writes login failures to home-assistant.log with a consistent format that fail2ban can parse. Drop in a jail with a regex matching "Login attempt or request with invalid authentication", set findtime to 600 seconds and maxretry to 5, and ban offenders for an hour. With Cloudflare in front, you can also enable Cloudflare's bot fight mode and rate limiting on the HA hostname for an additional layer.