Headscale: Self-Hosted Tailscale Control Server on Linux
- Author :Liam K.
- Date :August 3, 2026
- Time :17 minutes
Headscale reimplements the Tailscale control plane so you can keep coordination private while still using official Tailscale clients. It is ideal when compliance, data residency, or cost rules block SaaS VPN control planes. This guide installs Headscale behind HTTPS and enrolls the first nodes with ACLs.
Note: Headscale is community software and not affiliated with Tailscale Inc. Validate licensing and supported client versions before production rollout.
Prerequisites
- Public Linux VPS for the control server
- DNS for
headscale.example.com - Clients that can install the Tailscale client
Step 1: Install Headscale
HEADSCALE_VERSION=0.23.0
curl -fsSL -o /tmp/headscale.deb \
https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_amd64.deb
sudo apt install -y /tmp/headscale.deb
sudo mkdir -p /etc/headscale /var/lib/headscale
sudo useradd --system --home-dir /var/lib/headscale --shell /usr/sbin/nologin headscale || true
sudo chown -R headscale:headscale /var/lib/headscaleStep 2: Configure Headscale
sudo tee /etc/headscale/config.yaml >/dev/null <<'EOF'
server_url: https://headscale.example.com
listen_addr: 127.0.0.1:8080
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: false
private_key_path: /var/lib/headscale/private.key
noise:
[...]Step 3: systemd and Nginx TLS
sudo systemctl enable --now headscale
sudo systemctl status headscale --no-pager
sudo tee /etc/nginx/sites-available/headscale >/dev/null <<'EOF'
server {
listen 80;
server_name headscale.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
[...]Step 4: Create Users and Pre-Auth Keys
sudo headscale users create ops
sudo headscale preauthkeys create --user ops --reusable --expiration 24h
# Use the printed key on clients:
# sudo tailscale up --login-server https://headscale.example.com --authkey <KEY>Step 5: Apply Basic ACLs
sudo tee /etc/headscale/acl.json >/dev/null <<'EOF'
{
"acls": [
{ "action": "accept", "src": ["group:ops"], "dst": ["*:*"] },
{ "action": "accept", "src": ["group:devs"], "dst": ["tag:dev:*"] }
],
"groups": {
"group:ops": ["ops@"],
[...]Production Checklist
- Back up
/var/lib/headscaleand private keys together. - Prefer short-lived pre-auth keys over reusable long-lived ones.
- Monitor control-server uptime; clients cannot enroll if Headscale is down.
- Keep Tailscale client versions within Headscale-supported ranges.
- Document break-glass SSH access that does not depend on the mesh.
"A self-hosted mesh is only safer than SaaS when ACLs, key rotation, and out-of-band recovery are part of the design."
Technical Author

System administrator and technical writer specializing in server infrastructure, security and deployment. Creating comprehensive guides to help you master server administration.