← All guidesGitHub
Development and Deployment

Host a private Home Assistant server with Tailscale

Host a private Home Assistant server on a Droplet with Tailscale HTTPS, no public dashboard ports, backups, and clear limits for devices on your home LAN.

Jump to stepsGitHub: TylorMayfield/private-droplet-tailscale

Host a private dashboard with a clear boundary

You can host a private Home Assistant server on a DigitalOcean Droplet and reach it through Tailscale without opening its dashboard to the internet. This guide builds on the private-SSH article. We will run Home Assistant Container, complete onboarding through an SSH tunnel, restrict the backend to loopback, and give selected tailnet users a private HTTPS address.

The server will live in a data center. It cannot directly use the Zigbee USB stick beside your router, hear nearby Bluetooth devices, or discover your home network as if it were on the same Wi-Fi. Start with a harmless dashboard and a cloud integration you already use. Do not move locks, heating, or other essential automations until you have tested the entire path and its failures.

I would keep Home Assistant at home for a radio-heavy household. A Droplet makes more sense for a learning environment or a small set of cloud-connected services when you already want to administer Linux. The comparison below should decide that choice before you create a paid server.

Choose cloud hosting for the right workload

Home Assistant OS is the recommended installation for most users. It manages more of the system and supports apps, formerly called add-ons. Home Assistant Container leaves the operating system, Docker and companion services to you. This tutorial uses Container; it does not install Supervisor or promise an app store on Ubuntu.

The benefit of a Droplet is a server that does not depend on keeping a spare computer powered at home. The cost is ongoing VM administration and an internet dependency for reaching home devices. Tailscale makes a private route possible, but it does not make those devices local. For a household that needs remote access rather than cloud hosting, Home Assistant OS at home plus a supported remote-access method is usually less work.

Scroll horizontally to see all columns.

Where should Home Assistant run?
OptionGood fitLimitation
Home Assistant OS at homeUSB radios, local discovery and everyday automationsNeeds local hardware and a remote-access plan
Container on a DropletLearning and compatible cloud integrationsLinux maintenance, no apps, no local radios
Container at homeExisting Linux operators with local devicesYou maintain Docker and hardware permissions

Budget for the server and finish private SSH first

Allow a couple of hours for the first deployment and longer for a restore rehearsal. Start with a fresh Ubuntu 24.04 LTS Droplet and enough memory for your intended integrations. A 2 GB machine is a reasonable small-lab starting estimate, not a measured capacity guarantee. Video processing, large histories and extra services can require much more. Review memory and disk use after adding each integration.

Check the selected monthly cap and hourly rate in DigitalOcean before creation. Include backups, extra storage and outbound transfer in your budget. Home Assistant Container itself is open source; the Droplet is paid infrastructure, and eligible personal Tailscale use has its own plan terms. No Home Assistant Cloud subscription is required for this particular private Tailscale route.

Complete the preceding guide first. You must have a tested operator SSH key, a recovery-console login, no cloud inbound rules, outbound connectivity, and the SSH-only tag policy. Keep a private session open while working. Do not begin with an existing public reverse proxy, an unrestricted tailnet, or a production Home Assistant configuration.

Install Docker and inspect the companion

From the private operator session, follow Docker's official Ubuntu apt-repository instructions linked below. Install Docker Engine and its Compose plugin from that same repository. Keep using sudo for Docker commands rather than granting ordinary users Docker group membership. Control of the Docker daemon effectively grants control of the host.

Run sudo docker version and sudo docker compose version to verify both are available. Clone the companion into the operator home directory, then enter it. Read compose.yaml before starting anything. It selects Home Assistant 2026.9.1 so the example does not silently follow a moving stable tag. Check release notes before adopting a newer version; the pin is a reproducibility choice, not a promise of indefinite security support.

The Compose file uses Linux host networking and persistent ./config storage. It omits privileged mode, USB devices and D-Bus because this cloud example does not use local hardware. This is a deliberate reduction from the general hardware-oriented installation example. Integrations requiring those capabilities need their own design review, not a blanket privileged switch.

Download and enter the companionConnected Droplet
git clone https://github.com/TylorMayfield/private-droplet-tailscale.git
cd private-droplet-tailscale
compose.yamlConnected Droplet
services:
  homeassistant:
    image: ghcr.io/home-assistant/home-assistant:2026.9.1
    network_mode: host
    restart: unless-stopped
    stop_grace_period: 60s
    environment:
      TZ: Etc/UTC
    volumes:
      - ./config:/config
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

Start the container behind the existing firewalls

Keep the initial SSH-only Tailscale policy active. Home Assistant initially listens on available interfaces, so the cloud no-inbound policy and the tailnet denial of TCP 8123 are prerequisites to this first start. Host networking means there is no Docker port mapping to hide behind. Do not add an 8123 rule to either firewall.

In the companion directory, create the private configuration folder with mkdir -m 700 config. The fresh directory must be empty. Set TZ in compose.yaml to your own IANA time zone if you want container logs to use it. Check the configuration and start the container with the commands below. Image download and initialization can take several minutes.

Inspect the logs if it keeps restarting. A running container only proves a process exists; it does not prove the dashboard is ready or private. Wait until a request to the loopback address returns an HTTP response. Never paste configuration files or full logs containing tokens into public issues. Use a short redacted error excerpt when seeking help.

Before continuing: Use the fresh tutorial Droplet and keep a tested recovery path. Read the preceding checkpoint before running.

Validate and start Home AssistantConnected Droplet
sudo docker compose config --quiet
sudo docker compose pull
sudo docker compose up -d
sudo docker compose logs --tail=80 homeassistant
Check the backend responds locallyConnected Droplet
curl --max-time 10 -I http://127.0.0.1:8123/

Complete onboarding through a local SSH tunnel

On your computer, open a dedicated terminal and run the tunnel command below. Replace TAILSCALE_IP with the Droplet's private Tailscale address. The command deliberately stays in the foreground. Leave it running and visit http://127.0.0.1:18123 in a browser on that same computer. This forwards your local port through authenticated SSH to port 8123 on the server.

Create the owner account with a unique password and save it in your password manager. Set your location, units and time zone deliberately; these values affect automations. Use a harmless helper such as a toggle for the first dashboard test. Leave automatic discovery expectations aside because the VM is not on your home LAN.

If your browser cannot connect, check that the tunnel terminal is still running and that nothing else uses local port 18123. If SSH reports forwarding is administratively prohibited, inspect the server's effective AllowTcpForwarding setting. Do not solve a tunnel error by opening the dashboard publicly.

  1. Run in a new local terminalLocal terminal
    Replace every highlighted value before running this command.
    ssh -N -o ExitOnForwardFailure=yes -L 127.0.0.1:18123:127.0.0.1:8123 operator@TAILSCALE_IP

Restrict the backend in the current HTTP settings

In Home Assistant 2026.9, open Settings > System > Network and find HTTP server. Set Listen addresses to 127.0.0.1 only, retain Server port 8123, enable Trust X-Forwarded-For, and set Trusted proxies to 127.0.0.1. Save, reconnect through the SSH tunnel, and confirm the settings within the five-minute confirmation window. Unconfirmed changes revert.

These instructions use the UI introduced in 2026.8. Do not paste an old http: YAML example into a new installation. The proxy will run on the host and connect to that exact IPv4 loopback address, so there is no reason to trust every private address, the whole tailnet, or 0.0.0.0/0.

On the Droplet, run the listener check below. The Home Assistant TCP listener must be 127.0.0.1:8123, with no 0.0.0.0:8123, [::]:8123 or public-address listener. If it is still broad, return to the tunnel and fix the saved HTTP settings before adding HTTPS access. Keep the cloud and tailnet restrictions in place throughout.

Inspect the port 8123 listenerConnected Droplet
sudo ss -lntp 'sport = :8123'

Add private HTTPS with Tailscale Serve

Enable MagicDNS and HTTPS certificates for the tailnet if needed. Choose a neutral machine name such as ha-lab before requesting a certificate. Certificate Transparency logs can reveal the machine's certificate name; a private service does not imply a secret hostname. Use the exact HTTPS address printed by Serve rather than inventing a public DNS record.

On the Droplet, start Tailscale Serve with the command below. The background flag persists the service across reboots. Serve terminates HTTPS and forwards to IPv4 loopback. Tailscale Funnel is a separate public-sharing feature. Do not enable it for this setup, and inspect its status to ensure an earlier experiment has not left public sharing active.

Adapt the companion home-assistant.json policy in the tailnet editor. Keep the operator TCP 22 grant and add TCP 443 for operators and selected residents. Replace all example identities with enrolled users. The policy tests require residents to reach 443 while denying them SSH and direct 8123 access. Remove overlapping broad allows, validate, save, and run the tests before inviting anyone.

Visit the printed HTTPS address from an allowed Tailscale client. Sign in with your Home Assistant account and toggle the harmless helper. A resident should have a separate non-administrator Home Assistant account. Tailscale network permission gets a user to the login page; Home Assistant authentication still decides what they can do after login.

Before continuing: Use the fresh tutorial Droplet and keep a tested recovery path. Read the preceding checkpoint before running.

Enable private HTTPSConnected Droplet
sudo tailscale serve --bg http://127.0.0.1:8123
Inspect Serve and public-sharing statusConnected Droplet
sudo tailscale serve status
sudo tailscale funnel status

Verify phone access and denied connections

Install Tailscale on your phone and sign in as an allowed resident. Turn off Wi-Fi to use cellular data, keep Tailscale connected, and open the private HTTPS URL. Enter that same address in the Home Assistant companion app. Confirm the helper changes state and reconnects after the app has been closed. This tests the network you actually plan to use away from home.

With Tailscale disconnected, the private address must stop working. With a separate enrolled user outside both allowed groups, HTTPS must fail. From a device outside the tailnet, test the Droplet's public IPv4 and assigned IPv6 addresses on TCP 22, 443 and 8123. None should establish a session. A Home Assistant login page on a public address is a failed test even if it asks for a password.

Reboot the Droplet and repeat the private HTTPS and public denial checks. If HTTPS returns a proxy error, check the backend listener, container logs and trusted-proxy address before changing firewall rules. If it works on Wi-Fi but not cellular, inspect the phone's VPN state and Tailscale connection. Record these outcomes before connecting real devices.

Confirm public 8123 is unreachableLocal terminal
Replace every highlighted value before running this command.
curl --connect-timeout 5 --max-time 10 http://PUBLIC_IP:8123/

Connect home devices only through a reviewed route

A cloud integration that calls a vendor API may work without a route into your home. A LAN-only device needs a reachable address, a compatible integration and a return path. A Tailscale subnet router on an always-on home device can advertise selected home addresses. Approve the route and grant only the Droplet tag access to the required device addresses and ports; Linux clients also need to accept the advertised routes.

Treat this as a separate networking project. Avoid overlapping home and cloud subnets. Configure integrations with explicit device IPs where supported rather than expecting multicast discovery to cross the VPN. USB, Bluetooth, Matter and Thread requirements do not disappear because IP routing works. Check each integration before choosing cloud hosting for it.

Test what happens when the home internet or subnet router goes down. Keep critical controls usable locally. A disconnected sensor should become unavailable rather than quietly leaving you dependent on stale data. If several essential integrations need complicated routing, move Home Assistant home and use Tailscale only for remote access.

Back up, rehearse a restore, then update

Enable Home Assistant multifactor authentication for the owner account and keep residents non-administrative. Create a backup in Settings > System > Backups, download it to storage outside the Droplet, and keep the backup emergency kit or encryption key separately. A backup that exists only under ./config disappears with the disk it is meant to protect.

Rehearse restoration on a separate isolated test instance before relying on it. Use a downloaded backup through the onboarding restore flow. Keep that test machine unable to reach real devices or vendor services so restored automations cannot run twice. Confirm the helper, dashboard and configuration survived, then destroy the test instance after recording the result.

Before an upgrade, take another backup and record the current image tag. Read the target release notes, change the image version in compose.yaml, then pull and recreate the container. Confirm the saved loopback setting, private URL and denied public access afterward. Retain the earlier backup because downgrading an image after a database migration may not undo the data changes.

Keep Ubuntu, Docker and Tailscale patched too. Review disk usage and backup downloads routinely. To retire the service, stop the container, verify your offline backup, remove the Serve mapping and tailnet node, and destroy the exact Droplet. This guide gives you a private route and a recoverable configuration; the live acceptance tests are what establish that your own deployment meets that design.

Can a Droplet use my Zigbee USB stick?

No direct USB connection exists between your home and the cloud VM. Use Home Assistant at home for local radios, or design a separately supported network gateway for a compatible integration. A Tailscale route by itself does not transport USB or provide Bluetooth discovery.

Should I open port 8123?

No public 8123 rule is needed here. Onboarding uses an SSH tunnel. Afterward the backend listens on 127.0.0.1 and Tailscale Serve provides the private HTTPS endpoint. Verify both public IP families and the tailnet policy instead of relying on the login screen as the network boundary.

Can family members use it without Tailscale?

Not through this private endpoint. Each remote device needs an authorized Tailscale connection and its own Home Assistant login. If installing a VPN client is unsuitable, evaluate a supported alternative such as Home Assistant Cloud with a local installation rather than enabling Funnel by accident.

Can I install Home Assistant apps on this server?

Home Assistant Container does not provide the apps managed by Supervisor. You can operate separate services yourself, but each needs its own maintenance and access controls. Home Assistant OS is usually the better choice when you want the integrated app experience.

Does private HTTPS replace Home Assistant passwords?

No. Tailscale grants control network reachability and Serve supplies HTTPS. Keep Home Assistant authentication, unique user accounts and owner multifactor authentication. A compromised allowed device can still reach the login page, and an application account must have only the permissions its user needs.

Check your result

Expected result
Allowed private connections work after reboot. Public and unauthorized connections fail.
Stop if
Stop if a public address or unauthorized user reaches the service. Restore the last working configuration through the recovery path.
Next step
Record a reboot and recovery test before connecting real workloads.