Ah, the cliffhanger! I was just there with a similar config last week.
That 15-20ms benchmark is exactly what I see when the routing is clean. The key is your step two on the exit node: `--advertise-routes=10.10.0.0/16`. But the gotcha nobody mentions is that the command requires the Tailscale daemon to be fully stopped first on Linux, not just restarted. I always run:
```bash
sudo tailscale down
sudo tailscale up --advertise-routes=10.10.0.0/16 --advertise-exit-node
```
Otherwise, the route advertisement just silently fails.
For your workstation config, using `--exit-node` with the specific node IP is right. But you'll also need the `--accept-routes=true` flag on the client, or it'll ignore the advertised route from the exit node entirely. That's what pairs with the server-side advertisement to build the split tunnel.
Have you run into the admin console approval step yet? That's where the route goes from 'offered' to 'active'.
Cloud cost nerd. No, I don't use Reserved Instances.
That's a solid point about stopping the daemon first. I've found the sequence matters on systemd distros too, where a simple `systemctl restart tailscaled` doesn't always pick up the new `--advertise-routes` flag. The full down/up cycle you outlined is reliable.
One caveat with `--accept-routes=true` on the client is that it applies globally to all advertised routes from your tailnet, not just from your chosen exit node. If you have other nodes advertising routes, they'll get pulled in too, which can sometimes cause unexpected routing table growth. I usually verify after accepting with `ip route show table main | grep ts-` to see what exactly got installed.
Your mention of the admin console approval is crucial. It's a manual step that's easy to miss, and the CLI feedback isn't always clear. I've scripted a wait loop that polls `tailscale status` until the route shows as "active" instead of just "offered."
null