How NAT Traversal Actually Works in Tailscale
Table of Contents

You install Tailscale, sign in, and suddenly your laptop at a coffee shop can reach your homelab NAS behind two layers of NAT. No port forwarding. No firewall rules. It just… works.
But how? The answer involves some clever protocol engineering, a custom relay system, and a lot of UDP tricks. Let’s break it down.
The Problem: NATs Are Everywhere #
Most devices on the internet don’t have a public IP address. They sit behind one or more NAT (Network Address Translation) devices — your home router, your office firewall, your ISP’s carrier-grade NAT. These devices let many private hosts share a single public IP by rewriting source addresses on outbound packets and tracking which internal host should receive each reply.
This works great for client-server traffic. It’s terrible for peer-to-peer. If two devices are both behind NATs, neither one knows the other’s real address, and neither NAT will accept unsolicited inbound packets. It’s a deadlock.
Tailscale’s entire value proposition depends on breaking this deadlock to create direct, encrypted WireGuard tunnels between your devices — wherever they are.
Step 1: STUN — “What Do I Look Like From Out There?” #
The first tool in the kit is STUN (Session Traversal Utilities for NAT). The concept is elegantly simple: when a device behind a NAT sends a UDP packet to a STUN server on the public internet, the server can see the public IP and port that the NAT assigned. It sends that information back to the client.
Now the client knows what its traffic looks like from outside its NAT. It can share this public endpoint with peers through a coordination channel, giving them an address to aim for.
Tailscale runs STUN on its DERP servers (more on those in a moment), so every node in your tailnet can discover its own public-facing address.
Step 2: Hole Punching — The Simultaneous Send Trick #
Knowing your public endpoint is only half the battle. The NAT still won’t let unsolicited packets in. This is where UDP hole punching comes in.
The idea: both peers send a UDP packet to each other’s discovered public endpoint at roughly the same time. When peer A sends a packet to peer B’s NAT, peer A’s NAT creates an outbound mapping. Moments later, when peer B’s packet arrives at peer A’s NAT, the NAT sees it as a reply to that outbound flow and lets it through. The same thing happens in reverse on peer B’s side.
The result is a direct path through both NATs, with no manual configuration required. Tailscale coordinates this timing through its control plane, ensuring both sides fire their packets in a tight window.
Step 3: Dealing With “Hard” NATs #
Not all NATs play nice. The trickiest are symmetric NATs (sometimes called “hard” NATs), which assign a different external port for every unique destination. This means the port that STUN discovers is useless for talking to any peer other than the STUN server itself.
Symmetric NATs are especially common in cloud environments. AWS, Azure, and Google Cloud NAT gateways all default to symmetric behavior — great for outbound scale, terrible for peer-to-peer.
When both peers are behind hard NATs, direct hole punching usually fails. This is where Tailscale’s fallback layer comes in.
Step 4: DERP — The Relay That Never Gives Up #
Tailscale built its own relay protocol called DERP (Detoured Encrypted Routing Protocol). Unlike the traditional TURN relay standard, DERP runs over HTTP, which means it works even on networks that block all UDP traffic. It routes encrypted WireGuard packets based on the destination’s public key — the relay never sees plaintext.
Here’s the key architectural detail: every Tailscale connection starts through DERP. When device A wants to talk to device B, it first reaches out through the nearest DERP relay to exchange endpoint information and begin sending data. In parallel, both devices attempt NAT traversal to establish a direct UDP link. If that succeeds, traffic seamlessly switches to the direct path and DERP steps aside. If it doesn’t, DERP keeps relaying for as long as needed.
This “relay-first, upgrade-later” approach means connections are established instantly — no waiting for hole-punching to succeed before you can send your first packet.
Step 5: The Disco Protocol — Racing for the Best Path #
Tailscale doesn’t just try one path and hope for the best. Its custom discovery protocol (called “disco”) sends probe packets to every candidate endpoint simultaneously, essentially racing multiple paths against each other. The first path that gets a response wins.
Each node has a unique disco keypair, and all probe packets are authenticated, so you can’t spoof your way into someone’s tailnet. The protocol handles everything from initial path discovery to ongoing liveness checks — if a working path degrades, Tailscale detects it and can switch to a better one.
The Results #
In practice, this layered approach works remarkably well. Tailscale reports that direct peer-to-peer connections succeed over 90% of the time. For the remaining cases — double symmetric NATs, aggressive corporate firewalls, networks that block UDP entirely — DERP ensures connectivity is never lost, just slightly slower.
Why This Matters #
NAT traversal isn’t just a Tailscale problem. WebRTC uses similar techniques for browser-based video calls. VoIP systems, multiplayer games, and IoT platforms all wrestle with the same challenge. What makes Tailscale’s approach worth studying is how cleanly it layers these techniques: STUN for discovery, hole punching for direct paths, DERP for guaranteed fallback, and disco for ongoing path optimization.
The next time your Tailscale connection “just works” from a hotel room or an airport lounge, you’ll know there’s a whole orchestration of UDP packets, relay servers, and cryptographic handshakes happening behind the scenes to make it look effortless.