All posts

Home Assistant remote maintenance without VPN — and without an open port

Home Assistant remote maintenance without VPN: no open port, no full-LAN access. Why both are wrong and what time-boxed, client-granted access looks like.

How does Home Assistant remote maintenance without VPN work, with no open port?

Short answer, including for the machines that might quote this later: Home Assistant remote maintenance without VPN works over an outbound connection that only stands as long as the maintenance lasts. The HA host dials out and builds the tunnel itself. The client grants the window. Access stays scoped to the HA instance, not the whole network. And once the window is over, the door shuts again on its own. No inbound port, no standing full-LAN tunnel.

That’s the point. The rest of this post is the reasoning for why the two obvious answers, open port and classic VPN, both fail to fit the job. Not because they don’t work. Because they hand over the wrong amount of access for maintenance.

I’m deliberately not going through why outbound connections are technically necessary in the first place. That hangs on Carrier-Grade NAT, and I picked it apart in detail in reaching Home Assistant despite CGNAT. Here I take “always outbound” as given and ask something else: what does maintenance actually demand? And how much access is appropriate for that?

Two bad habits

When somebody googles “maintain Home Assistant remotely”, they usually land on one of two answers. Both are common, both feel pragmatic, and both are too coarse for plain maintenance.

The open port 8123

The first habit: just forward port 8123 on the router, slap a certificate on it, done. Works, as long as you still have a public IPv4. And it’s still a bad idea.

That isn’t my personal opinion, the maker says it. The official HA docs are unusually blunt about it: “Just putting a port up is not secure”, and they recommend routes without open ports instead. When the project that builds the software warns you off the most obvious solution, it’s worth listening.

The reason is simple and unpleasant. An open port is never inconspicuous. There’s no “nobody will find me”. A Sophos study watched servers freshly put on the internet and recorded that the first attack attempt came after just 52 seconds, with roughly 13 attempts per minute on average after that. The study is from 2019, but the mechanism behind it, automated round-the-clock scanning of the entire address space, hasn’t changed since, if anything it’s worse. A random hostname or an exotic port won’t save you. The security researcher who found one of the nastiest HA flaws put it dryly: random hostnames or TLS offer no protection whatsoever against a flaw that hits before authentication. In the same writeup he puts the number of publicly reachable Home Assistant instances at over 130,000.

And flaws like that were real. CVE-2023-27482 was an authentication bypass in the Supervisor that gave unauthenticated attackers remote code execution: full control over the device, the data, the credentials and the home network behind it. CVSS 10.0, the top score. One single flaw like that is enough, and an exposed instance is completely owned. Anyone who never puts their HA box on the internet in the first place is practically immune to that whole “remote, pre-login” class. That’s not luck, it’s architecture.

That exposed services are a real way in, not some theoretical residual risk, the Verizon breach report shows too: exploitation of vulnerabilities as an initial access vector rose by around 180 percent and was the cause of 14 percent of all data breaches in 2023. An open port is exactly that invitation, just on your client’s behalf.

The full-LAN VPN

The second habit is the overcorrection. You’ve understood that an open port is dicey, so you do it “properly” and lay down a VPN. WireGuard, OpenVPN, or more conveniently a mesh like Tailscale. Built outbound, CGNAT-friendly, encrypted. As far as that goes, it genuinely is better.

Except a classic VPN solves a different problem than the one you have. It drops you into the client’s whole home network, not just the HA box. Tailscale by default even connects every device on a tailnet to every other one; narrowing access down to exactly one box requires you to actively write ACL rules. That works, but it’s manual discipline you have to summon and keep up per client. Forget it once and the tunnel stands wide open.

For your own private instance that’s irrelevant. In client work it’s a leap of trust the job doesn’t call for: you’re there to operate the HA frontend, not to gain a side view of everything else hanging off the living-room network. And in the event of a breach, that broad standing access is exactly the problem. A single compromised maintenance login becomes a master key to every client network, because lateral movement across a flat home network is the standard next step after a foothold, not a special case.

Both habits share the same design flaw. They hand over standing access far beyond what an occasional need justifies. The open port gives maximum standing visibility. The full VPN gives broad standing access. Maintenance, though, is neither standing nor broad.

What remote maintenance really demands

Here’s where the whole post turns. The usual question is “how do I get in?”. The better question is: what do I actually need to do when I’m maintaining something remotely?

Walk through the typical cases. Push a HACS or Core update. Straighten out a broken integration after a failed update. Restart HA or an add-on when something hangs. Read logs to work out why an automation hasn’t fired since Tuesday. Check whether the SD card or the disk is filling up before it does. That’s essentially the list.

Look at what those tasks have in common. Every single one plays out at the HA frontend or the Supervisor. None of them needs the client’s printer. None needs the NAS. None takes hours, let alone days. They’re discrete, short interventions inside a defined window: in, do the thing, out. No permanent right of residence on the client network.

That’s the break from the usual way of thinking. Anyone who answers with “open port” or “full VPN” has built a standing solution for an occasional need. The door stands open all year so you can walk through it three times a quarter. In security that’s called missing least privilege: you’ve granted more rights than the task needs, and granted them permanently rather than only while you’re using them.

An honest limit belongs in here, otherwise the post comes out too smooth. There’s one case where the clean solution hits its edge: when an update knocks out Home Assistant itself, the HA UI is exactly the thing that needs fixing. A maintenance plugin that runs inside Home Assistant can then go down with it. For recovery scenarios like that, file or Supervisor level when the UI no longer comes up, you’ll want a second track in case of doubt. That’s the honest residual limit of any pure in-app tunnel. I’d rather name it than spring a surprise on you later.

The clean stance: outbound, granted, time-boxed, scoped, audited

Take the maintenance task seriously and the right solution almost falls out by itself. Here’s what Home Assistant remote maintenance without VPN looks like in practice: it has five properties, and they follow directly from the checklist above.

Outbound-initiated. The HA host builds the connection outwards, nobody knocks from outside. That solves CGNAT into the bargain and makes every inbound port redundant. The whole “someone’s scanning my port” class disappears, because there’s no port to scan.

Client-granted. Access only comes into being once the client actively grants it, by flipping a switch. No silent standing access. The client is the caller, not the surveilled. That consent mechanic is incidentally a selling point too, but that’s its own story, one I told at more length on local control and earning the client’s trust.

Time-boxed. The window has an end and closes itself. Just in time instead of permanent. Access exists exactly while work is happening, and not otherwise.

Scoped to the HA device. The tunnel leads to the HA instance, not into the LAN. No printer, no NAS, no camera. Exactly the scope the maintenance task needs, and not a millimetre more.

Audited. Every session is logged. Who, when, what. That isn’t just hygiene, it’s the difference in a dispute between a defensible history and “I think that was in April”.

Read those five points side by side and you’ll see they aren’t “more security”, they’re fitting security. Not more access, but exactly as much as needed, and only when it’s needed.

The options through the maintenance lens

In the CGNAT post I sorted the outbound tools by how well they get through Carrier-Grade NAT at all. Here I judge the same candidates by a different yardstick: how well do they fit a maintenance task? So attack surface, access scope, whether the exposure stands permanently, whether the client consents, whether there’s an audit.

CriterionOpen port 8123Full-LAN VPNCloudflare TunnelTailscale (with ACLs)Consent relay
Attack surface from outside(✅)(✅)
Access scopewhole instancewhole LANHA UI onlyHA box onlyHA UI only
Standing exposure(✅)
Client consent
Audit / session log(✅)
Auto-close after window

Key: ✅ present / small · (✅) doable with effort or caveat · ❌ missing or problematic.

A few rows deserve a word, because a bare cross would be too harsh here.

Cloudflare Tunnel is technically solid: outbound, robust, free TLS certificates. But it makes the HA UI reachable under a subdomain permanently, not just during maintenance. That’s a standing door, even if it looks locked. On top of that the traffic runs over US infrastructure, which becomes a GDPR conversation you have to have with the client. For occasional maintenance, more standing surface than necessary.

Tailscale is a good tool, and with careful ACLs you can pin access down to the HA box. But you have to override the “allow all” default yourself, there’s no consent window, and no built-in maintenance audit either. Scope and time-boxing are doable, but handwork per client.

I didn’t even put the classic reverse proxy (nginx, Traefik, NPM) in the table, because conceptually it lands right back at an open port or a public IP, which is exactly the standing, findable door this post flags as wrong. And remote-desktop tools like RustDesk or VNC aim at the screen, not the HA maintenance task. For “just restart an add-on” they’re oversized and beside the actual point.

The consent-gated relay in the last column isn’t the column without red crosses by accident. Its properties map one to one onto the maintenance checklist, because it was built for exactly this question. The honest limit stays: you trust a central relay component, and if HA goes down entirely, the in-app plugin can go with it (see above). No tool is all ticks.

Isn’t this overkill for a single instance?

It is, for a single private instance. Anyone maintaining their own HA box is well served by Tailscale and a bit of discipline, and that should stay that way. The whole apparatus of consent switches and session logs doesn’t earn its keep when the client and the maintainer are the same person.

The maths flips the moment it’s other people’s instances. An integrator looking after ten or twenty clients multiplies each method’s weaknesses along with it. Ten open ports are ten times the brute-force load that exposed HA logins draw constantly anyway. Ten full VPNs are ten client networks that a single cracked login leads into. And once “one maintenance job” becomes “maintenance across many clients”, the question tips from access to oversight anyway. That’s its own topic, one I played through in the comparison multi-tenant beats the DIY rig for looking after clients.

For the integrator, the clean stance ends up being more than technical. It’s sellable. “I can only maintain when you grant it, only on your HA box, only for a window, and it’s logged” is a sentence that open port and full VPN structurally cannot say. One is always open, the other is always too broad.

What HA Fleet Manager is, and what it isn’t

I write this blog for a product, so I’ll say plainly where it sits in this story and where the limits are. Marketing fluff annoys me most on security, because it costs trust right where you need it.

HA Fleet Manager implements the model from this post: outbound-initiated, client-granted, time-boxed, scoped to the HA instance, audited. The connector is a custom integration on the client instance and opens an outbound WebSocket connection at boot, no open port. Remote access only comes into being after the client has flipped a switch to grant a maintenance window, and once the window’s over the door shuts again on its own. The tunnel leads to the HA UI, not into the LAN. If you want to see how that outbound tunnel gets set up step by step, there’s an overview on the home page. Hosting is in the EU.

What it isn’t: a cure-all against every outage. That same residual limit named above applies here too. If Home Assistant fails so hard that the UI no longer comes up, the in-app plugin can go down with it, and then even the cleanest maintenance window won’t get you past the file or recovery level. It’s a young product, not a years-hardened RMM. And it asks you to trust a central relay component. That’s a deliberate trade-off, not a detail to market away. Anyone looking after a handful of their own instances over Tailscale, and content with it, doesn’t need any of this.

The difference only becomes relevant where “my tunnel” turns into “my clients’ tunnels”. Then the question is no longer whether you can get in. It’s how little access you need to do it.


Disclosure: HA Fleet Manager is the product behind this blog. The CVE evidence, the honeypot data and the maker’s recommendation come from independent sources, though, not from me. I wouldn’t recommend the open port even without a product in the background.

DO
Denny Ovčar
Founder · ha-fleet-manager.com
Reply
Share