Your anti-DDoS provider is eating your VPN — and QUIC is hiding it
Two failure modes that look like "the server is broken" but aren't. One is your hosting provider silently scrubbing UDP. The other is Google refusing to fall back from QUIC. Both are one line to fix once you can see them.
Failure #1 — inbound UDP that never arrives
You stand up a WireGuard / AmneziaWG server on a DDoS-protected host. The daemon is listening. The keys are right. Clients time out. Meanwhile the same box happily joins your mesh as a client and passes traffic all day.
That contradiction is the whole clue. Many scrubbing providers pass outbound-initiated flows (your node dialing out to a hub keeps a NAT mapping open) but drop unsolicited inbound UDP to your listen port. So:
- The node works as a mesh spoke — it dials out, replies come back on the open flow.
- The node fails as a VPN server — clients' fresh inbound handshakes get scrubbed before your daemon ever sees them.
How to confirm it (without lying to yourself)
Do not trust a single nc -u probe — a garbage datagram is not a valid handshake and gets dropped for unrelated reasons, giving false "blocked" readings even on a working host. Instead:
- Open a real listener on a candidate port and hit it end-to-end (
python3 -m http.serverover TCP returns200? then the port is not provider-blocked). - Compare inbound-initiated vs outbound-initiated: if outbound works and only inbound dies, it's scrubbing, not your config.
The fixes
- Relay through a clean-IP node. Terminate the client-facing UDP on a host the provider doesn't scrub, forward it over your established mesh to the spoke. Camouflage the public port as something expected (
udp/443looks like QUIC). - Or switch transport to TCP. If UDP is hopeless on that provider, a TCP-based transport (VLESS over XHTTP, for instance) sidesteps the whole UDP-scrubbing problem — provided you find a port the provider forwards (test with a real listener, don't assume).
The host isn't broken. The network in front of it has opinions. Diagnose the path, not just the daemon.
Failure #2 — Google/AI apps hang over a working tunnel
Now the tunnel is up and general browsing works — but Gemini, Google, YouTube stall or won't load. The exit node itself reaches them fine (curl to the API returns a normal 400 "API key not valid"; the web endpoints return 200). So why does the client hang?
QUIC. Google's clients try HTTP/3 over QUIC (UDP/443) first. Through a proxy tunnel that QUIC path often can't complete, and the app sits there instead of cleanly falling back to TCP/HTTP2.
The one-line fix — block QUIC egress, force the fallback
Reject UDP/443 on the exit so clients drop to TCP immediately. In an Xray-style router:
"routing": { "rules": [
{ "type": "field", "network": "udp", "port": 443, "outboundTag": "block" }
]}
In a Hysteria2 ACL:
acl:
inline:
- reject(all, udp/443)
- direct(all)
Restart, reconnect. Google and Gemini load over TCP, which the tunnel carries reliably. It's counter-intuitive — you fix "can't reach Google" by blocking a Google protocol — but forcing the well-behaved fallback is exactly the point.
Takeaway
Both bugs share a shape: the endpoint is healthy, the transport assumptions are wrong. UDP you assumed would arrive gets scrubbed; QUIC you assumed would fall back doesn't. Production networking is mostly this — the daemon is fine, the path has a personality, and the fix is to stop assuming and start measuring end-to-end.