How Hotel Wi-Fi Broke My Tailscale Peer Relay

July 10, 2026

TL;DR: If you use peer relays in your Tailscale setup, you should consider port forwarding/exposing more than one port.

If you subscribed to this blog for my thoughts and findings on cloud security, I would like to proactively apologize. That said, I’d like to share a little story about a recent troubleshooting journey in which I fought against everyone’s worst enemy: hotel Wi-Fi.

The setup

For work, I travel several times a year. Every time I get to the hotel, one of the first things I do is run a speed test on the Wi-Fi to get an idea of how well things are going. Earlier this week I did my normal ritual and was very pleased to see a ~100 Mbps connection. “Great,” I thought, and shortly thereafter I tried to download some files from my NAS only to be disappointed at how slow the transfer was.

My personal VPN of choice is Tailscale (not sponsored). As a security nerd, Tailscale has a ton of benefits over a traditional VPN, one of which is that, most of the time, it will make an encrypted, direct, peer-to-peer connection between two devices.

However, sometimes this process can be difficult, particularly when traversing different NAT scenarios (such as the aforementioned hotel Wi-Fi dread). When it cannot rely on a direct connection, Tailscale will use DERP. To keep things simple, you really don’t want your traffic to go over DERP if you’re looking for any kind of performant transfer speed.

In order to provide another option for when you can’t tunnel out of a hard NAT scenario, Tailscale introduced a relatively new feature called a peer relay. The idea is that you create a Tailscale node somewhere more accessible that essentially proxies the connection between the two nodes trying to talk to each other. This eliminates the bottleneck of DERP and allows you to have near-peer-to-peer speeds.

I run a Proxmox hypervisor in my home server rack and one of those VMs is a dedicated Tailscale peer relay VM. In addition, I port forward port 40000 (the default port) on the WAN interface of my router. This should ensure I will never have a bad connection to my NAS.

However, here I was with a bad connection to my NAS. Thus begins the troubleshooting adventure:

Refusing to relay

The obvious place to start was to run tailscale status which immediately showed that indeed, the peer relay was not being used. My traffic was being routed through a DERP server in Paris.

The next step was to try and get a bit more information via tailscale netcheck:

* UDP: true
* IPv4: yes
* MappingVariesByDestIP: true
* PortMapping:
* Nearest DERP: Paris

The field we are really looking for here is MappingVariesByDestIP: true. What this means is that the DERP servers are receiving traffic from us from different IPs and ports. Every time we made an outbound connection the public port assigned to the laptop was changing depending on the destination. That explains why I couldn’t make a direct, peer-to-peer connection, but why couldn’t I use the relay?

Getting tricked

From here, I started poking at the debug options for the Tailscale CLI and stumbled into peer-relay-servers which will “Print the current set of candidate peer relay servers”. Excellent! What’s in there?

[]

…oh. Nothing. That is probably why I’m not getting peer relay connections. This took me down a rabbit hole looking into how the policies and authorizations are configured for peer relays.

The src field in a peer relay grant is easy to misread. It describes the stable resources that should be accessible through the relay, not necessarily the roaming laptop initiating the connection.

After fiddling with this for a while, I decided to change gears and connect to my phone as a hotspot and see what I got. Turns out:

nick@laptop ~ % tailscale status
100.132.214.101  nas                 tagged-devices  linux    active; peer-relay X.X.X.X:40000:vni:5484, tx 7508844 rx 11256008
nick@laptop ~ % tailscale debug peer-relay-servers
[]

So even though the set of candidate peer relay servers was empty, I was indeed using a peer relay. I’m not sure whether that was a bug or whether I was looking at the wrong signal, but I was certainly pulling my (nonexistent) hair out at this point.

While this rabbit hole didn’t solve my problem, it did reinforce my initial assumption. My configuration was totally fine and working. It was the hotel network that was the problem.

Hostile network

At this point I was confident the control plane was fine. I now needed to figure out what was happening on the wire. I booted up tcpdump on the relay and sent some packets with netcat (not to be confused with Datadog):

printf test | nc -u -w1 X.X.X.X 40000
$ sudo tcpdump -ni any 'udp dst port 40000'
0 packets captured

Okay! That’s progress! The relay wasn’t receiving my UDP traffic on port 40000! We now know the port forwarding, relay host firewall, and relay listener were not the problem. The packet was being dropped somewhere on the current network path.

This led me to try a variety of UDP ports (along with the associated port forwarding rules). What I found was that the overwhelming majority where blocked, including some that would break services like STUN or regular WireGuard.

UDP 40000  blocked
UDP 40001  blocked
UDP 51820  blocked
UDP 1010   blocked
UDP 3123   blocked
UDP 3478   blocked
UDP 1194   reachable

For whatever reason, 1194 (commonly associated with OpenVPN) was allowed outbound on the hotel network. This meant with a simple config change, I was able to have the relay listen on that port, update the port forwarding rule, and instantly I had a peer relay connection back home! Magnifique!

$ tailscale debug force-netmap-update
$ tailscale ping nas
pong from nas via DERP(tor) in 114ms
pong from nas via DERP(tor) in 114ms
pong from nas via DERP(tor) in 114ms
pong from nas via peer-relay(X.X.X.X:1194:vni:6) in 109ms
pong from nas via peer-relay(X.X.X.X:1194:vni:6) in 109ms

Building a more robust system

While I was happy this worked, I wanted to make sure I didn’t run into this problem again in the future. Sure, 1194 works on this network, but what if it’s blocked in the future? Was there a way I could have the relay listen on two different ports at the same time? As it turns out, no you can’t do that, but you can achieve something similar.

From reading the docs I found tailscale set --relay-server-static-endpoints. This allows you to, “specify one or more additional static endpoints for the peer relay to advertise to other tailnet devices. Doing so is useful in network environments where users use port forwarding or users use load balancers”. This flag lets you specify a list of IP and port combinations to advertise to clients so they can connect. If a client tries to connect to one port and it fails, it will move on to the next. Simply port forward multiple ports on your WAN to the one relay port.

By configuring this, and configuring two or more port forwarding rules on your router, you can have multiple options for your clients to connect to. Hopefully protecting you from hostile hotel Wi-Fi networks.

Conclusion

Having run into this and the frustration of trying to track it down, if you’re a Tailscale user and have a peer relay running on your home network, I encourage you to open more ports than just the default 40000. It may save you a headache down the road.