Headscale: Ditch Tailscale's Cloud Control Server Today
What if I told you that every device on your "private" Tailscale network phones home to a cloud server you don't control? That sleek VPN you set up in five minutes? Its beating heart—the control server that holds every public key, every IP assignment, every routing decision—lives on infrastructure owned by a Silicon Valley company. For hobbyists, homelab warriors, and privacy-obsessed developers, that's not a feature. It's a dealbreaker waiting to happen.
Enter Headscale, the open-source, self-hosted implementation of the Tailscale control server that's making waves across Reddit, Hacker News, and every self-hosting community worth its salt. Created by Juan Font Alonso and actively maintained—including contributions from a Tailscale employee officially sponsored to work on it—Headscale tears down the walled garden and hands you the keys to your own network kingdom.
No subscription fees. No vendor lock-in. No trusting a third party with your WireGuard public keys. Just pure, unadulterated control over your overlay network. If you've ever felt that nagging discomfort about cloud-dependent infrastructure, or if your monthly Tailscale bill is starting to sting, this article will show you exactly why thousands of developers are migrating to Headscale—and how you can join them in under thirty minutes.
What is Headscale?
Headscale is an open-source, self-hosted reimplementation of the Tailscale control server, written in Go and designed for a single, focused purpose: giving self-hosters complete sovereignty over their WireGuard-based overlay networks.
The project was created by Juan Font Alonso and has since grown into a thriving community effort. Its most intriguing twist? One of its active maintainers, Kristoffer Dalby, is employed by Tailscale itself and officially permitted to spend work hours contributing to what is technically a competing project. This isn't corporate sabotage—it's a testament to Tailscale's genuine commitment to open source, and it gives Headscale an almost unfair advantage: insider knowledge of the protocol, direct lines of communication, and a legitimacy that few third-party reimplementations ever achieve.
Why is Headscale trending right now? Three forces are converging:
- The self-hosting renaissance: Post-pandemic, developers are reclaiming their infrastructure. Cloud bills are under scrutiny, and "cloud exit" strategies are trending.
- WireGuard ubiquity: The Linux kernel's adoption of WireGuard made fast, modern VPNs accessible to everyone. Tailscale built brilliant clients on top—but the control server remained proprietary.
- Privacy paranoia (justified): High-profile breaches and surveillance revelations have made technical users acutely aware of who holds their cryptographic material.
Headscale occupies a deliberately narrow scope. Unlike Tailscale's multi-tenant SaaS offering, Headscale implements a single tailnet—perfect for personal use, small open-source organizations, or tight-knit teams. This isn't a limitation; it's a design philosophy. By saying "no" to enterprise complexity, Headscale says "yes" to simplicity, auditability, and deployability on a $5 VPS.
The project maintains rigorous quality standards. Code is linted with golangci-lint, formatted with gofumpt and golines, and the Protobuf definitions are managed with buf. Documentation is versioned alongside releases, with separate tracks for stable and development builds. This isn't a weekend hack—it's production-grade infrastructure disguised as a community project.
Key Features That Make Headscale Irresistible
Headscale isn't a stripped-down clone. It's a thoughtfully engineered alternative that preserves what makes Tailscale magical while eliminating the SaaS dependency. Here's what you're getting:
🔐 Complete Cryptographic Sovereignty Your WireGuard public keys never leave hardware you control. The control server—the single most sensitive component in any Tailscale deployment—runs on your infrastructure, behind your firewall, subject to your compliance requirements. For GDPR-sensitive organizations or security-conscious individuals, this is non-negotiable.
💰 Zero Subscription Costs Tailscale's free tier is generous but limited. Their paid tiers scale per-user. Headscale? The only cost is your server. A $3.50/month VPS from Hetzner or a Raspberry Pi in your closet handles hundreds of devices without blinking.
🖥️ Full Client Compatibility Headscale works with official Tailscale clients across Linux, Android, BSD, and other platforms. You're not sacrificing the polished UX that made Tailscale famous—you're just replacing the invisible backend. Check the official client support documentation for the latest compatibility matrix.
🛠️ Nix-First Development Environment
The project embraces Nix for reproducible builds and development environments. A single nix develop command drops you into a shell with exact versions of Go, Buf, Protobuf tools, and linters. No "works on my machine." No dependency drift. Just hermetic, bit-for-bit reproducible builds.
📡 NAT Traversal Without Compromise Headscale inherits Tailscale's brilliant NAT traversal techniques—STUN, DERP relays, UDP hole punching—because it speaks the same protocol. Your devices still find each other through the toughest corporate firewalls and carrier-grade NAT, but the coordination happens on your terms.
🎯 Single Tailnet Simplicity By design, Headscale manages one tailnet. No user namespaces, no complex ACL inheritance, no enterprise RBAC sprawl. You get a flat, comprehensible network topology that you can hold in your head. This is the Unix philosophy applied to VPN infrastructure: do one thing well.
⚡ Active, Transparent Governance With a Tailscale employee as maintainer and open community direction-setting, Headscale avoids the "bus factor" anxiety that plagues many open-source projects. The FOSDEM 2026 talk by Kristoffer Dalby explicitly frames Headscale as "complementary"—not antagonistic—to Tailscale's commercial offering.
Real-World Use Cases Where Headscale Dominates
Theory is cheap. Let's talk about where Headscale actually solves problems that keep engineers awake at night.
The Privacy-First Homelab
You've got Plex, Nextcloud, Home Assistant, and a dozen other services running on bare metal in your closet. You could expose ports and pray. You could use a cloud VPN and trust their logs policy. Or you could run Headscale on that same hardware, create a mesh network that never touches third-party infrastructure, and access everything from your phone with cryptographic certainty. Your ISP sees encrypted WireGuard packets to your own IP. That's it.
The Bootstrapped SaaS Startup
Your team is five people across three continents. You need shared access to staging databases, internal Grafana dashboards, and the occasional production rescue. Tailscale's per-user pricing would cost you $30-50/month minimum. Headscale on a $5 VPS gives you identical functionality with a docker↗ Bright Coding Blog-compose.yml you can version control. When you hit Series A, migrate to Tailscale's enterprise offering. Until then, spend that money on coffee.
The Air-Gapped or Compliance-Bound Organization
Healthcare. Finance. Defense contractors. Any environment where "cloud" is a four-letter word. Headscale deploys entirely on-premises, generates audit logs you control, and never exfiltrates metadata to external infrastructure. Your security team can review every line of Go. Try getting that transparency from a SaaS provider.
The Distributed CI/CD Mesh
Your GitHub Actions runners, self-hosted Buildkite agents, and on-premise GitLab CI executors need to communicate securely without public IPs. Headscale creates a flat network where your ARM64 build farm in your garage talks directly to your x86 cloud instances, all coordinated by your control server. No SSH bastions. No VPN concentrators. Just WireGuard everywhere.
Step-by-Step Installation & Setup Guide
The maintainers are explicit: they don't support reverse proxies or containers for production deployments. This guide respects that guidance while showing you the canonical path to a running server.
Prerequisites
- A Linux server (Debian 12, Ubuntu 22.04+, or NixOS recommended)
- A public IP address (IPv4 or IPv6)
- Open UDP ports 3478 (STUN) and 41641 (WireGuard)
- A domain name (optional but strongly recommended for TLS)
Method 1: Binary Installation (Recommended)
Download the latest release matching your architecture:
# Fetch the latest stable release (check GitHub for actual version)
curl -LO https://github.com/juanfont/headscale/releases/download/v0.23.0/headscale_0.23.0_linux_amd64
# Make executable and install to PATH
chmod +x headscale_0.23.0_linux_amd64
sudo mv headscale_0.23.0_linux_amd64 /usr/local/bin/headscale
# Verify installation
headscale version
Method 2: NixOS Module (For Nix Users)
NixOS users get first-class treatment. The module lives in the repository's nix/ directory:
# In your configuration.nix
services.headscale = {
enable = true;
address = "0.0.0.0";
port = 8080;
settings = {
server_url = "https://headscale.yourdomain.com";
# Your WireGuard private key (generate with: headscale generate private-key)
private_key_path = "/var/lib/headscale/private.key";
# SQLite for small deployments, PostgreSQL↗ Bright Coding Blog for scale
db_type = "sqlite3";
db_path = "/var/lib/headscale/db.sqlite";
# DERP (relay) configuration
derp = {
urls = [];
paths = [];
auto_update_enable = true;
update_frequency = "24h";
};
};
};
Configuration File Setup
Create your configuration directory and copy the example:
sudo mkdir -p /etc/headscale
sudo curl -o /etc/headscale/config.yaml \
https://raw.githubusercontent.com/juanfont/headscale/v0.23.0/config-example.yaml
Critical configuration values to modify:
# /etc/headscale/config.yaml
server_url: https://headscale.yourdomain.com # Your public endpoint
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 127.0.0.1:9090
# Generate keys before first run
private_key_path: /var/lib/headscale/private.key
noise:
private_key_path: /var/lib/headscale/noise_private.key
# SQLite for simplicity; PostgreSQL for production
database:
type: sqlite3
sqlite:
path: /var/lib/headscale/db.sqlite
# Define your tailnet's IP range
ip_prefixes:
- fd7a:115c:a1e0::/48 # IPv6 ULA
- 100.64.0.0/10 # IPv4 CGNAT (Tailscale's default)
# DNS configuration
dns:
magic_dns: true
base_domain: example.com
nameservers:
- 1.1.1.1
- 8.8.8.8
Generate required keys:
sudo mkdir -p /var/lib/headscale
sudo headscale generate private-key > /var/lib/headscale/private.key
sudo headscale generate noise-private-key > /var/lib/headscale/noise_private.key
sudo chmod 600 /var/lib/headscale/*.key
Systemd Service Setup
sudo curl -o /etc/systemd/system/headscale.service \
https://raw.githubusercontent.com/juanfont/headscale/v0.23.0/docs/packaging/headscale.systemd.service
sudo systemctl daemon-reload
sudo systemctl enable --now headscale
sudo systemctl status headscale
First User and Machine Registration
# Create your first user (namespace)
sudo headscale users create myuser
# Generate a pre-auth key for automated enrollment
sudo headscale preauthkeys create --user myuser --reusable --expiration 24h
# On your client machine, register with your server
tailscale up --login-server https://headscale.yourdomain.com --authkey <pre-auth-key>
REAL Code Examples from the Repository
Let's examine actual patterns from the Headscale codebase and documentation, with detailed explanations of what's happening under the hood.
Example 1: Development Environment with Nix
The project strongly recommends Nix for reproducible development. Here's the exact workflow:
# Enter the development shell with all tools pinned to exact versions
nix develop
# The shell now contains:
# - Go (exact version specified in flake.nix)
# - Buf (Protobuf build system)
# - Protobuf compiler and plugins
# - golangci-lint, golines, gofumpt (formatting and linting)
# - clang-format (for Protobuf formatting)
# - mdformat, prettier (documentation formatting)
# Verify your environment
go version
buf --version
make help # See all available build targets
Why this matters: Traditional Go projects suffer from "it works on my machine" because go.mod only pins module versions, not toolchain versions. Two developers with different golangci-lint versions get different lint results. Nix eliminates this entire class of problems by providing a hermetic environment where every tool is cryptographically hashed and reproducible. When a maintainer says "run make lint", they mean the exact same binary on every machine.
Example 2: Protobuf Code Generation
Headscale communicates with Tailscale clients using gRPC and Protocol Buffers. When you modify the API definitions, you must regenerate Go code:
# After modifying files in proto/, regenerate Go bindings
make generate
# This internally runs:
# - buf generate (compiles .proto to Go structs and gRPC interfaces)
# - goimports (fixes import statements)
# - gofumpt (stricter formatting than gofmt)
# Critical: commit generated code separately for cleaner reviews
git add gen/
git commit -m "chore: regenerate protobuf bindings"
The technical story: Tailscale's control protocol is defined in Protobuf, but the official definitions aren't fully open. Headscale's maintainers carefully reverse-engineered compatible messages while maintaining clean-room separation. The gen/ directory contains the resulting Go code—thousands of lines of meticulously crafted structs that speak Tailscale's dialect of WireGuard coordination. By checking this in separately, reviewers can focus on hand-written logic without drowning in generated noise.
Example 3: Building and Testing
Here's the complete development workflow, showing both Nix and non-Nix paths:
# === RECOMMENDED: With Nix ===
nix develop # Enter hermetic shell
make test # Run full test suite (integration tests included)
make build # Compile headscale binary
# === ALTERNATIVE: With manual dependencies ===
# The Makefile will warn if tools are missing
make test # May fail with helpful error: "Install buf or run nix develop"
make build # Produces ./headscale binary
# See all available targets
make help
What's actually tested: Headscale's test suite includes integration tests that spin up real Tailscale clients in containers, verify NAT traversal, test key exchange, and validate the full control loop. This isn't unit-test theater—it's testing against actual client behavior. The make test command orchestrates Docker, network namespaces, and cryptographic verification to ensure your changes don't break real-world connectivity.
Example 4: Makefile Targets for Quality Assurance
The Makefile enforces project standards automatically:
# From the actual Makefile (conceptual representation)
lint:
golangci-lint run --config .golangci.yaml
buf lint
# Catches: unused code, security issues, style violations
fmt:
golines -w --max-len 88 .
gofumpt -w .
buf format -w
mdformat docs/
prettier --write "**/*.{md,yaml,yml}"
# Enforces: consistent formatting, readable line lengths
test:
go test -race -count=1 ./...
# -race: detects data races (critical for concurrent network code)
# -count=1: disables test caching (integration tests are stateful)
build:
go build -ldflags "-X version=$VERSION" -o headscale ./cmd/headscale
# Injects version into binary for `headscale version` command
The craftsmanship insight: Notice the 88-character line width (matching Black, Python↗ Bright Coding Blog's formatter), the race detector mandatory for network code, and the version injection at link time. These aren't arbitrary choices—they're battle-tested conventions from large-scale Go projects, applied with discipline that prevents technical debt accumulation.
Advanced Usage & Best Practices
Once you're running, these pro tips extract maximum value from your deployment:
🔑 Pre-Auth Key Rotation Strategy Don't reuse long-lived keys. Generate short-lived keys for provisioning batches, then revoke immediately. For infrastructure-as-code, inject keys via your secret manager (Vault, 1Password Secrets Automation, SOPS) with automatic rotation.
📊 Metrics and Observability
Headscale exposes Prometheus metrics on metrics_listen_addr. Scrape these for Grafana dashboards tracking active peers, control message rates, and DERP relay utilization. Set alerts for certificate expiration and unusual authentication patterns.
🔄 Backup Your SQLite Database
The SQLite file at db_path contains all node registrations, keys, and network state. Back it up with sqlite3 db.sqlite ".backup to /backup/headscale-$(date +%F).db" before upgrades. For production, migrate to PostgreSQL for point-in-time recovery.
🌐 DERP Server Selection Headscale can use Tailscale's public DERP relays or run your own. For minimal latency, deploy private DERP servers geographically close to your users. The configuration supports weighted selection for failover.
🛡️ ACLs with HuJSON Headscale supports Tailscale's HuJSON (Human JSON) ACL format. Define granular access controls: tag-based rules, user-to-user restrictions, and port-level filtering. Start permissive, then tighten based on observed traffic patterns.
Headscale vs. Alternatives: The Honest Comparison
| Feature | Headscale | Tailscale SaaS | NetMaker | OpenZiti |
|---|---|---|---|---|
| Control Server | Self-hosted | Cloud-hosted | Self-hosted | Self-hosted |
| Cost | Free (server only) | Free tier, then per-user | Free/Pro tiers | Free/Enterprise |
| Client Compatibility | Official Tailscale clients | Official Tailscale clients | WireGuard + custom | Custom SDKs |
| Protocol | Tailscale protocol | Tailscale protocol | WireGuard | Custom (TLS everywhere) |
| Scope | Single tailnet | Multiple tailnets, orgs | Multiple networks | Zero-trust overlay |
| Complexity | Low | Minimal | Medium | High |
| NAT Traversal | Full (STUN, DERP, UPnP) | Full (global DERP network) | STUN, manual relay | Proxy-based |
| Auditability | Complete source access | Black box | Open source | Open source |
| Best For | Homelabs, small teams | Enterprises, quick start | Multi-site businesses | Security-critical deployments |
When to choose Headscale: You value control over convenience, your budget matters, and your scale fits a single tailnet. The official client compatibility means you're not sacrificing UX—you're just self-hosting the coordination plane.
When to stay with Tailscale: You need multi-tenant user management, SCIM provisioning, or you simply value "it just works" over configurability. Tailscale's global DERP network has better coverage than most self-hosted setups.
FAQ: What Developers Actually Ask
Is Headscale legal? Does Tailscale approve? Yes, completely legal. Tailscale's protocol is built on open standards, and one of Headscale's maintainers is a Tailscale employee. The projects are explicitly framed as complementary, not competitive.
Can I use official Tailscale mobile apps with Headscale? Yes for Android (sideload or custom builds). iOS is restricted by Apple's ecosystem—you'll need to use TestFlight builds or accept that Apple's clients hardcode Tailscale's control server. Check the latest client support docs.
How do I migrate from Tailscale without reconfiguring every device? There's no automatic migration path. Generate new auth keys in Headscale, then re-authenticate devices. For fleets, use pre-auth keys with your configuration management (Ansible, Puppet, etc.) to minimize disruption.
Does Headscale support MagicDNS and HTTPS certificates? Yes. MagicDNS works identically to Tailscale. For HTTPS, Headscale can coordinate Let's Encrypt certificates via ACME, or you can terminate TLS at your reverse proxy (though unsupported by maintainers for production).
What's the maximum number of devices? Practical limits depend on your server specs. Hundreds of devices are routine on small VPS instances. The SQLite backend becomes a bottleneck around 1000+ nodes; migrate to PostgreSQL for larger deployments.
How stable is the API? Will my clients break? Headscale follows Tailscale's protocol evolution. Major version bumps may require client updates. Pin your deployment to specific versions and test upgrades in staging.
Can I contribute if I'm not a Go expert? Absolutely. Documentation improvements, bug reports, client compatibility testing, and Nix packaging are all valuable contributions. The CONTRIBUTING.md has details.
Conclusion: Take Back Your Network
Headscale represents something rare in modern infrastructure: a genuinely open alternative to a polished commercial product that doesn't demand you sacrifice quality for freedom. It proves that self-hosting doesn't have to mean cobbling together fragile scripts, and that open-source governance can thrive even when a team member works for the "competition."
The migration path is straightforward. The client experience is identical. The cost savings are immediate. But more importantly, you regain something intangible yet invaluable: the certainty that your network's nervous system beats on hardware you can touch, in jurisdictions you understand, under policies you set.
For homelab enthusiasts, this is the missing piece that completes your sovereignty stack. For startups, it's runway-extending infrastructure pragmatism. For privacy advocates, it's cryptographic self-determination made practical.
Your next step: Head to github.com/juanfont/headscale, read the stable documentation, and spin up your control server this weekend. Join the Discord community when you hit questions—the maintainers and users are genuinely helpful.
The cloud isn't going anywhere. But neither is your right to opt out of it when the tradeoffs don't serve you. Headscale makes that choice not just possible, but pleasant. Deploy it, audit it, own it. Your future self—the one debugging a 3 AM outage without a vendor support ticket—will thank you.