WireGuard + Shadowsocks
WireGuard is a popular new VPN protocol. A known limitation of WireGuard is that it is vulnerable to deep packet inspection. Combining WireGuard with Shadowsocks obfuscates the WireGuard protocol.
In this tutorial, WireGuard and Shadowsocks are implemented on an Ubuntu Linux server and an Ubuntu Linux client. The client is assumed to be at IP address
11.11.11.11
, and the server is assumed to be at IP address 22.22.22.22
. We will use port 1433
for Shadowsocks and port
51820
for WireGuard.
We assume that you SSH into the server as root
but use a non-root username with sudo permissions on the client.
1. Server
1.1. Update Server
Before you do anything else, get your server completely up to date:
apt update && apt upgrade -y
1.2. Configure Firewall
We are going to use port 1433
for the Shadowsocks server. Although we use port 51820
for the WireGuard server, this port can be kept
closed to the public, since that will better camouflage your server.
Here are some sample iptables rules for IPv4. In this example, SSH is confined to a single IP address, which is 11.11.11.11
in the example. Replace
11.11.11.11
by the actual IP address of your workstation.
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 11.11.11.11/32 -j ACCEPT
iptables -A INPUT -p udp --dport 1433 -j ACCEPT
iptables -P INPUT DROP
Here are some sample rules for IPv6. Note that in our example, we assume you always use IPv4 for SSH, so the firewall is not open for SSH input over IPv6:
ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -p icmpv6 -j ACCEPT
ip6tables -A INPUT -p udp --dport 1433 -j ACCEPT
ip6tables -P INPUT DROP
To persist these rules across reboots, install the package iptables-persistent:
apt install iptables-persistent -y
1.3. Install WireGuard
Install WireGuard using the script and instructions from https://github.com/angristan/wireguard-install:
apt install curl -y
curl -O https://raw.githubusercontent.com/angristan/wireguard-install/master/wireguard-install.sh
chmod +x wireguard-install.sh
./wireguard-install.sh
You can accept the defaults all the way through the script’s questions, except specify the server’s WireGuard port as 51820
.
When prompted for the name of the first client, call it wgss
. This causes the script to create a client configuration file named
wg0-client-wgss.conf
.
The server configuration is placed in /etc/wireguard/wg0.conf
. You can check the status of the systemd service with the command:
systemctl status wg-quick@wg0
It should read active (exited)
.
Press the q key on your computer keyboard to quit the status display.
1.4. Install Shadowsocks
Install shadowsocks-libev
from the repositories:
sudo apt install shadowsocks-libev
1.5. Generate Password for Shadowsocks
Generate a 192-bit password, expressed as 32 base-64 characters, with the command:
openssl rand -base64 24
We will use the example:
C3WOo2qwJCJaiJpe9DY4pGBUC/WGMDxx
In what follows, replace the example with your own generated password.
1.6. Configure Shadowsocks
Edit your Shadowsocks server configuration file:
vi /etc/shadowsocks-libev/config.json
Delete the existing contents, and insert contents as follows:
{ "server": "0.0.0.0", "server_port": 1433, "password": "C3WOo2qwJCJaiJpe9DY4pGBUC/WGMDxx", "timeout": 300, "method": "chacha20-ietf-poly1305", "mode": "udp_only" }
Replace C3WOo2qwJCJaiJpe9DY4pGBUC/WGMDxx
by your actual password.
Write the file to disk. Quit the editor.
1.7. Run Shadowsocks
The Shadowsocks systemd service is already running. Restart the service with your new configuration file:
systemctl restart shadowsocks-libev
Exit your SSH session with the server:
exit
2. Client
2.1. Update Client
Before you do anything else, get your client completely up to date:
sudo apt update && sudo apt upgrade -y
2.2. Install Shadowsocks
Install shadowsocks-libev
from the repositories:
sudo apt install shadowsocks-libev
2.3. Configure Shadowsocks
Edit your Shadowsocks client configuration file:
sudo vi /etc/shadowsocks-libev/config.json
Delete the contents, and insert new contents as follows:
{ "server": "22.22.22.22", "server_port": 1433, "local_address": "127.0.0.1", "local_port": 1080, "password": "C3WOo2qwJCJaiJpe9DY4pGBUC/WGMDxx", "timeout": 300, "method": "chacha20-ietf-poly1305", "mode": "udp_only", "tunnel_address": "127.0.0.1:51820" }
Replace 22.22.22.22
by the actual IP address of your server. Replace C3WOo2qwJCJaiJpe9DY4pGBUC/WGMDxx
by your actual password.
Write the file to disk. Quit the editor.
Edit the systemd service file:
sudo vi /usr/lib/systemd/system/shadowsocks-libev.service
Change the binary from ss-server
to ss-tunnel
:
ExecStart=/usr/bin/ss-tunnel -c $CONFFILE $DAEMON_ARGS
Write the file to disk. Quit the editor.
Reload systemd:
sudo systemctl daemon-reload
2.4. Run Shadowsocks
Shadowsocks systemd service is already running. Restart it with your new service file and configuration file:
sudo systemctl restart shadowsocks-libev
2.5. Install WireGuard
Install WireGuard on the client:
sudo apt install wireguard resolvconf -y
2.6. Configure WireGuard
Download the WireGuard client configuration file from the server.
cd ~/Downloads
scp root@22.22.22.22:wg0-client-wgss.conf .
Replace 22.22.22.22
in the above command by your actual server IP address.
Copy the configuration file into place:
sudo cp wg0-client-wgss.conf /etc/wireguard/wg0.conf
Edit the WireGuard client configuration file:
sudo vi /etc/wireguard/wg0.conf
Shadowsocks will take care of forwarding packets to the real server IP address. Therefore change the endpoint of the peer to be localhost port 1080, which is where Shadowsocks expects its input.
Here is a sample client configuration file after changes:
[Interface] PrivateKey = kNBDeCk8Nz4ir2qsFd88QthH8CyCPOqS6x1z596MNGA= Address = 10.66.66.2/32,fd42:42:42::2/128 DNS = 94.140.14.14,94.140.15.15 [Peer] PublicKey = q+z9MX5ii/YaSivcFim4mXA1zPpopPTSt7YEAyK6s1o= PresharedKey = Sj+DR9NR0FbXOFC8ht9sITdnEzSEhrjvts0ljZarEtA= Endpoint = 127.0.0.1:1080 AllowedIPs = 0.0.0.0/0,::/0
If your client does not support IPv6, remove the IPv6 addresses (fd42:42:42::2/128
and ::/0
).
Write the file to disk. Quit the editor.
2.7 Add Static Route
Add a static route from the client to the server, so that it does not try to send WireGuard traffic via Shadowsocks, then Shadowsocks via WireGuard, in a continuous
and never-ending loop. For example, if your default gateway is 192.168.1.1
and your interface is wlp3s0
:
sudo ip route add 22.22.22.22 via 192.168.1.1 dev wlp3s0
Replace 22.22.22.22
in the above by your actual server IP address. Replace 192.168.1.1
and wlp3s0
by your actual default
gateway. If you do not know your default gateway already, you can obtain it by issuing the command ip r
.
2.8. Run WireGuard
sudo wg-quick up wg0
You can test your connection by visiting https://whatismyipaddress.com in Firefox.
2.9. Disconnect
Stop WireGuard:
sudo wg-quick down wg0
Stop Shadowsocks:
sudo systemctl stop shadowsocks-libev
Delete the static route:
sudo ip route del 22.22.22.22 via 192.168.1.1 dev wlp3s0
Replace 22.22.22.22
in the above by your actual server IP address. Replace 192.168.1.1
and wlp3s0
by your actual default
gateway.
3. Get Help and Report Issues
For WireGuard, the best place to get help is the #wireguard
IRC channel on libera.chat.
For Shadowsocks issues, see the GitHub issues page.
Updated 2022-02-08