Headscale derp
Skill magnus919/agent-skills/bundles/tailscale/skills/headscale-derp
Configure and manage DERP relay servers for Tailscale/Headscale — embedded and standalone DERP deployment, latency testing, and connectivity diagnostics. Use when direct peer connections fail, traffic is routed through DERP relays, or setting up custom relay regions.From its SKILL.md
npx -y skills add magnus919/agent-skills --skill headscale-derpAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
5.4 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it
headscale-derp Skill
Overview
DERP = Designated Encrypted Relay Protocol. DERP is Tailscale's TURN-like fallback mechanism used when direct peer-to-peer NAT traversal fails. Traffic through DERP is fully encrypted (WireGuard inside TLS), but it routes through a relay server rather than directly between peers, so it introduces additional latency.
Common scenarios where DERP is used:
- Symmetric NAT — Both peers behind symmetric NAT gateways
- Corporate firewalls — Restrictive egress policies that block UDP/STUN
- Double NAT — Carrier-grade NAT on both sides
- Blocked STUN — UDP port 3478 is filtered
DERP in Headscale
Headscale includes an embedded DERP server that is enabled by default in the config.yaml:
derp:
server:
enabled: true
region_id: 999
region_code: "headscale"
region_name: "Headscale Embedded DERP"
stun_listen_addr: "0.0.0.0:3478"
private_key_path: "/var/lib/headscale/derp_server_private.key"
The embedded server runs a STUN endpoint on port 3478 and relays on port 443 (or whatever port Headscale listens on). It's suitable for small tailnets (under ~50 nodes).
Key config options
| Option | Default | Description |
|---|---|---|
derp.server.enabled | true | Enable the embedded DERP server |
derp.server.region_id | 999 | Numeric region identifier (must be unique across all regions) |
derp.urls | [] | Additional DERP map URLs (for standalone servers) |
derp.paths | [] | Local DERP map JSON file paths |
derp.auto_update | true | Automatically fetch Tailscale's default DERP map |
derp.stun_listen_addr | 0.0.0.0:3478 | STUN listener address |
DERP Map
A DERP map is a JSON structure that defines relay regions and nodes. Example:
{
"Regions": {
"900": {
"RegionID": 900,
"RegionCode": "us-nyc",
"RegionName": "New York",
"Nodes": [
{
"Name": "900a",
"RegionID": 900,
"HostName": "derp-nyc.example.com",
"DERPPort": 443,
"STUNPort": 3478,
"STUNOnly": false
}
]
}
}
}
The DERP map can be served via HTTPS URL (put in derp.urls) or as a local JSON file (put in derp.paths).
Connectivity Testing
Run tailscale netcheck to see which DERP regions are reachable and their latency:
$ tailscale netcheck
Report:
* UDP: true
* IPv4: yes
* IPv6: no
* MappingVariesByDestIP: true
* HairPinning: false
* PortMapping: UPnP
* Nearest DERP: Dallas
* DERP latency:
- dallas: 18ms (dallas)
- us-west: 35ms (us-west)
- new-york-city: 5ms (new-york-city)
- london: 85ms (london)
Standalone DERP
For larger tailnets or dedicated relay capacity, run a standalone DERP server using the official tailscale/derper Docker image:
docker run -d \
--name=derper \
--restart=always \
-p 3478:3478/udp \
-p 443:443 \
-v /etc/letsencrypt:/certs \
-v /var/lib/derper:/var/lib/derper \
tailscale/derper \
--hostname=derp.example.com
TLS Certificates
DERP requires TLS. Recommended approaches:
- Let's Encrypt (auto) —
tailscale/derpersupports automatic certificate issuance via Let's Encrypt. It listens on port 80 for the ACME HTTP-01 challenge. - Manual certs — Pass
--cert=/path/to/cert.pem --key=/path/to/key.pemto thederperbinary. - Reverse proxy — Terminate TLS at a reverse proxy (nginx, Caddy, Traefik) and forward to the local DERP port.
Region Selection
Tailscale clients automatically select the DERP region with the lowest latency. The selection algorithm:
- Sends STUN requests to all configured DERP regions
- Measures round-trip time for each
- Picks the region with the lowest latency
- Falls back to the next-closest region if connectivity fails
Gotchas
- DERP is encrypted but slower — All DERP traffic is WireGuard-inside-TLS, adding ~5-15ms overhead. Direct connections are always preferred.
- Embedded DERP works for small tailnets — The embedded server in Headscale uses the same Headscale process for relaying. Under heavy relay traffic, it can impact Headscale control-plane performance. For >50 nodes doing active relay, deploy a standalone DERP.
- All traffic routes through DERP if STUN is blocked — If UDP port 3478 is blocked anywhere in the network path, Tailscale cannot establish direct peer-to-peer connections and will route ALL traffic through the nearest DERP relay.
- Port 3478 (STUN) and 443 (DERP) must be open — STUN uses UDP for NAT traversal probing; DERP uses TCP/TLS for relay traffic. Both must be reachable from clients.
- Multiple regions improve resilience — Deploy DERP relays in at least two geographically diverse locations so clients have a fallback.
- DERP map caching — Clients cache the DERP map. If you add a new region, it can take up to 5 minutes for clients to pick it up. Use
tailscale netcheckto force a refresh.
Trigger Conditions
This skill is activated by keywords: DERP, relay, peer relay, STUN, direct connection failed
What ships with it: 4 files
30.7 KB alongside SKILL.md, 3 of them executable
scripts/
- deploy-derp.shruns10.2 KB
- derp-health-check.pyruns12.0 KB
- test-derp-latency.shruns8.0 KB
- README.md494 B