Headscale
Open-source self-hosted Tailscale control server
Headscale is an open-source, self-hosted implementation of the Tailscale control server. It lets you run your own coordination server while using official Tailscale clients.
Headscale setup guides & articles
Hands-on coverage of Headscale from the blog.
Key features
- Self-hosted Tailscale coordination
- Works with official clients
- Single binary server
- ACL support
Pros & cons
Strengths
- Full control of coordination
- Lightweight
Trade-offs
- No official GUI
Headscale replaces
Last reviewed Aug 25, 2026 · 722 words
Headscale makes your Tailscale network fully yours: a single Go binary reimplements the coordination server — the piece that authenticates devices and distributes keys — while every phone and laptop keeps running the official open-source Tailscale clients, just pointed at your URL. No device caps, no user tiers, no third party holding your network map. The deal, stated plainly up front: you are now operating the most security-critical service you own, and this guide is as much about that responsibility as about the (genuinely easy) setup.
Deploy: small server, public HTTPS, one config
Headscale wants a small always-on Linux box with a public HTTPS endpoint — a $5 VPS is the canonical home, since clients must reach it from anywhere. The container plus a config.yaml covers it: set server_url to your public https://headscale.example.com, leave SQLite as the database (correct at this scale), and put Caddy in front for TLS with websocket pass-through. RAM ~128 MB. Two config decisions worth making day one: enable MagicDNS with a base_domain so nodes get names, and decide your DERP posture (below). Then create a user and enroll each device by running the official client with --login-server https://headscale.example.com — desktop and CLI clients take the flag directly; iOS and Android accept an alternate server in the app settings. Pre-auth keys (headscale preauthkeys create) enroll servers non-interactively, which is how your containers and boxes join without ceremony.
The pieces you're now responsible for
- The database is your network.
/var/lib/headscale(SQLite) holds every node registration; lose it and every device re-enrolls by hand. It goes in the nightly backup, and the restore gets tested like anything else that matters. - Updates are security events. A coordination-server vulnerability is a network-wide problem; watch Headscale releases (it tracks a moving upstream, so client/server version drift occasionally breaks features first) and patch deliberately rather than automatically.
- The admin surface is the crown jewels. The
headscaleCLI on the server and the gRPC API can mint pre-auth keys — i.e., add devices to your network. Keep the API loopback-only unless you consciously need remote admin; if you add one of the community web UIs, treat its authentication as seriously as the threat model demands, because "admin panel for adding devices to my VPN" is not a thing to put behind a weak password.
DERP: borrow Tailscale's relays or run your own
When NAT traversal fails, traffic falls back to DERP relays. Headscale defaults to using Tailscale's public DERP fleet — encrypted ciphertext only, but a dependency on the company you were routing around. Your call: leaving it is pragmatic (their relay network is global and excellent), while derp.server.enabled: true runs Headscale's embedded DERP for full independence — at the cost of your VPS relaying those sessions' bandwidth, the same arithmetic as a RustDesk relay. Most self-hosters sensibly start on the public relays and revisit if principle or traffic patterns demand.
ACLs: the same policy engine, in a file you own
Headscale implements Tailscale's ACL policy format — JSON (HuJSON) defining who reaches what, with tags for servers and groups for people. Write it early, exactly as the Tailscale guide argues: a flat everything-reaches-everything network is fine at five devices and a liability at twenty-five. The file lives on your server (policy.path), versions in git, and reloads without restarts — config-as-code for your network's firewall, which is precisely the sort of thing that makes the self-hosted control plane worth its keep. Subnet routers and exit nodes work as upstream: advertise from the client, approve with headscale routes.
What I'd do
Headscale on a dedicated small VPS with Caddy, SQLite backed up nightly and restore-tested, MagicDNS on, public DERP accepted initially, ACLs in git from device ten, API loopback-only with no web UI, releases watched and patched within the week. And a candor note this directory owes you: hosted Tailscale with tailnet lock is the better answer for people who won't sustain that list — Headscale is the right choice exactly when you read it and nodded rather than sighed.
Compare Headscale
9 head-to-head comparisons.
Similar remote access & vpn apps
RustDesk
Remote Access & VPNOpen-source remote desktop alternative to TeamViewer
Replaces TeamViewer, AnyDesk
frp
Remote Access & VPNFast reverse proxy to expose local servers behind NAT
Replaces ngrok
Sunshine
Remote Access & VPNSelf-hosted game-stream host for Moonlight clients
Replaces NVIDIA GameStream, Parsec
Tailscale
Remote Access & VPNZero-config mesh VPN built on WireGuard
Replaces ZeroTier
JumpServer
Remote Access & VPNOpen-source bastion host and PAM platform
Replaces CyberArk, Teleport
Algo VPN
Remote Access & VPNSet up a personal IPsec and WireGuard VPN in minutes
Replaces NordVPN