Obfuscating Wireguard: hide VPN traffic with Shadowsocks

Use Shadowsocks to obfuscate Wireguard traffic and bypass firewalls.

Obfuscating Wireguard: hide VPN traffic with Shadowsocks
Security of VPN, now with plausible deniability.

Wireguard is probably one of the most important network innovations that has blessed Linux (and everything else) in recent years. Its predecessor, OpenVPN, is slow and cumbersome to configure and use. Wireguard, on the other hand, utilizes a faster crypto algorithm and only relies on common Linux networking tools. Moreover, it can be (and already is!) deployed everywhere! For example, cloudflare warp is pure Wireguard.

So, if Wireguard is so good, why not just use it on all your devices? You can forget about leaking your IP addresses or being DDoSed ever! The problem is, despite all of Wireguard's goodies, there is one minor issue:

⁉️
What if you don't want anyone else to know you're using a VPN?

Say you don't want your ISP to figure out that you are using a VPN for some reason. Maybe your ISP throttles VPN traffic. Perhaps they forbid users from using one in the first place due to shitty local regulations. In this case, Wireguard alone is not adequate enough to hide your traffic.

Wireguard traffic: Easily identifiable?

Sometimes, my Wireguard traffic will get disconnected when I attempted to use it over college WiFi. At first I thought that the VPN server was broken and spent hours debugging it. While in fact, the school firewall detected my VPN connection and dropped it (I have no idea why).

Believe it or not, hiding its own traffic, or "obfuscating", is not the focus point of Wireguard. Its website specifically stated that "Obfuscation should happen at a layer above Wireguard". It is kind of counter-intuitive, as it shouldn't be hard to just implement obfuscation in the Wireguard protocol in the first place, given it uses chacha20-poly1305 cipher. On contrast,

💡
It is trivially easy to identify and filter Wireguard traffic.

The network tool Wireshark already has Wireguard identification support in its source code for a long time. If anyone with Wireshark can do it, it is not hard to imagine your corporate or school network intentionally filtering out Wireguard VPN traffic (GFW wink wink).

For residential ISPs, they seldom filter out VPN traffic intentionally. But that does not stop them from deliberately slowing down Wireguard traffic with all those UDP traffic de-prioritization crap.

Moreover, isn't it better if the ISP does not know you are using a VPN at all?

Great, how to hide my Wireguard traffic?

With some help from our old friend: shadowsocks. According to its front page,

💡
Shadowsocks is a lightweight proxy.

However, this lightweight proxy supports tunneling TCP and UDP traffic, with AEAD ciphers for extra confidentiality. It is perfect for hiding our Wireguard UDP traffic, and from my personal experience, is proven to circumvent the strongest censorship currently possible.

Installing Shadowsocks

If your server runs Debian or Ubuntu,

sudo apt install shadowsocks-libev

If your servers runs Arch Linux or Manjaro,

sudo pacman -S shadowsocks-libev

Using the same procedure as before, install shadowsocks on your local computer. If your computer runs macOS,

brew install shadowsocks-libev

Run Shadowsocks on your server

After installing it, create shadowsocks server's config file with the following content, and name it as wg-tun.json.

{
    "server": "0.0.0.0",
    "server_port": <desired port>,
    "password": "<desired password>",
    "timeout": 300,
    "method": "chacha20-ietf-poly1305",
    "mode": "tcp_and_udp"
}

Here, <desired port> is the server port listened by shadowsocks. <desired password> is a secret password for authenticating shadowsocks connections. It's basically a second password.

Then, run shadowsocks server on your Wireguard server by executing

ss-server -c wg-tun.json

Tunnel Wireguard

Create shadowsocks tunnel's config file on your local computer with the following content as wg-tun.json.

{
  "server": "<Wireguard server's IP address>",
  "server_port": <server port>,
  "local_address": "0.0.0.0",
  "local_port": 5634,
  "password": "<server password>",
  "timeout": 300,
  "method": "chacha20-ietf-poly1305",
  "mode": "tcp_and_udp",
  "tunnel_address": "127.0.0.1:<Wireguard server's port>"
}

Here, <server port> and <server password> are from last step.

<Wireguard server's IP address> is your shadowsocks server's IP. Since we are hosting Wireguard and shadowsocks on the same server, they should be identical.

<Wireguard server's port> is ListenPort of Wireguard server.

Then, run shadowsocks tunnel on your local computer by executing

ss-tunnel -c wg-tun.json

Configure Wireguard to use the tunnel

Open your Wireguard client's config.

In section [Peer], change value of entry Endpoint into 127.0.0.1:5634, the local Wireguard endpoint tunneled through shadowsocks. Your configuration file should look similar to this:

[Peer]
PublicKey = <your pubkey>
AllowedIPs = ::/0, 0.0.0.0/0
Endpoint = 127.0.0.1:5634

sample Wireguard config

Restart your Wireguard client. Now all your Wireguard traffic are hidden from ISPs!

My Wireguard still gets randomly disconnected

Well, we only hid the fact that you are using Wireguard. Even after shadowsocks, your VPN tunnel still uses UDP. It is possible that your network unconditionally filters out UDP traffic for unethical reasons such as "UDP stresses the network out" or "preventing abuse".

It is technically still solvable. There are plenty of ways to fake a TCP connection from UDP packets. However, that topic is for another article. For hiding your VPN traffic from the ISP alone, shadowsocks is more than good enough.