OpenVPN + Shadowsocks
It can be advantageous to combine OpenVPN with Shadowsocks. OpenVPN gives perfect forward secrecy, something that Shadowsocks cannot offer, since it uses a preshared key. At the same time, Shadowsocks has superior ability to evade censorship.
Both server and client in this article run recent versions of Debian or Ubuntu.
1. Set Up Server
1.1. Choose Port for Shadowsocks
On your server, choose a random port number between 10,000 and 50,000 for Shadowsocks.
awk -v min=10000 -v max=50000 'BEGIN{srand(); print int(min+rand()*(max-min+1))}'
The example result that we will use in the rest of this article:
16273
1.2. Open Firewall
There are multiple ways to implement a firewall: nftables, iptables, ufw, and firewalld. The modern way is nftables. However, in a moment we are going to install OpenVPN with a script that uses iptables. Therefore we will use iptables to build our basic firewall. Issue each of these commands in turn:
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
Open port 22
for SSH. If you can restrict the port 22
rule so that only certain source IP addresses are whitelisted for SSH access, then
so much the better.
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
Add rules to open the random port you chose for Shadowsocks:
iptables -A INPUT -p tcp --dport 16273 -j ACCEPT
iptables -A INPUT -p udp --dport 16273 -j ACCEPT
Drop all unexpected input:
iptables -P INPUT DROP
Save the iptables rules so that they persist after reboots:
apt update && apt upgrade -y
apt install iptables-persistent -y
1.3. Implement BBR
Bottleneck Bandwidth and Round-trip propagation time (BBR) is a TCP congestion control algorithm developed at Google. Under certain types of network congestion, it will improve your latency. Implement BBR TCP congestion control on your server with the following commands:
cat >> /etc/sysctl.d/50-bbr.conf <<EOF
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF
sysctl -p /etc/sysctl.d/50-bbr.conf
1.4. Download Angristan OpenVPN Install Script
Get the Angristan OpenVPN script from GitHub:
wget https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh
Make the script executable:
chmod +x openvpn-install.sh
1.5. Run Script and Create Client OVPN File
Run the Angristan OpenVPN script:
./openvpn-install.sh
You can accept the suggested default answers to most of the questions, but Shadowsocks will require OpenVPN to use TCP
rather than
UDP
:
- IP address should accurately reflect the IP address of your server
- Port choice should be
1194
(it will be hidden behind Shadowsocks anyway) - Protocol
UDP
is fastest and should work with Shadowsocks, but some countries throttle or blockUDP
, so chooseTCP
if you need to - For DNS servers, you can choose your favorite, e.g. Cloudflare or Google
- For enable compression, recommend
n
for no - For customized encryption settings, recommend
n
for no
After answering all the questions, press any key to continue and run the script. At the end of the installation, you are asked about the first client:
- For the first client name, we will put
debian10
- For the private key file, we will put passwordless
You can check that OpenVPN is active (running)
after the script finishes:
systemctl status openvpn@server
Check also that OpenVPN is listening for UDP
or TCP
input on port 1194
:
ss -tulpn | grep 1194
1.6. Adjust Firewall Rules
If you look at the iptables firewall, you will see that the script has opened port 1194
to the public:
iptables -vnL
We want to make the OpenVPN server as invisible as possible. Therefore we will close port 1194
to the public. In a few minutes, we’ll add Shadowsocks
to handle incoming traffic and pass it to OpenVPN, on the loopback interface port 1194
.
Edit the iptables rules that get added when OpenVPN is brought up:
vi /etc/iptables/add-openvpn-rules.sh
Delete the line to insert an input rule accepting packets on port 1194
. Save the file.
Edit the iptables rules that get removed when OpenVPN is brought down:
vi /etc/iptables/rm-openvpn-rules.sh
Delete the line deleting the input rule accepting packets on port 1194
. Save the file.
Make sure that everything still works after you reboot the server:
reboot
Check the revised iptables rules:
iptables -vnL
You should see that port 1194
is no longer open to the public. Traffic that is passed from Shadowsocks to OpenVPN will still be accepted, since it uses
the loopback interface (-i lo
), for which we added a special iptables rule at the beginning.
1.7. Install Shadowsocks
Install Shadowsocks-Libev from the repositories:
apt install shadowsocks-libev -y
1.8. Configure Shadowsocks
Generate a strong password:
openssl rand -base64 24
The example result that we will use in the rest of this article:
r7EaFR2DshpQT+QMfQGYO5BXC2BAV8JG
Edit the Shadowsocks-Libev configuration file:
vi /etc/shadowsocks-libev/config.json
Enter your choice of configuration details. Using our example of a random port and password:
{
"server":["::1", "0.0.0.0"],
"mode":"tcp_and_udp",
"server_port":16273,
"local_port":1080,
"password":"r7EaFR2DshpQT+QMfQGYO5BXC2BAV8JG",
"timeout":300,
"method":"chacha20-ietf-poly1305"
}
Save the file.
1.9. Restart Shadowsocks
Restart Shadowsocks-Libev, check that it is working, then exit your session with the server:
systemctl restart shadowsocks-libev
systemctl status shadowsocks-libev
ss -tulpn | grep ss-server
exit
2. Set Up Client
2.1. Copy Client Configuratio File from Server to PC
Now work on your PC. Assuming that your server has IP address yy.yy.yy.yy
and that you named the client file debian10.ovpn
, copy the OVPN
file down from the server to the client like this:
scp root@yy.yy.yy.yy:debian10.ovpn ~/Downloads/debian10.conf
2.2. Install Shadowsocks Client
Install Shadowsocks-Libev from the repositories:
sudo apt update && sudo apt upgrade -y
sudo apt install shadowsocks-libev -y
2.3. Configure Shadowsocks Client
sudo systemctl stop shadowsocks-libev
sudo systemctl disable shadowsocks-libev
sudo vi /etc/shadowsocks-libev/config.json
Enter your server details, replacing yy.yy.yy.yy
by your server’s public IP address. The port, password, and encryption method must match those on the
server.
{
"server": "yy.yy.yy.yy",
"server_port": 16273,
"local_address": "127.0.0.1",
"local_port":1080,
"password": "r7EaFR2DshpQT+QMfQGYO5BXC2BAV8JG",
"method": "chacha20-ietf-poly1305",
"timeout": 300,
"fast_open": false,
"mode": "tcp_and_udp"
}
Save the file.
2.4. Start Shadowsocks
Start the local client listening on port 1080
:
sudo systemctl enable shadowsocks-libev-local@config
sudo systemctl start shadowsocks-libev-local@config
sudo ss -tulpn | grep 1080
2.5. Install OpenVPN Client
Install OpenVPN for GNOME and all its dependencies from the repositories:
sudo apt install network-manager-openvpn-gnome -y
2.6. Configure OpenVPN Client
Edit the downloaded OpenVPN client configuration file:
vi ~/Downloads/debian10.conf
Add a line at the end:
socks-proxy 127.0.0.1 1080
Save the file. You can now also close your terminal.
From GNOME Settings, go to the Network page.
- Click the plus sign to add a VPN
- Select the option Import from file...
- Select your downloaded
~/Downloads/debian10.conf
file - Click Add
2.7. Add Static Route to Server
With OpenVPN and Shadowsocks running at the same time, we must prevent a routing loop. We do not want traffic for the OpenVPN server to go to the OpenVPN client, then to the Shadowsocks client, and then back to the OpenVPN client again.
On Windows, you can add route yy.yy.yy.yy 255.255.255.255 net_gateway
to the OpenVPN client configuration. This does not work on a Linux client running
Network Manager due to #1417169. Network Manager for OpenVPN does not support special
route
keywords such as vpn_gateway
or net_gateway
.
Therefore on a Linux client, we will add a static route at this stage.
Determine your default gateway:
ip route | grep default
Let’s say, for example, that your OpenVPN server is yy.yy.yy.yy
, your default gateway is 192.168.1.254
, and your real interface is
enp0s3
. Add a temporary static route:
sudo ip route add yy.yy.yy.yy via 192.168.1.254 dev enp0s3
The route will persist until the next reboot (or until you explicitly delete the route).
2.8. Test End-to-End
In GNOME Network Settings, toggle your newly added VPN connection to the ON position.
Open Firefox, and visit IP Chicken.
You should see the IP address of your remote server, not your local client.
3. Get Help and Report Issues
- For OpenVPN questions, post in the OpenVPN forum
- For Shadowsocks-Libev issues, see GitHub
Updated 2020-09