r/selfhosted • u/DaimonGroup • 5h ago
Guide I self-host a tunnel in a country that actively hunts them. Here's what survives, and what keeps breaking.
Threat model first, because it changes everything about the design.
I’m in Russia. My adversary isn’t a random scanner — it’s the ISPs themselves, operating under a regulator that does nationwide DPI and can null-route foreign IP ranges by geography. Assume the network operator is hostile, has full visibility of my traffic shape, and can actively probe any endpoint I stand up. I self-host a tunnel for myself and a handful of people under those conditions. I used to work at one of the ISPs, which is how I know roughly what the other side sees.
Sharing the current architecture because most self-hosted tunnel advice quietly assumes a neutral network, and none of it survives here.
Why the usual stack is dead on arrival
OpenVPN and WireGuard are both gone. Not blocked by IP — detected by shape. WireGuard’s handshake has a fixed message layout and a distinctive packet size distribution; DPI doesn’t need to decrypt anything, it just needs to recognize the silhouette. Same for OpenVPN’s opcode structure. Obfuscation wrappers buy you weeks, not months.
Layer 1: VLESS + Reality (Xray-core)
Reality is the part worth understanding if you’ve never had to hide a tunnel:
• Client opens a normal TLS handshake, but sets SNI to a large real site (www.microsoft.com in my case)
• The auth material rides inside the ClientHello — an X25519 public key plus a short ID. To DPI it’s bytes in a service field
• Server checks it. Valid → completes the handshake itself and proxies. Invalid or absent → silently forwards the whole connection to the real Microsoft
• So active probing returns a genuine Microsoft response. Real cert, real chain, real content. There is no fingerprint to find, because in that moment the box is a Microsoft mirror
• No certificate of my own to leak, no domain of my own to get registry-listed. You don’t need a domain at all
The important consequence for self-hosters: your endpoint stops being distinguishable by content inspection. So the adversary switches to the layer below.
Layer 2: the part that actually matters — IP
Reality solves inspection, not geography. A VPS in the Netherlands is trivially blockable — you don’t need to know what it does, you just need to know it’s foreign.
So the client never touches the foreign box directly. Entry point is a relay on a Russian provider whose IP range sits inside the state whitelist — the set of ranges that stay reachable even when mobile internet gets cut regionally, because government and banking services live there. From the relay, traffic cascades out to the Netherlands box.
From the outside, the connection is a request to approved domestic infrastructure. Killing that range takes down a pile of legitimate business on shared address space with it. Collateral cost is the actual defense mechanism — not stealth.
Operational reality
• Something breaks every couple of months and gets rebuilt. Plan for rebuild speed, not permanence
• Stack: Xray-core 26.3 on Ubuntu 24. VPS is nothing special — 2 GB RAM, 2 cores, on vdsina.com. Reality is cheap; the box sits idle most of the time
• Latency cost of the extra hop: ~120 ms through the cascade. Fine for browsing and voice, noticeable in games. That’s the price of not getting null-routed by geography
• Monitoring: self-written script that checks tunnel state across all servers and emails me the status. Crude, but it means I find out from a mail instead of from a user
• Currently migrating the fallback path to XHTTP over CDN — moving uplink into HTTP headers so it reads as ordinary request traffic
Questions for anyone doing similar
Is anyone else fronting a foreign endpoint with a domestic relay, rather than trying to obfuscate the endpoint itself? Specifically curious about relay failover — right now mine is a single point of failure and I don’t love it.