SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor

What to run when your VPN gets blocked

Your VPN is blocked because its handshake is recognisable. What Outline, obfs4 and WebTunnel change about the bytes, and what they cannot hide.

Why your VPN is blocked

Your VPN is blocked, on most networks that block one, because its handshake is recognisable. A device on the path reads the first packet of each new flow and compares it against a list of protocol fingerprints. Flows it does not want are dropped or reset. Moving to a different port changes nothing, because the match is on the bytes and not on the port number. Changing what those bytes look like is the fix, and it works until the address of your server lands on a blocklist of its own.

The device doing the matching is a middlebox: anything in the path that inspects traffic instead of only forwarding it. The technique is DPI (deep packet inspection). A DPI rule is cheap to run when a protocol has a fixed shape at the start of every connection, and expensive when every connection opens with bytes that look random. That gap is what every transport below is working on.

Three families of answer exist. Shadowsocks-style obfuscation, which is what Outline ships, removes the fixed shape. obfs4, the Tor bridge transport, removes the fixed shape and also refuses to answer a scanner that does not already hold its key. WebTunnel and the other TLS-shaped transports go the other way, and produce traffic that matches a protocol the network already allows.

What does a plain WireGuard tunnel look like on the wire?

WireGuard has the simplest fingerprint of the group. A handshake initiation is a UDP datagram of exactly 148 bytes. The first byte is 0x01, the message type, and the next three are reserved bytes that are always zero. The handshake response is exactly 92 bytes and begins 0x02. Those sizes are fixed by the protocol, because every field in those messages is fixed width. A rule that reads "UDP payload of 148 bytes starting 01 00 00 00" costs a middlebox almost nothing to evaluate and matches almost nothing else.

There is nothing to tune. WireGuard has no padding option and no cover traffic. The cryptokey routing model that makes it small and fast is the same design that makes it easy to identify. Everything below assumes you know what a healthy tunnel looks like, so start from a WireGuard server on your own VPS if you have not run one.

OpenVPN does no better. Its control packets carry a five-bit opcode in the first byte, and the client's first packet is always a hard reset, so that byte takes one of a small set of values. tls-crypt encrypts the control channel payload, which hides the TLS (transport layer security) handshake carried inside it, and leaves that header byte in cleartext. Work presented at USENIX Security in 2022 identified OpenVPN flows from the opcode pattern and the shape of the first exchange, including flows using the XOR patches that some vendors sell as stealth. The wider WireGuard and OpenVPN comparison covers the rest of the trade. On this one axis they fail in the same way.

What does Outline change about the bytes?

Outline is Jigsaw's packaging of shadowsocks, and its server component outline-ss-server speaks shadowsocks with AEAD (authenticated encryption with associated data) ciphers such as chacha20-ietf-poly1305. A shadowsocks connection has no handshake. The client opens a TCP connection, writes a random salt, and then writes length-prefixed encrypted chunks. There is no version field, no cipher list, no server name and no fixed length anywhere in that. A fingerprint matcher has nothing to key on.

That pushes the network's cheapest attack up to two harder ones. The first is statistical. Packet sizes and inter-arrival timing are still visible, and a stream that is random from byte zero is itself unusual, because most protocols open with something structured. The second is active probing: the network replays bytes it watched you send, or sends its own garbage, and reads how your server reacts. A server that resets on bad input behaves differently from one that stays open and silent, and either behaviour can become the signature. outline-ss-server takes a --replay_history flag that remembers recent connections and rejects replayed ones, which closes the replay half of that.

Install it from the Outline VPN server install guide rather than from here. The decisions that determine whether it keeps working are about the machine you put it on, and they come further down.

What do obfs4 bridges do differently?

obfs4 is a pluggable transport for Tor. Like shadowsocks it is a look-like-nothing design, and its wire bytes carry no structure to match. It adds two things worth understanding even if you never run Tor.

The first is that the obfuscation is authenticated. obfs4 runs Tor's ntor handshake with the public keys hidden by an Elligator 2 mapping, so the key material on the wire has no recognisable form. The client must already know the bridge's node identity and public key, and both arrive packed into the cert= value of the bridge line you paste into the client. A scanner that finds the port open and connects without that value cannot build a valid first message, and the bridge answers with nothing. Scanning an address range therefore does not confirm that an address is a bridge, which is the property a plain proxy lacks.

The second is timing. The iat-mode parameter in the same bridge line controls whether obfs4 splits its writes to blur the gaps between packets. It costs throughput, so it ships off by default. Turning it on is a deliberate trade of speed for a weaker timing signal.

obfs4 carries Tor, so you inherit Tor's routing and Tor's latency with it. The difference between Tor and a VPN is a difference in who gets to see what, and that is what decides which of the two you want here. If it is the bridge you want, running a bridge with pluggable transports is its own setup job.

Can traffic that looks like ordinary TLS get through?

The third family stops hiding and starts blending in. The reason is allowlists. A network that permits only the protocols it recognises drops random-looking bytes by default, so look-like-nothing fails there while look-like-HTTPS passes.

WebTunnel is the Tor Project's current version of this idea. Its documentation describes it as a transport "designed to mimic encrypted web traffic (HTTPS)", which it does by "wrapping the payload connection into a WebSocket-like HTTPS connection". The property that matters to a server operator is that it "can coexist with a website on the same network endpoint, meaning the same domain, IP address, and port". A reverse proxy routes one URL path to the tunnel and every other path to a real site. From outside, the address serves a website, because it does serve a website.

That coexistence is doing the work. A service on port 443 that is not TLS is itself a signal on a network that checks, so the disguise is only as good as the thing it imitates. A self-signed certificate breaks it. So does a domain registered last week with no other traffic on it. Published work has also shown that a TLS session carried inside another TLS session leaves a recognisable pattern in record sizes and timing, so this family is not free either.

Domain fronting, used by the older meek transports, is history now. It worked by naming a large cloud provider's hostname in the TLS SNI (server name indication) field while the encrypted HTTP request named the real destination. The major cloud providers turned that behaviour off from 2018 onward.

What none of these transports hide

Every design above answers one question: what protocol is this. State the rest plainly, because the gap between what obfuscation does and what people assume it does is where the real risk sits.

  • They hide the protocol from a device in the path. That is the entire claim.
  • They do not hide you from the endpoint. Your server terminates the tunnel and sees every address you connect to. Self-hosting means the operator is you, which is the good half of the difference between renting a VPS and buying a VPN subscription. The other half is that a server with one user makes every flow leaving it attributable to that user.
  • They do not hide that you are talking to that address. The network still records a flow between your address and your server's, with its byte counts and its timing. Obfuscation changes what the flow looks like, not that it happened.
  • A burned address stays burned. When an address is on a blocklist the drop happens before any byte of your new transport is read, so moving from WireGuard to Outline on that same address changes nothing.

Why the server side decides whether this works

Run the server in a jurisdiction that is not the one doing the blocking. The tunnel exits at your server, so the server's country is where your traffic appears to come from, and its provider is who receives any abuse complaint. Read that provider's acceptable use policy before you build, because an account suspension burns the address just as thoroughly as a filter does.

Give the endpoint an address of its own and run one service on it. If it shares an address with your personal site, two things go wrong at once. The site disappears the moment the address is blocked. And anyone who has the address can read the site and work out who runs the endpoint.

A recycled address fails fastest. An IPv4 address at a hosting provider has a history you cannot see: it may have carried a public proxy or sent spam before it reached you. Test it before you spend an evening on it. Boot the server, then try to reach it from the network you care about. A freshly booted address that is already unreachable from there was on a list before you got it, and the answer is a different address rather than a different transport.

Keep the number of people holding a key small. A key shared with two hundred people reaches whoever maintains the blocklist sooner than a key shared with five, and the address goes with it. Outline issues a separate access key per user on one port, so you can revoke one person without disturbing anyone else.

Plan the replacement address before you need it. That means a way to deliver new keys that does not itself depend on the tunnel, and a deployment you can repeat in minutes on a fresh machine instead of rebuilding from memory.

Pick the port on the same logic as the transport. 443/TCP is the least surprising destination on the internet. UDP 443 is ordinary now too, because QUIC (quick UDP internet connections) carries a large share of web traffic. A fixed-size datagram arriving on a high random UDP port is the opposite of ordinary.

Is it blocking, or is it MTU or DNS?

These faults look similar from the client, and people reach for the transport first when the cause is usually simpler. One test separates them. Run a capture on the server while the client tries to connect.

sudo tcpdump -ni any udp port 51820

Packets arriving from the client's address while the client reports failure means nothing on the path is dropping them, so the fault is in your configuration. No packets at all while the client keeps retrying means they are dropped before they reach you. That takes ten seconds, and it tells you which half of the problem you are in.

Blocking shows up as the same client with the same configuration working on one network and failing on another. Use a phone on mobile data as the second network. A TCP connection that completes its handshake and then receives a RST (a TCP reset) after a few hundred bytes points at inspection, because a firewall rule that did not want the connection would have refused the handshake instead. A tunnel that runs for thirty seconds and then stops, every time, on one network is a third pattern again.

MTU (maximum transmission unit) shows up as a tunnel that comes up and then stalls only on large transfers. Interactive traffic is fine while big pages hang. Test the path size directly.

ping -M do -s 1372 -c 3 1.1.1.1

-M do sets the do-not-fragment bit and -s sets the payload size, so 1372 bytes plus 28 bytes of IP and ICMP headers probes a 1400-byte path. Message too long, or a Frag needed and DF set reply, means the path cannot carry that size, and you bisect downward until it passes. Finding the real path MTU and clamping TCP MSS does this properly. It is a path problem and it has nothing to do with filtering.

DNS (domain name system) shows up as ping 1.1.1.1 succeeding inside the tunnel while curl https://example.com returns Could not resolve host.

dig +short example.com @1.1.1.1

An answer there while your ordinary lookups fail means the resolver your client was handed is unreachable through the tunnel, or is answering wrongly. DNS that breaks the moment the tunnel comes up covers the resolver side. Rule it out before you conclude anything about blocking.

The order to run these tests in
  1. On the server, run sudo tcpdump -ni any udp port 51820, or tcp port 443 for a TCP transport, while the client tries to connect.
  2. From the client, run nc -vz your.server.example 443. A refused connection means the server is not listening. A hang with no answer means something in the path is dropping the packets.
  3. Repeat step 2 from a second network, such as a phone on mobile data. Working there and failing here is blocking.
  4. Once a tunnel comes up, test size with ping -M do -s 1372 -c 3 1.1.1.1 and names with dig +short example.com @1.1.1.1 before you touch the transport at all.

Obfuscation buys one thing and it buys it well: a middlebox that cannot tell which protocol you are speaking has to guess. Everything else is ordinary server engineering. A clean address, a jurisdiction that suits you, one service on the machine, and a plan for the day the address stops working.

FAQ

Why does changing the port not unblock my VPN?

Because the block matches the bytes and not the port number. A WireGuard handshake initiation is a UDP datagram of exactly 148 bytes beginning 0x01 0x00 0x00 0x00, and that pattern is identical on port 51820 and on port 443. Moving the listener helps only when the network is blocking the port itself. Run sudo tcpdump -ni any udp port 51820 on the server while a client tries: if the client's packets reach the server on the original port, the port was never the problem.

Does obfuscation hide me from the server I connect to?

No. Shadowsocks, obfs4 and WebTunnel all change what the traffic looks like to devices between you and the server. The server terminates the tunnel, decrypts your traffic and sees every address you visit, exactly as before. That is the argument for running the endpoint yourself rather than buying a subscription. It also means a server with a single user makes every flow leaving it attributable to that user, so obfuscation and anonymity are separate properties.

My server's address is blocked. Is switching transport worth trying?

Usually not on that address. An address-based block drops the packet before anything reads its contents, so a new transport has nothing left to change. The test is cheap: try any service at all on that address from the affected network, such as an ordinary web page on port 443. If nothing reaches it, get a new address. Switching transport is what you do when the address is reachable and only the tunnel protocol fails.

How do I tell a block apart from an MTU problem?

An MTU fault lets the tunnel come up. Handshakes complete, small requests work, and only large transfers stall. A block usually stops the connection from establishing at all, or resets it shortly after it starts. Confirm the MTU case from inside the tunnel with ping -M do -s 1372 -c 3 1.1.1.1. A Message too long result means the path cannot carry that packet size, which is a routing property rather than a filter.