Headscale: Self-Hosted Tailscale Control Server on Linux
Networking

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

bash
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/headscale

Step 2: Configure Headscale

bash
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:
[...]
Command truncated. Copy to view full command.

Step 3: systemd and Nginx TLS

bash
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;
[...]
Command truncated. Copy to view full command.

Step 4: Create Users and Pre-Auth Keys

bash
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

bash
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@"],
[...]
Command truncated. Copy to view full command.

Production Checklist

  • Back up /var/lib/headscale and 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

Technical Author - Liam K.
Liam K.

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