I didn't really understand the Tailscale hype until I tried it. Installed the client, authenticated it, and let the cloud handle the rest. It's a genuinely great product, but every device I put on my tailnet needs to check in with someone else's server to figure out how to talk to my other devices.
The traffic stays peer-to-peer, sure, but the coordination layer — the part that knows which devices exist, when they connect, and how they find each other — lives outside my control. That is, until I tried Headscale, and now I finally own my entire tailnet.
The server behind your tailnet
Headscale replaces Tailscale's control plane while keeping the same secure mesh networking model
Tailscale's magic depends on a coordination server that handles device registration, key exchange, and network topology, even though it never touches your actual traffic, which flows directly between devices over WireGuard. Headscale is a drop-in replacement for that piece, designed for a single tailnet, making it ideal for personal setups, homelabs, and small teams rather than larger, enterprise deployments.
The drop-in replacement bit is what makes Headscale easy to recommend over other self-hosted or reverse proxy alternatives. You don't have to give up the official Tailscale client on any of your devices. You just point them at your own server instead of Tailscale's, and nothing changes from the client's perspective.
Self-hosting it takes surprisingly little effort
With Docker and a few configuration steps, you can have your own control server up and running in minutes
Headscale requires certain prerequisites before you can get to work. You need a small VPS with a public IP, a domain name pointed at it for HTTPS via Let's Encrypt, and Docker ready to go. I wanted to use my Linux home server instead of a VPS, so I tried using a domain name I owned and setting up Cloudflared — one of the several Docker containers that make my home server worth the effort. Unfortunately, Headscale doesn't support running behind a Cloudflare tunnel, so that route is dead. Getting a cheap VPS or even a free-tier VPS from Oracle Cloud works.
From there, getting Headscale running is just a Docker Compose file: pull the image using docker pull headscale/headscale:latest, drop in a YAML configuration with your server's address and where to store its database, and bring the container up. Optional single sign-on lives in that same file if you want it. The ACL policy format mirrors Tailscale's own syntax, which means existing Tailscale documentation on access rules still applies almost verbatim.
Once the server was live, I created a user and a short-lived pre-authentication key from the command line, then pointed each device's Tailscale client at my own server address instead of Tailscale's, with one extra flag on login:
tailscale up --login-server=https://yourdomain.com --authkey=Everything else — authenticating, joining the tailnet — worked exactly like it always had
I wanted full control over my network
Self-hosting means managing my own devices, authentication, and infrastructure instead of relying on a third party
It's not that I distrust Tailscale, but I switched because of three main reasons. The first was data sovereignty. Even without seeing my traffic, Tailscale's servers still know which devices are on my network and when they connect. For a homelabber who obsesses over owning every layer of his stack, that metadata felt like a loose thread.
The second reason was offline resilience. If Tailscale's cloud has an outage, existing connections survive, but you can't add devices or push configuration changes until service resumes. Running my own control plane means uptime is entirely on me, for better or worse.
Finally, I was just curious to understand how mesh networking actually works under the hood instead of trusting an admittedly well-functioning black box. Self-hosting the control server forces you to learn the mechanics of device registration, key exchange, and ACL policy firsthand.
Freedom comes with a few trade-offs
Headscale offers greater ownership, but you'll miss some of Tailscale's polished cloud features and integrations
Headscale covers just about everything you need to get up and running. Device registration and authentication, MAgic DNS for readable hostnames, ACL support, OIDC for SSO, subnet routing, exit nodes, and pre-authentication keys for headless devices like Raspberry Pis. That's not a short list of features, and depending on your use case, might be all you need.
However, what you do miss out on are features like Tailscale Funnel and Serve, which let you expose services publicly or reverse-proxy them over HTTPS. There's no official web UI, although community projects like Headscale-UI somewhat fill that gap. If your homelab depends on these newer features, I'd recommend sticking to Tailscale for the time being.
My tailnet is finally mine
Headscale gave me the control I wanted without sacrificing the simplicity that made me choose Tailscale in the first place
For a homelab where privacy matters and I'd rather debug my own infrastructure rather than file a support ticket, Headscale checks every box. All I need it to do is expose my local services like Home Assistant safely to the internet, and it does that job reasonably well. It's also a good fit for air-gapped setups, learning projects, and small teams that don't want any external dependency in their networking stack.
If you need Tailscale's managed exit nodes, official SLAs, or features Headscale hasn't caught up on yet, staying with Tailscale makes sense, and you can even run the two in parallel to experiment and decide for yourself. For me, though, owning the control plane turned out to be a great learning exercise while giving me even more control of my data and devices.