I like Tailscale because it solves a messy problem in a very clean way. You install the client, sign in, and suddenly remote access, private DNS, and cross-network connectivity feel much easier than they should.
What pushed me toward Headscale was wanting more control over the coordination layer. If the rest of the stack is already self-hosted, it makes sense to bring the tailnet control plane in-house too.
Why I Wanted Headscale
Tailscale is one of the best tools I have used for private networking. It takes the rough edges off WireGuard, handles peer discovery well, and makes features like exit nodes practical enough to use all the time.
The one part I eventually wanted to own myself was the control plane. In a homelab or self-managed environment, it starts to feel a little strange to run your own DNS, reverse proxy, storage, and monitoring, but still depend on an outside service for the piece that coordinates your private network.
Headscale solves that problem neatly. It gives you a self-hosted control server while still letting you use the normal Tailscale clients, so the user experience stays familiar even though the backend is now yours.
How I Deployed It
The model that made the most sense for me was simple: put Headscale on a VPS, give it a public DNS name, and place it behind a reverse proxy with TLS. That keeps the design small and easy to reason about.
In practice, the stack looks like this:
- A Linux VPS for the control plane.
- Headscale for node registration, users, and policy.
- A web UI for approvals and quick administration.
- A reverse proxy such as Traefik for HTTPS and certificate handling.
- A public DNS record pointed at the VPS.
Once that is online, the rest is pretty straightforward. The client still uses the standard Tailscale software, but instead of authenticating against the hosted control plane, it talks to your own Headscale server.
Why This Setup Works
What I like about this combination is that it keeps the parts of Tailscale that matter most to me: easy clients, reliable connectivity, and a simple day-to-day workflow. At the same time, it moves control of the network definition, approvals, and policy back into infrastructure I manage.
That balance makes it a good fit for a homelab, a small VPS footprint, or really any environment where self-hosting is already the default mindset. It does not feel like replacing a polished tool with a science project; it feels like moving one layer of the stack back under your control.
Joining Devices
One reason this is so easy to live with is that client enrollment barely changes. You still install Tailscale on the device, but you point it at your own login server instead of the hosted service.
#bashtailscale up --login-server=https://headscale.example.com
From there, you approve the registration request in the Headscale UI or from the CLI, and the node joins the tailnet. That is one of the nicest parts of the whole setup: the workflow is different enough to be self-hosted, but not different enough to become annoying.
Using the VPS as an Exit Node
Once the control plane was working, the next logical step was using the VPS as an exit node. That gives remote devices a stable egress path and makes it easy to route traffic through infrastructure I already trust.
That is useful for a few reasons. It gives you a known public IP, helps when working from restrictive networks, and lets you keep outbound traffic anchored to a VPS instead of whatever network you happen to be sitting on that day.
The operational side is simple: enable forwarding, advertise exit-node capability, and then approve the default routes.
#bashsudo tee /etc/sysctl.d/99-tailscale.conf <<'CONF_EOF'
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
CONF_EOF
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf
sudo tailscale up \
--login-server=https://headscale.example.com \
--advertise-exit-node
After that, other devices on the tailnet can select the VPS as their exit node and push internet traffic through it. That turns the VPS into something more than just a control server; it becomes part of the network’s everyday utility.
Thanks to ServersatHome for the idea behind this.