Privacy Tools Guide

Access Home Assistant remotely without port forwarding by using Tailscale’s mesh VPN to create encrypted peer-to-peer connections between your server and client devices. Tailscale assigns private IP addresses to your Home Assistant instance, making it accessible from anywhere while keeping your network completely private and invisible to the public internet. This guide walks through setting up Tailscale for remote access, targeting developers and power users who want enterprise-grade security without complexity.

Why Avoid Port Forwarding

Opening ports on your router directly exposes services to the internet. Even with strong passwords, port scans and automated attacks target known vulnerabilities. Home Assistant running on your local network should remain private—Tailscale creates an encrypted tunnel that keeps your smart home infrastructure invisible to the public internet while remaining accessible to authorized devices.

Understanding the Tailscale Architecture

Tailscale operates as a mesh VPN, creating direct encrypted connections between devices. Unlike traditional VPNs that route all traffic through a central server, Tailscale establishes peer-to-peer connections when possible, minimizing latency. Each device gets a unique Tailscale IP address (in the 100.x.x.x range), and your Home Assistant instance becomes reachable at that private IP from any device logged into your Tailscale network.

Installing Tailscale on Home Assistant

The easiest method uses the Home Assistant Operating System with the Tailscale add-on. Access your Home Assistant instance, navigate to Settings → Add-ons, and search for “Tailscale.” Install the official add-on and configure it with your Tailscale authentication key.

Configuration requires minimal settings:

 tailscale:
   api_key: your_authentication_key
   accept_dns: true
   accept_routes: true
   verbose: false

After starting the add-on, note the Tailscale IP address assigned to your Home Assistant instance—you’ll use this for connections.

Alternative: Tailscale on a Raspberry Pi or Docker

For Home Assistant installations running on generic Linux, install Tailscale directly. On Debian/Ubuntu systems:

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --accept-routes

Docker containers work similarly. Use the official Tailscale Docker image:

docker run -d \
  --name tailscale \
  --cap-add NET_ADMIN \
  --device /dev/net/tun \
  -e TS_AUTH_ONCE=true \
  -v /var/lib/tailscale:/var/lib/tailscale \
  -v /dev/net/tun:/dev/net/tun \
  tailscale/tailscale:latest \
  tailscale up --accept-routes

Setting Up Client Devices

Install Tailscale on devices you want to use for remote access—phones, laptops, tablets. The Tailscale client is available for macOS, Windows, Linux, iOS, and Android. Log in using the same Tailscale account that authenticated your Home Assistant device.

Your Tailscale network now contains your Home Assistant instance and all your client devices. Each device receives a private IP address visible only within your Tailscale network.

Accessing Home Assistant

With Tailscale running on both your Home Assistant server and client device, accessing your smart home is straightforward. Instead of your public IP address or domain name, use the Tailscale IP assigned to your Home Assistant instance.

The connection uses the format http://[tailscale-ip]:8123. For example, if your Home Assistant Tailscale IP is 100.64.123.456, access it at http://100.64.123.456:8123 from any device on your Tailscale network.

Configuring Home Assistant for Tailscale

For optimal experience, configure Home Assistant to recognize Tailscale connections properly. Update your configuration.yaml to ensure proper hostname handling:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 100.64.0.0/10

This allows Home Assistant to correctly identify client devices behind the Tailscale VPN, enabling proper IP-based automation triggers and logging.

Using Tailscale DNS for Convenience

Tailscale includes a DNS feature that assigns hostnames to devices. By default, your Home Assistant instance becomes accessible at homeassistant.tail-scale.tset.hot (your specific subdomain appears in the Tailscale admin console). Access Home Assistant at http://homeassistant.tail-scale.tset.hot:8123—much easier than memorizing IP addresses.

Enable this in your Tailscale admin panel or by using --accept-dns when running tailscale up.

Security Considerations

Tailscale provides several security layers worth understanding. All traffic between devices is encrypted using WireGuard protocol, providing modern cryptographic protection. Access control happens through your Tailscale account—only users you authorize can connect to your network.

Consider enabling two-factor authentication on your Tailscale account for additional protection. The key expiration feature allows you to set time limits on authentication keys, useful for temporary access scenarios.

Review the devices connected to your Tailscale network regularly through the admin console. Remove devices you no longer use or recognize.

Troubleshooting Common Issues

Connection problems typically stem from a few common causes. Verify both devices show as “Online” in the Tailscale admin console. Check that accept_routes is enabled on the Home Assistant Tailscale installation—this allows client devices to reach the Home Assistant network segment.

If peer-to-peer connection fails, Tailscale automatically falls back to relay servers (DERP), which may increase latency. This usually indicates firewall issues on one end. For best performance, ensure UDP ports 41641 are open on your network.

Advanced: Tailscale SSH and Emergency Access

Beyond web access, Tailscale enables secure SSH into your Home Assistant server. Configure tailscale ssh to access your device’s command line from anywhere—no need for traditional SSH keys or exposed SSH ports.

# Enable Tailscale SSH on Home Assistant
tailscale ssh core@<tailscale-ip> "ha core logs"

# For non-core environments
tailscale ssh username@<tailscale-ip> "systemctl status home-assistant"

# Key expiration setup for temporary access
tailscale key create \
  --reusable \
  --expiry 24h \
  --description "emergency-access-key"

For scenarios requiring access without the Tailscale client, consider the Tailscale web proxy feature, which generates temporary URLs accessible through any browser:

# Generate a temporary web access URL (valid 24 hours)
tailscale web
# URL appears in admin console under "Web Proxy"

This is useful for one-off access on devices where installing Tailscale isn’t practical.

Advanced: Multi-Network Federation

Connect multiple Tailscale networks for large deployments:

# If managing multiple properties, use org-level administration
# Primary network: home.tailscale.com
# Secondary network: vacation-home.tailscale.com

# Failover configuration
tailscale set --accept-dns=true --accept-routes=true
# Enables automatic failover between relay endpoints

Threat Model and Security Analysis

Scenario Threat Level Tailscale Mitigation Additional Controls
Public Wi-Fi access MEDIUM Encrypted tunnel MFA on Tailscale account
Lost device access MEDIUM Device revocation IP-based ACLs
Compromised device HIGH Immediate removal Regular key rotation
Inside adversary LOW-MEDIUM Encrypted traffic Network segmentation
ISP surveillance LOW Hidden traffic patterns Additional VPN layer optional

Configuring Access Control Lists (ACLs)

Tailor network access with granular policies:

// tailscale-acl.hcl - Access control policy
// Home Assistant automation setup

acls = [
  // Allow all devices to reach Home Assistant HTTP
  {
    action = "accept"
    src    = ["tag:mobile", "tag:desktop", "tag:home"]
    dst    = ["homeassistant:8123"]
  },

  // Restrict SSH access to desktop only
  {
    action = "accept"
    src    = ["tag:desktop"]
    dst    = ["homeassistant:22"]
  },

  // Block unexpected access patterns
  {
    action = "reject"
    src    = ["*"]
    dst    = ["homeassistant:*"]
  },
]

hosts = {
  homeassistant = "100.64.123.456"
}

tagOwners = {
  "tag:mobile" = ["autogroup:members"]
  "tag:desktop" = ["user@example.com"]
  "tag:home" = ["homeassistant"]
}

Deploy and test:

# Validate ACL syntax
curl -X POST \
  https://api.tailscale.com/api/v2/tailnet/example.com/check \
  -H "Authorization: Bearer $(cat ~/.tailscale-token)" \
  -H "Content-Type: application/json" \
  -d @tailscale-acl.hcl

# Apply ACL policy
curl -X POST \
  https://api.tailscale.com/api/v2/tailnet/example.com/acl \
  -H "Authorization: Bearer $(cat ~/.tailscale-token)" \
  --data @tailscale-acl.hcl

Performance Optimization and Monitoring

Monitor Tailscale connection quality:

# Check connection status and relay information
tailscale status --json | jq '.Peer[] | {name: .HostName, relay: .Relay, latency: .Latency}'

# Monitor bandwidth usage
tailscale bugreport | grep -A 20 "Bandwidth"

# Test latency to relay servers
ping -c 4 $(tailscale status --json | jq -r '.Self.Relay')

# Optimize for specific use cases
# For Home Assistant automations requiring low latency:
tailscale up --accept-routes --mangle-default-route=false

Automated Home Assistant Monitoring via Tailscale

Create a monitoring script that uses Tailscale to check Home Assistant remotely:

#!/usr/bin/env python3
import json
import subprocess
import requests
from datetime import datetime

def get_tailscale_status():
    """Get current Tailscale status"""
    result = subprocess.run(['tailscale', 'status', '--json'],
                          capture_output=True, text=True)
    return json.loads(result.stdout)

def check_home_assistant(ha_ip, ha_token):
    """Check Home Assistant availability and basic stats"""
    headers = {"Authorization": f"Bearer {ha_token}"}

    try:
        response = requests.get(
            f"http://{ha_ip}:8123/api/",
            headers=headers,
            timeout=5
        )

        if response.status_code == 200:
            return {
                "status": "healthy",
                "timestamp": datetime.now().isoformat()
            }
    except requests.RequestException as e:
        return {
            "status": "error",
            "error": str(e),
            "timestamp": datetime.now().isoformat()
        }

def main():
    # Configuration
    HA_IP = "100.64.123.456"  # Tailscale IP
    HA_TOKEN = "eyJhbGc..."  # Long-lived token from Home Assistant

    # Get Tailscale status
    ts_status = get_tailscale_status()
    ha_status = check_home_assistant(HA_IP, HA_TOKEN)

    # Log results
    print(f"Tailscale Status: {ts_status['Self']['Online']}")
    print(f"Home Assistant: {ha_status['status']}")

    # Send alert if unhealthy
    if ha_status['status'] == 'error':
        send_alert(f"Home Assistant unreachable: {ha_status['error']}")

if __name__ == "__main__":
    main()

Integration with Home Assistant Automations

Create automations that use Tailscale connectivity:

# automations.yaml - Example automations

- id: "monitor_tailscale_connectivity"
  alias: "Monitor Tailscale Network Status"
  trigger:
    platform: state
    entity_id: "binary_sensor.tailscale_online"
    to: "off"
  action:
    service: notify.mobile_app
    data:
      message: "Tailscale connection lost - remote access unavailable"
      title: "Network Alert"

- id: "remote_restart_ha"
  alias: "Emergency Restart via Tailscale"
  trigger:
    platform: template
    value_template: "{{ states('sensor.uptime_days') | float > 30 }}"
  action:
    service: homeassistant.restart

- id: "geo_location_trigger"
  alias: "Enable Automations When Away (Tailscale Verified)"
  trigger:
    platform: state
    entity_id: "person.user"
    to: "away"
  action:
    - service: input_boolean.turn_on
      entity_id: "input_boolean.away_mode"

Database-Level Logging

Store Tailscale connection logs in Home Assistant for forensics:

# Export Tailscale device logs to Home Assistant database
tailscale devices --json | jq '.[] | {hostname: .HostName, ip: .Addresses, os: .OS, lastSeen: .LastSeen}' >> /var/lib/home-assistant/tailscale_devices.json

# Set up cron job for hourly snapshots
0 * * * * tailscale devices --json > /var/lib/home-assistant/tailscale_status_$(date +\%Y\%m\%d_\%H\%M\%S).json

Advanced: Tailscale SSH with MFA

Enhance SSH security with multi-factor authentication:

# Enable Tailscale SSH and require MFA
tailscale ssh --accept-risk-idp-device-trust user@homeassistant

# Configure SSH certificates for Home Assistant
# Add to /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/tailscale-ca.pub
AuthorizedKeysCommand /usr/bin/tailscale-ssh-ca %u

Troubleshooting Connection Quality

Common issues and diagnostic commands:

# Test if peer-to-peer connection is established
tailscale ping -verbose homeassistant.tail-scale.tset.hot | grep -E "via|direct"

# If relay connection, investigate why:
# 1. Check firewall rules (UDP port 41641 should be open)
sudo ufw allow 41641/udp

# 2. Check NAT type
tailscale debug deeplink | grep -i nat

# 3. Force specific relay endpoint
tailscale set --derp-region=sfo

# 4. Monitor STUN requests
sudo tcpdump -i any 'udp port 3478 or udp port 5349' -n

Built by theluckystrike — More at zovo.one