Install Headscale VPN on VPS Instead of Tailscale

Install Headscale VPN on VPS Instead of Tailscale

June 2026 · 9 min read

Headscale is an open-source implementation of the Tailscale control server that lets you run a mesh VPN privately using any Tailscale client app (iOS, Android, Mac, Windows, Linux), but with your control plane hosted on your own VPS instead of Tailscale's cloud infrastructure. This means all routing data and network information stays under your complete control.

Install Headscale on Your VPS

# Download headscale binary
HEADSCALE_VERSION=$(curl -s https://api.github.com/repos/juanfont/headscale/releases/latest | grep tag_name | cut -d'"' -f4)
wget "https://github.com/juanfont/headscale/releases/download/${HEADSCALE_VERSION}/headscale_linux_amd64"
sudo mv headscale_linux_amd64 /usr/local/bin/headscale
sudo chmod +x /usr/local/bin/headscale

# Or install using Docker:
mkdir -p ~/headscale/config ~/headscale/data

Create Configuration File

sudo mkdir -p /etc/headscale
sudo nano /etc/headscale/config.yaml
server_url: https://hs.yourdomain.com
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 0.0.0.0:50443
grpc_allow_insecure: false

private_key_path: /var/lib/headscale/private.key
noise:
  private_key_path: /var/lib/headscale/noise_private.key

ip_prefixes:
  - 100.64.0.0/10

derp:
  server:
    enabled: false
  urls:
    - https://controlplane.tailscale.com/derpmap/default

disable_check_updates: false
ephemeral_node_inactivity_timeout: 30m

db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite

tls_letsencrypt_hostname: hs.yourdomain.com
tls_letsencrypt_cache_dir: /var/lib/headscale/cache

log:
  level: info

Set Up systemd Service

sudo useradd -m -d /var/lib/headscale -s /usr/sbin/nologin headscale
sudo mkdir -p /var/lib/headscale
sudo chown headscale:headscale /var/lib/headscale

sudo nano /etc/systemd/system/headscale.service
[Unit]
Description=headscale controller
After=network.target

[Service]
Type=simple
User=headscale
Group=headscale
ExecStart=/usr/local/bin/headscale serve
Restart=unless-stopped
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now headscale

Create Users and Preauthentication Keys

# Create a namespace/user
sudo headscale users create myteam

# Generate preauthentication key for new devices
sudo headscale preauthkeys create --user myteam --reusable --expiration 24h

# View created keys
sudo headscale preauthkeys list --user myteam

Add Devices Using Tailscale Client

# On Linux device:
curl -fsSL https://tailscale.com/install.sh | sh

# Connect to Headscale instead of Tailscale cloud
sudo tailscale up --login-server https://hs.yourdomain.com --authkey PREAUTH_KEY_HERE

# View nodes in Headscale
sudo headscale nodes list
Tip: Headscale supports Exit Node functionality, allowing you to route all traffic through your VPS. Set --advertise-exit-node on the VPS you want to act as exit node, then approve it in the headscale CLI.

Your VPS running Headscale should have low latency to most devices in your network. For teams in Thailand and Southeast Asia, Singapore VPS from asiagb.com provides low latency across the region and is ideal for hosting your Headscale control server. Before deployment, verify your DNS and port configuration using dnsxray.com to ensure your domain points correctly and port 443 is open.


Verify Headscale is Working Correctly

# Check service status
sudo systemctl status headscale

# List connected nodes
sudo headscale nodes list

# View network routes
sudo headscale routes list

# Test connectivity between nodes
# From one node, ping another using Tailscale IP
ping 100.64.0.2
Tip: Run tailscale status on all devices to verify all peers are connected correctly, and use tailscale ping PEER_IP to test connectivity between devices.

Common Issues & Troubleshooting

Device Cannot Connect to Headscale

Verify DNS resolution for hs.yourdomain.com and ensure port 443 is open. Check Headscale logs for errors:

sudo journalctl -u headscale -f
# Look for TLS or connection refused errors

SSL Certificate Fails to Issue (LetsEncrypt Error)

Port 80 must be open for ACME challenges, or use DNS challenge instead:

sudo ufw allow 80
sudo systemctl restart headscale

Nodes Cannot Ping Each Other Even After Connecting

This may be due to DERP server configuration. Try enabling the built-in DERP server:

# In /etc/headscale/config.yaml
derp:
  server:
    enabled: true
    region_id: 999
    region_code: "headscale"
    region_name: "Headscale Embedded DERP"
    stun_listen_addr: "0.0.0.0:3478"

Preauthentication Key Expired

Preauthentication keys have a limited lifetime and must be regenerated periodically:

sudo headscale preauthkeys create --user myteam --reusable --expiration 7d

Frequently Asked Questions

How does Headscale differ from raw WireGuard?

WireGuard is a low-level VPN protocol that requires manual configuration of every peer. Headscale/Tailscale uses WireGuard as the underlying transport layer but automates key exchange and routing through a control plane. Adding new devices is significantly simpler and doesn't require manual configuration of each connection.

Does Headscale support iOS and Android?

Yes. Use the official Tailscale app on iOS and Android, then go to Settings, change the coordination server to your Headscale URL, and log in with your preauthentication key.

Is Headscale free? Are there device limits?

Headscale is 100% open-source with no cost and no device limits, unlike Tailscale's Free tier which limits devices to 100 and restricts certain features behind a paywall.