The derper debug pages had no way to see which clients were connected. The expvar gauges only give counts, /debug/check only says whether the counts agree, and /debug/traffic only reports connections that moved bytes since its last tick, and only if ss is installed. Add /debug/clients/, which by default serves an index page with a form to pick one of four filters: ?all lists every connection, ?ip=1.2.3.4 and ?cidr=1.2.0.0/16 list connections from an address or prefix, and ?key=nodekey:... lists the connection(s) for one node key. Each row shows the connection number, key, remote address, connection age, flags (home, mesh, prober, notideal, dup/active/disabled), protocol version, app name, per-connection rx/tx packet and byte counts, and the estimated unique sender count. Big derpers have far too many connections for one page, so results are paginated with keyset cursors rather than page numbers: sort=key, ip, conn, rx, tx, rxpkts, or txpkts (with a leading - for descending) picks the walk order, limit=N the page size, and after=X resumes after that value of the sort field. The next-page links add afterconn=N so a page boundary that falls among connections sharing a value (duplicate keys, one IP with many ports, equal counters) resumes exactly. Column headers link to the other sort orders. The walk under Server.mu does only a filter match, a cursor comparison, and at most a bounded-heap operation per connection, so connections before the cursor are discarded without being copied and at most limit entries are ever kept. Only the summary counts (matching connections and keys) look at every connection. Snapshots are taken and the page rendered after the lock is released, so a slow debug client can't stall the server. A benchmark with 100k connections takes about 10ms per page. There were no per-connection traffic counters before, only the server-wide ones, so sclient gains four atomic.Uint64 counters (rx/tx packets and bytes, counting data packets like the server-wide ones) bumped alongside them. That's 32 bytes per connection. For the counter sorts, the value is loaded once per connection during the walk and used for both the cursor test and the heap order, so the order stays consistent while the counters keep changing. The sclient preferred field becomes an atomic.Bool so the page can report which connections are the client's home DERP; it was previously only touched by the run goroutine. Updates tailscale/corp#48933 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I4e9b7c2d5a83f61b0e7d2c94a5f8b3e16d7c0a29
DERP
This is the code for the Tailscale DERP server.
In general, you should not need to or want to run this code. The overwhelming majority of Tailscale users (both individuals and companies) do not.
In the happy path, Tailscale establishes direct connections between peers and data plane traffic flows directly between them, without using DERP for more than acting as a low bandwidth side channel to bootstrap the NAT traversal. If you find yourself wanting DERP for more bandwidth, the real problem is usually the network configuration of your Tailscale node(s), making sure that Tailscale can get direction connections via some mechanism.
If you've decided or been advised to run your own derper, then read on.
Caveats
-
Node sharing and other cross-Tailnet features don't work when using custom DERP servers.
-
DERP servers only see encrypted WireGuard packets and thus are not useful for network-level debugging.
-
The Tailscale control plane does certain geo-level steering features and optimizations that are not available when using custom DERP servers.
Guide to running cmd/derper
-
You must build and update the
cmd/derperbinary yourself. There are no packages. Usego install tailscale.com/cmd/derper@latestwith the latest version of Go. You should update this binary approximately as regularly as you update Tailscale nodes. If using--verify-clients, thederperbinary andtailscaledbinary on the machine must be built from the same git revision. (It might work otherwise, but they're developed and only tested together.) -
The DERP protocol does a protocol switch inside TLS from HTTP to a custom bidirectional binary protocol. It is thus incompatible with many HTTP proxies. Do not put
derperbehind another HTTP proxy. -
The
tailscaledclient does its own selection of the fastest/nearest DERP server based on latency measurements. Do not putderperbehind a global load balancer. -
DERP servers should ideally have both a static IPv4 and static IPv6 address. Both of those should be listed in the DERP map so the client doesn't need to rely on its DNS which might be broken and dependent on DERP to get back up.
-
A DERP server should not share an IP address with any other DERP server.
-
Avoid having multiple DERP nodes in a region. If you must, they all need to be meshed with each other and monitored. Having two one-node "regions" in the same datacenter is usually easier and more reliable than meshing, at the cost of more required connections from clients in some cases. If your clients aren't mobile (battery constrained), one node regions are definitely preferred. If you really need multiple nodes in a region for HA reasons, two is sufficient.
-
Monitor your DERP servers with
cmd/derpprobe. -
If using
--verify-clients, atailscaledmust be running alongside thederper, and all clients must be visible to the derper tailscaled in the ACL. -
If using
--verify-clients, atailscaledmust also be running alongside yourderpprobe, andderpprobeneeds to use--derp-map=local. -
The firewall on the
derpershould permit TCP ports 80 and 443 and UDP port 3478. -
Only LetsEncrypt certs are rotated automatically. Other cert updates require a restart.
-
Don't use a firewall in front of
derperthat suppressesRSTs upon receiving traffic to a dead or unknown connection. -
Don't rate-limit UDP STUN packets.
-
Don't rate-limit outbound TCP traffic (only inbound).
Diagnostics
This is not a complete guide on DERP diagnostics.
Running your own DERP services requires exeprtise in multi-layer network and application diagnostics. As the DERP runs multiple protocols at multiple layers and is not a regular HTTP(s) server you will need expertise in correlative analysis to diagnose the most tricky problems. There is no "plain text" or "open" mode of operation for DERP.
-
The debug handler is accessible at URL path
/debug/. It is only accessible over localhost or from a Tailscale IP address. -
Go pprof can be accessed via the debug handler at
/debug/pprof/ -
Prometheus compatible metrics can be gathered from the debug handler at
/debug/varz. -
cmd/stuncin the Tailscale repository provides a basic tool for diagnosing issues with STUN. -
cmd/derpprobeprovides a service for monitoring DERP cluster health. -
tailscale debug derpandtailscale netcheckprovide additional client driven diagnostic information for DERP communications. -
Tailscale logs may provide insight for certain problems, such as if DERPs are unreachable or peers are regularly not reachable in their DERP home regions. There are many possible misconfiguration causes for these problems, but regular log entries are a good first indicator that there is a problem.