Decide who can reach Home Assistant, then give them a clean address
By now Home Assistant is in your tailnet and you can open it from somewhere else. Those two things are on or off. This article is about the settings in between: narrowing who is allowed through, and replacing the address-and-port you have been typing with a proper HTTPS name that never leaves the tailnet. Neither is hard. Both are easy to get wrong in the direction of too much access.
Three layers, and none of them replaces the others
Installing Tailscale is not a reason to assume that everything can now reach everything. When something is blocked — or, more importantly, when something is not blocked and you think it should be — the first useful question is which layer made that decision. There are three, and they are managed in three different places.
Think of an office building. Tailscale membership is the street door: you are either in the building or you are out on the sidewalk. The tailnet policy is the door to a particular floor. Your Home Assistant login is the key to the filing cabinet inside. Getting through the street door tells you nothing about the cabinet, and no amount of network setup will unlock it for you.
That last part is the one people skip. Tailscale manages the network path. Home Assistant should still use personal accounts, strong passwords and appropriate admin rights — Tailscale does not replace the Home Assistant login and was never meant to.
| Layer | What it handles | How you check it |
|---|---|---|
| Tailscale admin console | Accounts, Machines, routes and policy | Home Assistant appears in Machines |
| The HA Tailscale app | Runs Tailscale on the Home Assistant host | Status healthy, no blocking errors in the log |
| Home Assistant | Login, dashboard and admin rights | You log in normally with a personal account |
Tell those three apart before you change anything, so that later you do not spend an evening clicking in the wrong place. The app itself lives at Settings → Apps in the Home Assistant menu; if your screen still uses the older name, it will say Add-ons. The interface text and its translations vary by version, so recognize the Tailscale app and its Info, Configuration, Log and Web UI tabs rather than memorizing a menu label.
flowchart TD
A["A phone on some other network"] --> B{"Is this device signed in
to your tailnet?"}
B -->|"no"| X["There is no path at all"]
B -->|"yes"| C{"Does the tailnet policy let
this source reach the Home
Assistant machine?"}
C -->|"no"| Y["The network path stops here"]
C -->|"yes"| D{"Does this person have a
Home Assistant account?"}
D -->|"no"| Z["The login page, and it stays there"]
D -->|"yes"| E["The dashboard, with whatever rights
that Home Assistant account has"]
Least privilege is a list you write before you edit anything
Least privilege means one thing here: give network access to the people and devices that need to use Home Assistant, and to nobody else. Admin rights inside Home Assistant stay where they are, controlled by Home Assistant user accounts.
You ask a neighbor to water the plants while you are away. You hand over the front door key. You do not hand over the whole keyring — the garage, the shed, the filing cabinet, the car. It is not that you distrust them. It is that there is no reason for those keys to leave your hand, and every reason for them not to.
Two syntaxes exist for writing those rules. The Tailscale docs recommend grants as the modern access-control syntax, and ACL is still supported. If you already have working ACL rules, they have not stopped working; if you are writing something new, grants are what the documentation points you at.
The four steps, in order
-
Step 1
Take inventory of sources and targets
On paper, or in a note. Write down who needs to reach Home Assistant, from which device, and which ports or services they actually need. Family members who use the dashboard day to day and the person who administers the tailnet are different roles, even when they are the same person on two different devices.
-
Step 2
Read the current rules in Access controls
Open Access controls in the Tailscale admin console and understand the grants or ACL that are already there. Do not paste in a whole policy you found online. A policy from someone else's network describes someone else's devices.
-
Step 3
Grant the minimum that works
Grant only the necessary sources access to the necessary machines and services, and preserve the meaning of the rules that were already there. The list from step 1 is what tells you where the edges are.
-
Step 4
Test with a non-admin account
Verify Home Assistant from a test device that should have access, and confirm that no account which should not have access quietly picked up a wider scope. An admin account passing the test proves less than you think.
Step 1 sounds like homework you can skip. It is the step that makes the other three short. Written out, an inventory tends to look like this:
flowchart TD A["Someone cannot reach
Home Assistant"] --> B{"Should they be
able to?"} B -->|"no"| C["Leave the policy alone.
It is working"] B -->|"yes"| D{"Is their device signed in
to the same tailnet?"} D -->|"no"| E["Fix the device,
not the policy"] D -->|"yes"| F{"Is it the network path or the
Home Assistant login failing?"} F -->|"the HA login"| G["Sort out their Home
Assistant account"] F -->|"the network path"| H["Widen the grant for that one
source and that one target"]
Start small, then expand
Start with the smallest setup that works and grow it deliberately. If all you want is to see your dashboard while you are away, private access over the tailnet is usually easier to control than a public entry point. If you need to reach a LAN subnet, list one subnet with a clear purpose first rather than advertising every network at once.
| What you need | Where to start | Not yet |
|---|---|---|
| View Home Assistant remotely | Private access from a device signed in to the tailnet | Open router ports, and public sharing you do not need |
| Manage devices | The Machines list, with personal accounts | A shared admin login everyone knows |
| Reach your home LAN | A single approved subnet route | Advertising several subnets before taking inventory |
Serve keeps it inside. Funnel does not.
Serve and Funnel look like two settings on the same switch. They are not the same risk. Tailscale Serve makes a local service available to the devices inside your tailnet. Funnel makes it available to the wider internet. The official docs draw a clear line between them, and this guide deals only with Serve.
Serve is an internal extension number. Anyone already inside the building can dial it; nobody outside can dial it at all, because the number does not exist out there. Funnel prints that same number in the public directory. Same phone, same desk — a completely different set of people who can make it ring.
flowchart LR
subgraph F["Funnel, which is out of scope here"]
direction LR
F1["Any device on the public
internet, with no Tailscale
installed on it"] --> F2["Tailscale relays
it inward"] --> F3["Home Assistant"]
end
subgraph S["Serve, which is what this article sets up"]
direction LR
S1["A device signed in
to your tailnet"] --> S2["An HTTPS name that only
exists on the tailnet"] --> S3["Home Assistant"]
end
Both behaviors are reached through one option in the Home Assistant app, share_homeassistant, which is disabled by default. That default is a good one. Leaving it alone is a valid choice, and if the address-and-port you already use is working for you, you can stop reading here and skip to Part 5.
Five steps to an HTTPS address that stays private
What you get at the end is a URL you can type on any device in your tailnet, with no port number on the end and no certificate warning. What you change to get there touches three different places: a Home Assistant configuration file, the Tailscale admin console, and the app's own options. Do them in this order.
Step 2 below is the one that looks like magic. Once Serve is in front, every request reaches Home Assistant from the machine itself rather than from the phone that sent it — the way all post in an office arrives from the mailroom, with the mailroom's own address on the envelope. Those two settings tell Home Assistant that the mailroom is trustworthy, so it should read the forwarding label instead of the envelope.
Settings → Apps in the Home Assistant menu, find Tailscale, and note whether it is running. One line in a note is enough. That line is what you compare against if something stops working later, and it is the difference between rolling a change back and guessing at what the change was.share_homeassistant does not sit alone on the Configuration tab. It has neighbors — options this article says nothing about, which are set the way they are for a reason. Change the one the step names, and leave the rest exactly where you found them.-
Step 1
Leave Home Assistant on local HTTP
The official app docs assume Home Assistant is reachable over HTTP. If you already run another HTTPS reverse proxy in front of it, do not stack the two setups on top of each other — assess your situation against the docs before going further. This step is often nothing at all: a default installation is already where it needs to be.
-
Step 2
Set up trusted proxies, then restart Home Assistant
In
configuration.yaml, inside the existinghttp:section or a new one, set both of the values below. Save the file, then restart Home Assistant.use_x_forwarded_for: truetrusted_proxies: - 127.0.0.1The address
127.0.0.1is the machine talking to itself — it is the same on every computer, so this is not a value you need to look up or change. -
Step 3
Enable HTTPS in the Tailscale admin console
Go to the DNS settings in the admin console, choose a tailnet name, enable MagicDNS, and then choose Enable HTTPS under HTTPS Certificates. This is the prerequisite for Serve to obtain a certificate — skip it and step 4 has nothing to present to your browser.
-
Step 4
Set share_homeassistant to serve, then restart the app
In the Tailscale app's Configuration tab, set
share_homeassistanttoserve. Leaveshare_on_portat its default of443. Restart the app.Do not choose
funnel. It is the neighboring value in the same field, which is exactly why it is worth pausing on this step rather than clicking through it. -
Step 5
Open the new URL from another tailnet device
From a phone or laptop signed in to the same tailnet, open
https://<machine>.<tailnet>.ts.net— with no port number on the end, unlike the address you have been using so far. Then log in with your personal Home Assistant account, as usual.The two bracketed parts are placeholders. Your own machine name and tailnet name go there; this guide does not print real ones, and neither should you when you ask for help.
flowchart LR A["A device signed in
to the tailnet"] -->|"HTTPS on port 443"| B["Serve, running on the
Home Assistant machine"] B -->|"local HTTP,
arriving from 127.0.0.1"| C["Home Assistant, still
on plain HTTP"] C --> D["Your normal Home
Assistant login"]
The check, the test, and the note you leave behind
Three quick confirmations before you consider this finished. None of them takes more than a minute, and all three are the sort of thing that is obvious now and impossible to reconstruct in six months.
The right Tailscale account
Confirm the account signed in to Tailscale is the one you meant to use. It is easy to authorize a device with whichever account the browser was already holding.
Home Assistant still on personal accounts
Everyone who uses Home Assistant should still have their own account in it. Only the people who need to manage the tailnet should have admin console access.
No strangers in Machines
Open the Machines page in the Tailscale admin console and account for every entry. Unknown devices are the obvious problem; retired ones — the replaced phone, the dead tablet — are the common one.
Cross-check the Home Assistant machine in the admin console
Open the Machines page in the Tailscale admin console and confirm the machine that corresponds to Home Assistant. Finding its name in the list is the easy half. Two other things on that row tell you more:
| What to read | What it tells you | When it looks wrong |
|---|---|---|
| Its last-seen status | Whether the machine is connected right now, or was last connected at some point in the past | A stale last-seen means the machine stopped talking to the tailnet. Read the app log before you change any setting. |
| Its feature badges | What this machine is doing for the tailnet beyond simply being a member of it | A badge you were not expecting means something is switched on that you did not switch on. Find out what before you carry on. |
Test it on two networks
One test proves less than two, because a device at home may be reaching Home Assistant over your LAN without Tailscale being involved at all.
- On your home network: open Home Assistant on the local LAN and confirm that your existing accounts and dashboard were not affected by the changes in this article.
- On a different network: switch a test phone to mobile data or another secure network, confirm Tailscale is connected, then open Home Assistant once. If you are testing routes, test only targets you are authorized to manage.
- Record the result: success or failure, the device you used, and the time. That is far easier to work from later than remembering that “it used to work”.
- Stop at the security boundary: this guide does not cover exit nodes, DNS override or public Funnel setup. Leave them disabled unless you have a specific need for them.
Leave a handover-ready record
The biggest risk with network settings is not that they break. It is that they worked at the time and nobody remembers why. When you finish, write down the date, who did it, the purpose, the state before and after, and the device you verified with — in your password manager or your site maintenance notes.
That record is not a place to store passwords, auth keys or full private subnets. Those belong in a controlled secrets manager. The note holds only the description the next maintainer needs in order to understand the decision. A real one reads like this: “2026-08-19, the administrator confirmed the Home Assistant machine is still in the designated tailnet; private access tested successfully from a managed laptop on a non-home network.” For a subnet router, add that only a single approved LAN CIDR is advertised and approved in the admin console.
| Record this | Keep out of public docs | Who needs it next |
|---|---|---|
| Purpose of the change, date, verification result | Credentials, auth keys, login URLs | The Home Assistant maintainer |
| Each machine's purpose and its owner's role | The full tailnet domain and private IPs | The Tailscale admin |
| Which subnet, with a clear purpose, was approved | Unredacted CIDRs, scan results, street addresses | The network maintainer |
Never write street addresses, customer names, the full Tailscale domain or device identifiers into a public repository. The record is what lets you judge which layer to roll back when a phone is lost, a router is replaced, the app is updated, or admin rights are handed to someone else.
Check these first, then the questions people ask
I cannot find Apps in the Settings menu
Home Assistant is not in the Machines list
Machines shows Home Assistant, but Home Assistant will not open
The route seems to exist but the LAN is still unreachable
Things got uncertain after a change
Questions that come up every time
Do I need to open a port on my router?
Does Tailscale replace the Home Assistant login?
My screen says Add-on, not App
Can I set up an exit node or DNS override while I am in here?
Where to go from here
Home Assistant is reachable and scoped. Part 5 widens the door.
A subnet router lets the tailnet see the rest of your home network, not just the machine Tailscale is installed on. It also introduces the approval step that stops a route working until an administrator says so — which is a safety check, not a fault.
Open the full guidePart 4 of the Home Assistant Tailscale Remote Access Guide series on the Apporo blog.
Adapted from the Home Assistant Tailscale Remote Access Guide, produced by WoowTech and released under CC BY 4.0. This adaptation is published by Apporo under the same licence.
Light · Air · Water · Control · apporo