Why Run Your Own Tailscale Control Server?
Tailscale makes private networking genuinely simple – connect devices across the internet as if they share a local network, no port forwarding required, no complex VPN configurations to maintain. Under the hood, it uses WireGuard for the actual tunneling, but Tailscale’s coordination server handles key exchange, device authentication, and routing decisions. That coordination layer is what Headscale replaces.
Headscale is an open-source, self-hosted implementation of the Tailscale control server. Running it means your device list, authentication tokens, and network topology data never touch Tailscale’s infrastructure. For anyone managing a homelab, running services for a small team, or simply preferring not to depend on a third-party SaaS product for core networking, Headscale offers a clean alternative. The official Tailscale clients – on Linux, macOS, Windows, iOS, and Android – work with Headscale without modification.
This guide walks through deploying Headscale on a Linux server, connecting clients, and handling the small configuration details that trip up most first-time setups.

Server Requirements and Installation
Headscale runs on any Linux server with a public IP address. That public IP is non-negotiable – your clients need to reach the control server from the internet, so a home server behind a residential NAT will require either port forwarding or a small cloud VPS. A $5-6/month VPS from any major provider works fine. You will also need a domain name pointing to that server, since Headscale expects to serve over HTTPS and clients verify the server address by hostname. Make sure port 443 (HTTPS) and port 3478 (STUN, for NAT traversal) are open in your firewall.
Download the latest Headscale binary from the official GitHub releases page at github.com/juanfont/headscale. Choose the architecture matching your server – typically amd64 for standard VPS instances. Install it to /usr/local/bin/headscale and make it executable with chmod +x /usr/local/bin/headscale. Create the required directories and a dedicated system user:
- useradd –system –create-home –home-dir /var/lib/headscale headscale
- mkdir -p /etc/headscale /var/lib/headscale /var/run/headscale
- chown -R headscale:headscale /var/lib/headscale /var/run/headscale
Grab the example configuration file from the repository and place it at /etc/headscale/config.yaml. Open it and set four critical values immediately: server_url (your full HTTPS domain, like https://hs.yourdomain.com), listen_addr (set to 0.0.0.0:8080 if you are placing a reverse proxy in front, or 0.0.0.0:443 for direct TLS), ip_prefixes (the subnet Headscale assigns to your devices – the default 100.64.0.0/10 matches Tailscale’s range and works well), and db_path pointing to /var/lib/headscale/db.sqlite. If you are running a reverse proxy like Traefik already, keeping Headscale on port 8080 and letting the proxy handle TLS is the cleaner setup.
TLS, systemd, and First Launch
Headscale can manage its own TLS certificates via Let’s Encrypt, or it can operate behind a reverse proxy that handles certificates externally. For the built-in approach, set tls_letsencrypt_hostname in the config to your domain and set tls_letsencrypt_listen to :http so the ACME challenge can complete on port 80. Make sure port 80 is open during initial setup. If you are using an external proxy, leave those fields empty and set tls_cert_path and tls_key_path to empty strings – Headscale will serve plain HTTP internally and trust the proxy for encryption.
Create a systemd service file at /etc/systemd/system/headscale.service with the following content:
- [Unit] – Description=Headscale Control Server, After=network.target
- [Service] – User=headscale, ExecStart=/usr/local/bin/headscale serve, Restart=always
- [Install] – WantedBy=multi-user.target
Run systemctl daemon-reload, then systemctl enable –now headscale. Check that the service started cleanly with journalctl -u headscale -f. If you see certificate errors, verify your domain’s DNS A record has propagated and that port 80 is reachable. If the database file fails to open, check directory ownership. A clean startup log ends with something like “Headscale listening on 0.0.0.0:443” – at that point the control server is live.

Creating Users and Registering Clients
Headscale organizes devices into namespaces called “users” – each user is a logical group, similar to how Tailscale accounts separate devices. Create your first user with headscale users create mynetwork. You can create as many users as your setup needs; for a homelab, one user covering all your personal devices is usually enough.
On each client machine, install the standard Tailscale client for that operating system – official Tailscale packages work without any modification. Do not log in through the normal Tailscale app flow. Instead, run the following command on the client:
- tailscale up –login-server=https://hs.yourdomain.com –accept-routes
The client will output a registration URL. Copy that URL and run it on the Headscale server: headscale nodes register –user mynetwork –key [the key from the URL]. The node is now registered. Run headscale nodes list to confirm it appears with a valid IP from your configured prefix. For mobile clients or any situation where typing a registration command on the server is inconvenient, Headscale supports pre-auth keys – generate one with headscale preauthkeys create –user mynetwork –reusable –expiration 24h, then pass it to the client with tailscale up –login-server=https://hs.yourdomain.com –authkey=[key].

Running a Stable Self-Hosted Network
Once your first two or three nodes are connected, verify connectivity by pinging between their Headscale-assigned IPs. If pings succeed but traffic is slow, check whether direct WireGuard connections established by running tailscale status on a client – look for “direct” rather than “relay” in the connection type. STUN on port 3478 handles this negotiation, so if most connections fall back to relay, that port is likely blocked on your server’s firewall. Keep the Headscale binary updated by periodically checking the GitHub releases page; the project moves quickly and older versions occasionally lose compatibility with newer Tailscale clients. Headscale’s SQLite database is lightweight enough that a simple daily backup of /var/lib/headscale/db.sqlite gives you full recovery capability – losing that file means re-registering every node from scratch.
Frequently Asked Questions
Does Headscale work with the official Tailscale apps?
Yes. The standard Tailscale clients on all platforms connect to Headscale without any modification – just point them to your server URL at login.
Do I need a public IP address to run Headscale?
Yes. Your clients connect to the Headscale control server over the internet, so it must be reachable at a public IP, typically via a VPS with a domain name.





