Tailscale works hard to do all this stuff automatically.
Possibly you'd have more luck on a network where your client can allow incoming UDP connections on the Tailscale port, and so the exit node would be able to establish a direct connection.
But for a Tailscale peer I have running on AWS ECS, I can open the UDP port there, so a direct connection always happens regardless of what sort of network my Tailscale clients are on. I don't know if there's any Fly equivalent to get a direct connection to a UDP port.
Yes, fly.io allows you to expose a UDP port. See the fly.toml [1] in the repo. Make sure the tailscale port is pinned [2] to the exposed port (41641 in that case).
I just tested it again and the connections are made directly (after the first 2,3 packages go via DERP):
tailscale ping fly-ams
pong from fly-ams (100.96.123.32) via DERP(ams) in 15ms
pong from fly-ams (100.96.123.32) via [2604:1380:4601:d605:0:6c3b:eed5:1]:41641 in 12ms
tailscale status
100.96.123.32 fly-ams patte@ linux active; offers exit node; direct [2604:1380:4601:d605:0:6c3b:eed5:1]:41641
100.101.54.36 fly-hkg patte@ linux active; offers exit node; direct [2605:4c40:95:4eed:0:40f0:67b1:1]:41641
Possibly you'd have more luck on a network where your client can allow incoming UDP connections on the Tailscale port, and so the exit node would be able to establish a direct connection.
But for a Tailscale peer I have running on AWS ECS, I can open the UDP port there, so a direct connection always happens regardless of what sort of network my Tailscale clients are on. I don't know if there's any Fly equivalent to get a direct connection to a UDP port.