Headscale: Nodes Not Connecting — Fix
The Problem
Your Headscale nodes can’t connect to each other. The Tailscale client shows “not connected” or nodes appear in headscale nodes list but can’t ping each other. You might also see registration failures, MagicDNS not resolving peer names, or nodes routing through DERP relays instead of connecting directly.
The Cause
Headscale connection issues typically fall into four categories: the Headscale server not reachable by clients, node registration failures, routing/ACL problems preventing peer communication, or NAT traversal issues forcing relay connections.
The Fix
Method 1: Verify Server Reachability
The Tailscale client must reach the Headscale server on its configured URL:
# Check if Headscale is listening
curl -I https://headscale.yourdomain.com/health
# Expected: HTTP 200 with {"status":"ok"}
If this fails:
- SSL certificate issue: Headscale requires HTTPS. If using a reverse proxy, ensure SSL is configured. Self-signed certs won’t work with the Tailscale client unless you set
HEADSCALE_TLS_CERT_PATHandHEADSCALE_TLS_KEY_PATH. - Wrong port: The default gRPC port is 50443 and the HTTP port is 8080. If behind a reverse proxy, route port 443 to 8080.
- Firewall: Ensure port 443 (or your configured port) is open on both the server firewall and any cloud firewall.
Method 2: Fix Node Registration
If tailscale up fails to register with your Headscale server:
# On the client
tailscale up --login-server=https://headscale.yourdomain.com
# If you get a URL to visit, copy it and register the node:
headscale nodes register --user <username> --key nodekey:<key>
Pre-auth keys skip the manual registration step:
# On the Headscale server
headscale preauthkeys create --user <username> --reusable --expiration 24h
# On the client
tailscale up --login-server=https://headscale.yourdomain.com --authkey <pre-auth-key>
Common issue: Using tailscale login instead of tailscale up. With Headscale, always use tailscale up --login-server=<url>.
Method 3: Fix Nodes Can’t Ping Each Other
Nodes are registered and online but can’t communicate:
# Check node status on the server
headscale nodes list
# Check routes on the client
tailscale status
ACL issue: By default, Headscale allows all traffic between nodes. If you’ve configured ACLs (acl_policy_path in config), verify your rules allow the traffic:
{
"acls": [
{"action": "accept", "src": ["*"], "dst": ["*:*"]}
]
}
Route issue: If you’ve advertised routes, they must be approved:
# List routes
headscale routes list
# Enable a specific route
headscale routes enable --route <route-id>
Method 4: Fix DERP Relay Connections
If nodes connect but only through DERP relays (slow, indirect), they can’t establish direct peer-to-peer connections:
# Check connection type on the client
tailscale status
# Look for "relay" vs "direct" in the output
tailscale netcheck
# Shows NAT type and DERP connectivity
Causes:
- Symmetric NAT on both sides — direct connection impossible, DERP is the only option
- Firewall blocking UDP — WireGuard needs UDP port 41641 (Tailscale default)
- Both nodes behind CGNAT — neither can accept incoming connections
Fix: Open UDP port 41641 on at least one node’s firewall/router. Or use a custom DERP server closer to your nodes.
Method 5: Fix MagicDNS
If Tailscale IPs work but hostnames don’t resolve:
# Check if MagicDNS is enabled
tailscale status --json | jq .MagicDNSSuffix
Ensure magic_dns is enabled in your Headscale config:
dns:
magic_dns: true
base_domain: headscale.local
nameservers:
- 1.1.1.1
- 8.8.8.8
After changing the config, restart Headscale and reconnect clients:
# Server
docker restart headscale
# Client
tailscale down && tailscale up --login-server=https://headscale.yourdomain.com
Prevention
- Use pre-auth keys for automated node registration instead of manual approval.
- Pin your Headscale version — don’t use
:latest. Config format can change between versions. - Back up
/var/lib/headscale/— this contains the SQLite database with all node registrations and keys. - Monitor DERP connectivity — run
tailscale netcheckperiodically to verify direct connections. - Use the same Headscale version across upgrades of the config format — check the changelog before upgrading.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments