Comparing Relay Approaches in Mesh VPNs
Tailscale relies on WireGuard to link machines across disparate networks. In ideal conditions, UDP hole punching connects any two endpoints directly. But strict cellular carriers (CGNAT), corporate firewalls, and hotel Wi-Fi often impose Symmetric NAT. In those environments, mapped public ports change unpredictably for every destination. When direct peer-to-peer handshakes fail, traffic must fall back to intermediate relay servers: Tailscale’s Designated Encrypted Relay for Packets (DERP).
Teams running into NAT traversal bottlenecks usually weigh three choices:
- Default Public DERP Nodes: Tailscale maintains dozens of shared relays around the globe. They work out of the box. However, hops to distant regions routinely add 150ms to 250ms of ping time, and throughput often caps out under 15–20 Mbps during peak periods.
- Static Port Forwarding and UPnP: Opening fixed UDP ranges (like
41641/udp) on edge routers guarantees direct handshakes. Yet you cannot use this workaround on mobile uplinks, cloud VPCs, or corporate guest networks where upstream routers remain locked down. - A Dedicated Custom DERP Node: Spinning up a cheap cloud VM near your users to run Tailscale’s open-source
derperdaemon. WireGuard keys still encrypt all payload data end-to-end. You gain predictable throughput, dedicated bandwidth, and single-digit local latency.
Trade-offs: When Does a Self-Hosted Relay Make Sense?
A private relay improves connection reliability immediately. Still, operating your own node shifts certain infrastructure burdens onto your team.
Key Advantages
- Dramatically Lower Latency: If your office sits in Singapore and your traffic routes through a public relay in Tokyo, latency hovers around 80–120ms. Placing a local DERP node in a Singapore datacenter cuts round-trip ping down to 4–12ms.
- Uncapped Throughput: You avoid noisy-neighbor throttling on shared infrastructure. Large rsync jobs, database replicas, and bulk transfers can saturate your server’s full 1 Gbps uplink.
- Transparent Diagnostics: You control the host logs. When connections drop, run
tcpdumpon the interface rather than guessing what happens inside a third-party relay. - Zero-Trust Security by Design: DERP instances handle HTTPS-encapsulated WireGuard frames. Because the relay never holds private cryptographic keys, it cannot decrypt your data stream.
Operating Costs and Trade-offs
- Infrastructure Costs: A dedicated cloud VM with a static IPv4 address typically adds $4 to $6 per month to your hosting bill.
- Maintenance Footprint: You must patch the operating system, track upstream
derperupdates, and monitor TLS renewals. - Open Relay Risk: Leaving your instance exposed without strict client checks invites abuse. Unauthenticated third parties will scan for port 443 and hijack your node as a free proxy.
Hardware and Network Requirements
A modest instance handles production workloads surprisingly well. In our benchmarks, a basic single-core node comfortably manages dozens of concurrent tunnels without breaking a sweat.
Pick a minimal Ubuntu 22.04 or Debian 12 virtual machine with at least 1 vCPU and 1 GB of RAM. The instance requires:
- A static, publicly routable IPv4 address (and native IPv6 if available).
- An A/AAAA record pointing an FQDN to your host (such as
derp.example.com). - Port 80/TCP accessible for Let’s Encrypt HTTP-01 challenges.
- Port 443/TCP open for the HTTPS DERP relay tunnel.
- Port 3478/UDP open for STUN address discovery.
- The local Tailscale daemon running on the host so
derpercan verify peer identity via--verify-clients.
Step-by-Step Linux Deployment Guide
1. System Preparation and DNS Configuration
Point your DNS record to the server IP and verify propagation with dig +short derp.example.com. Next, log in and install baseline build utilities:
sudo apt update && sudo apt install -y curl git ufw build-essential
2. Install Go and Build the Relay Daemon
Tailscale ships derper as part of its official Go module repository. Fetch a modern Go release, extract it into /usr/local, and build the binary:
# Download and extract Go
wget https://go.dev/dl/go1.22.4.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.22.4.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
# Compile derper binary
go install tailscale.com/cmd/derper@latest
sudo cp ~/go/bin/derper /usr/local/bin/derper
sudo chmod +x /usr/local/bin/derper
3. Authenticate the Relay Host on Your Tailnet
Never run a DERP relay as an open proxy. When you launch derper alongside a local tailscaled process, it queries the local Tailscale socket. It drops any relay request that does not come from an authenticated machine in your tailnet.
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
4. Create a Systemd Service Unit
Create a dedicated storage directory for Let’s Encrypt certificates and run derper as a background systemd service:
sudo mkdir -p /var/lib/derper
Write the service definition to /etc/systemd/system/derper.service. Replace derp.example.com with your actual hostname:
sudo tee /etc/systemd/system/derper.service > /dev/null <<EOF
[Unit]
Description=Tailscale Custom DERP Server
After=network.target tailscaled.service
Wants=tailscaled.service
[Service]
Type=simple
User=root
Restart=always
RestartSec=5
ExecStart=/usr/local/bin/derper \
-hostname derp.example.com \
-certmode letsencrypt \
-certdir /var/lib/derper \
-a :443 \
-stun-port 3478 \
-verify-clients
[Install]
WantedBy=multi-user.target
EOF
Start the daemon and inspect output to confirm that TLS certificate issuance succeeded:
sudo systemctl daemon-reload
sudo systemctl enable --now derper
sudo journalctl -u derper -f
5. Configure UFW Firewall Rules
Allow the required HTTP, HTTPS, and STUN ports before locking down the host firewall:
sudo ufw allow 22/tcp comment "SSH administration"
sudo ufw allow 80/tcp comment "Let's Encrypt verification"
sudo ufw allow 443/tcp comment "DERP HTTPS relay traffic"
sudo ufw allow 3478/udp comment "Tailscale STUN port"
sudo ufw enable
6. Register the Relay in Your Tailscale ACL Policy
Open the Tailscale Admin Console and select Access Controls. Append your node inside the top-level derpMap attribute. Pick an ID between 900 and 999 so your custom region avoids colliding with official Tailscale relay numbers:
"derpMap": {
"Regions": {
"901": {
"RegionID": 901,
"RegionCode": "custom-sg",
"RegionName": "Singapore Private DERP",
"Nodes": [
{
"Name": "901a",
"RegionID": 901,
"HostName": "derp.example.com",
"DERPPort": 443,
"STUNPort": 3478
}
]
}
}
}
7. Verify Relay Routing and Test Latency
Switch to any remote client on your tailnet and run network diagnostics:
tailscale netcheck
The console report lists available regions along with their round-trip pings. Find your custom-sg entry and confirm that UDP STUN reports no packet loss. To watch the relay forward live packets, ping a target node locked behind symmetric NAT:
tailscale ping --verbose 100.115.82.44
If edge firewalls block direct NAT hole-punching, the ping trace immediately confirms delivery via derp-901a. Instead of suffering 180ms round trips through shared public infrastructure, your traffic now routes cleanly through your private instance in 8ms to 12ms.

