Self-Hosting Tailscale: Building Your Own Private VPN Mesh With Headscale
Every Linux user who has ever tried to reach a Raspberry Pi tucked behind a consumer router knows the ritual. Open a port, set up dynamic DNS, hope the ISP doesn't change the address at the worst possible moment. Or run a VPN server and maintain its configuration by hand. WireGuard made the cryptography painless, but the real work was never the keys — it was managing a network of machines that move around, change networks, and need to reach each other securely from anywhere.
Tailscale solved that problem by wrapping WireGuard in a coordination service that handles discovery, authentication, and NAT traversal automatically. The catch, for a certain kind of user, is that the coordination service lives in someone else's cloud. Headscale changes that equation: it is an open source, self-hosted implementation of the Tailscale control server, and it works with the existing Tailscale clients almost unchanged.
For hobbyists who want full control, for teams that need more than the free tier allows, or for anyone who simply prefers not to run infrastructure on other people's hardware, Headscale offers a way to have the Tailscale experience without the Tailscale cloud.
Why the Free Tier Isn't Always Enough
To be fair to Tailscale, its free tier is genuinely good — and it recently became more generous, now allowing unlimited nodes and up to six users. For most hackers and small teams, that is plenty. The service handles NAT traversal, assigns each node a 100.x.x.x address, and provides convenient DNS names through MagicDNS.
But "plenty for most" is not the same as "right for everyone." The free tier still leaves some users wanting more:
- You need a seventh user, or more than six accounts.
- You want features that sit behind the paywall.
- You don't want your network metadata flowing through a third-party coordination server.
- You've seen what happens when a generous free tier gets less generous, and you'd rather not depend on it.
The last point is the one that resonates most in the self-hosting community. Free tiers are gifts that can be revised, and the only way to make sure the gift isn't revoked is to stop needing it. That is precisely the niche Headscale fills.
What Is Headscale?
Headscale is an open source, self-hosted implementation of the Tailscale control server, aimed primarily at self-hosters and hobbyists. It reproduces the essential functionality of the cloud coordination layer: nodes authenticate against your server instead of Tailscale's, and the clients handle the actual WireGuard tunnels as they always have.
The elegant part is the client side. Headscale works seamlessly with the existing Tailscale clients — you simply point them at your server instead of the defaults. There is no custom client to compile, no fork to maintain, and no divergence from the upstream WireGuard implementation. If you've used Tailscale, the transition is mostly invisible.
Technical Analysis: How the Pieces Fit Together
Understanding Headscale requires separating the two halves of the Tailscale architecture, which people often blur together.
The Control Plane
The coordination server is the brain of the network. It tracks which nodes belong to which user, distributes public keys, and tells peers how to reach each other. This is the part that lives in the cloud for normal Tailscale users — and the part Headscale replaces. It is also where features like MagicDNS, ACLs, tags, and exit-node configuration are defined.
The Data Plane
The actual encrypted tunnels are pure WireGuard, running between peers. Once two nodes know how to reach each other, traffic flows directly between them — the coordination server is not in the data path. This is why a self-hosted control server does not become a bottleneck for your traffic: it handles the introductions, not the packets.
Headscale supports the features most self-hosters actually use: MagicDNS, IPv4 and IPv6, subnet routers, exit nodes, tags, ACLs, Tailscale SSH, and file sharing. It does not reproduce every commercial Tailscale feature, so anyone depending on something exotic should check the compatibility list before committing.
The DERP Layer
Not every pair of nodes can connect directly. Some networks are behind strict NATs, some firewalls block the UDP ports WireGuard prefers. For those cases, Tailscale uses DERP servers — relay servers that forward encrypted packets between peers that cannot establish a direct connection.
By default, Headscale installations use the public DERP servers operated by Tailscale. That sounds contradictory for a self-hosting project, but it is less concerning than it appears: DERP relays only handle encrypted packets they cannot read. Still, the option exists to run your own DERP server, and the status output makes it easy to tell which path a connection is using. A line like direct 158.61.222.64:41641 means your computer and the remote node are connected directly, with no relay involved at all.
Running your own DERP server is a judgment call. If your cheap VPS sits halfway around the world from your other machines, every relayed packet pays a latency penalty. For most people, starting with the public relays is the sensible move — they are free, they are encrypted end-to-end, and you can always change course later.
Getting Started: Installing Headscale
The official documentation expects a Linux or BSD server with a public IP address, and recommends making Headscale available over HTTPS on port 443. A small VPS is ideal; alternatively, Headscale can sit behind a reverse proxy such as Apache, nginx, or Caddy on a server you already run.
There is one configuration wrinkle to know about up front: the Tailscale control protocol uses a somewhat unusual WebSocket upgrade, so not every arbitrary HTTP proxy configuration will work. The Headscale documentation provides working configurations for the usual suspects, so check those before fighting your reverse proxy.
On Debian or Ubuntu, installation is refreshingly simple. Official packages provide a dedicated user account, a default configuration, and a systemd unit. A basic installation uses SQLite, so there is no heavyweight database to administer. The file you will spend the most time with is:
/etc/headscale/config.yaml
Creating your first user is a single command:
headscale users create hackaday
Connecting a Linux client is equally direct. Point the Tailscale client at your server and authenticate:
tailscale up --login-server https://your-server-url
Authentication works a little differently than the hosted service. Instead of a password prompt, you will get a command to run on the server to authorize the node. There are also options for pre-shared keys and for single sign-on with providers like Google, which makes multi-user deployments considerably more pleasant.
Even the Android client can use an alternative server, although the option is well hidden: in the accounts page, open the three-dot menu to reveal "use alternative server."
Headplane: A Web Interface for the CLI-Averse
Headscale is unapologetically server software. Administration happens through configuration files and the headscale command, which suits many self-hosters perfectly — but it is a far cry from the polished Tailscale web dashboard.
Headplane closes that gap. It is a separate open source project that provides a web administration interface for Headscale, capable of managing machines, routes, users, ACLs, tags, DNS settings, and the rest of the network. It supports OpenID Connect for authentication and can even provide browser-based SSH access to nodes on your mesh.
The typical deployment runs Headplane in a container. It talks to Headscale using an API key generated during setup, and the two are usually deployed together. If you have used the official Tailscale admin interface, Headplane makes a self-hosted installation feel familiar — which is exactly the point. As with anything exposed on a network, you will want to secure the interface behind HTTPS or keep it reachable only from inside the Headscale mesh itself.
Practical Lessons: The Sensible Upgrade Path
One of the strengths of the Hackaday write-up on this subject is that it proposes a sane path for people who want to experiment without overcommitting:
- Try Tailscale first. Get a free account and use it for a while. If the free tier serves you, you are done — there is no shame in using the hosted service.
- Move to Headscale when you feel the limits. Set up a public server, install Headscale, and administer it from the command line until the network is stable.
- Add Headplane if you miss a dashboard. It makes day-to-day administration considerably easier without requiring you to abandon the CLI.
- Graduate to SSO and your own DERP servers once the basics are boring. That is where the real customization begins.
This ordering matters because it lets you isolate variables. If something breaks after switching to Headscale, you know the control plane is the new piece. If you then add Headplane and something breaks, you know exactly where to look. Incremental migration beats a big-bang rewrite every time.
The Bigger Lesson
Headscale is a textbook example of what Linux has always done best. Start with an application that hides a complicated technology behind an easy interface. Pull back one layer and discover that the complicated part is actually composed of several understandable pieces. Then replace one of those pieces with an open source implementation.
The result is a network that gives you the convenience of Tailscale and the sovereignty of self-hosting: your own coordination server, your own DNS, your own access policies, and no dependency on a free tier that could change tomorrow. The WireGuard tunnels remain the same battle-tested technology either way.
For anyone who has ever wanted the magic of Tailscale without the cloud attached, Headscale is the answer — and the barrier to entry has never been lower. A small VPS, a config file, and one command are all it takes to become your own VPN provider.
