VPN Chaining with Wireguard

Allan John
5 min readMar 8, 2022

--

Introduction

VPN Chaining is a method, where a client is connected to internet with 2 VPNs in between. This is usually for 2 purposes, masking the real IP address when web surfing and to improve network speed. The latter will only be good, when there is direct routes between the two VPNs or from the client to the first VPN. For better security with VPN chaining, there should be a good implementation of network security is required, which I am not going to cover in this topic. This doc is for speed improvement.

Requirement

  • 2 VPS or Servers. Cloud linux servers will be best as the internal routing will be very fast, and the network to access internet will be optimised because of the cloud. Server1 will be referred as Middleman and Server2 will be referred as Gate
  • IP forwarding enabled on the server. If not enabled, add net.ipv4.ip_forward=1 to /etc/sysctl.conf file and run sysctl -p to enable this kernel parameter.
  • An internal IP range. For convenience, I will choose the range 10.10.10.0/24

Design

Client ==> Middleman(Server1) ==> Gate(Server2) ==> Internet

Procedure

Configure Gate

First we will install wireguard and then configure

sudo apt update
sudo apt install wireguard -y

Next we will need to generate a Key pair for communication with wireguard tool.

wg genkey | sudo tee /etc/wireguard/private.key
sudo chmod go= /etc/wireguard/private.key

The sudo chmod go= command removes any permissions on the file for users and groups other than the root user to ensure that only it can access the private key.

Now we can create the public key from the created private key

sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key

Now the wireguard configuration /etc/wireguard/gate0.conf

[Interface]
Address = 10.10.10.2/32
PostUp = ufw route allow in on gate0 out on enp1s0
PostUp = iptables -t nat -A POSTROUTING -s 10.200.200.0/24 -o enp1s0 -j MASQUERADE
PreDown = ufw route delete allow in on gate0 out on enp1s0
PreDown = iptables -t nat -D POSTROUTING -s 10.200.200.0/24 -o enp1s0 -j MASQUERADE
ListenPort = 51820
PrivateKey = private-key-of-gate-created
[Peer]
PublicKey = public-key-of-server1
AllowedIPs = 10.10.10.0/24
Endpoint = IP-of-server1:51820

Here we add the iptables and firewall rules so that we add the config and forget to remove. Make sure the value enp1s0 should be replaced with proper interface.

The Peer config is for the Middleman, where we are allowing the Middleman to communicate with Gate. The public key is the one to add from the next section. We are allowing the whole network, because we need the client communication to be allowed through this server.

Configure Middleman

sudo apt update
sudo apt install wireguard -y

Generate Keys

wg genkey | sudo tee /etc/wireguard/private.key
sudo chmod go= /etc/wireguard/private.key
sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key

Configure Wireguard in. /etc/wireguard/wg0.conf

[Interface]
Address = 10.10.10.3/32
PostUp = echo 1 > /proc/sys/net/ipv4/ip_forward
PostUp = echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT && iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT && iptables -D FORWARD -o wg0 -j ACCEPT
PostDown = echo 0 > /proc/sys/net/ipv4/ip_forward
PostDown = echo 0 > /proc/sys/net/ipv4/conf/all/proxy_arp
ListenPort = 51820
PrivateKey = private-key-of-middleman
[Peer]
PublicKey = public-key-of-client
AllowedIPs = 10.10.10.4/32
[Peer]
PublicKey = public-key-of-gate
AllowedIPs = 0.0.0.0/0
Endpoint = IP-of-Gate:51820

Similar configuration as the Gate, except for the iptables rule, which is basically forwarding the packets and Peer configuration. There is peer configuration for the client and then another config to connect to the Gate server. Here, Middleman is the client to Gate. The public key for client will be created in the next section.

Configure client

sudo apt update
sudo apt install wireguard -y

Generate Keys:

wg genkey | sudo tee /etc/wireguard/private.key
sudo chmod go= /etc/wireguard/private.key
sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key

Configure Wireguard in. /etc/wireguard/vpn0.conf

[Interface]
PrivateKey = private-key-of-client
Address = 10.10.10.4/32
PostUp = ip rule add table 200 from 10.0.2.15
PostUp = ip route add table 200 default via 10.0.2.2
PreDown = ip rule delete table 200 from 10.0.2.15
PreDown = ip route delete table 200 default via 10.0.2.2
[Peer]
PublicKey = public-key-of-middleman
AllowedIPs = 0.0.0.0/0
Endpoint = IP-address-of-middleman:51820

This configuration is to redirect all requests to the VPN interface. If only certain traffic should go through the VPN interface, then you can remove the PostUp and PreDown rules and replace the Allowed IPs with the proper network.

Note that the values for ip rule can be figured out from the output of the command ip route list table main default and the value for ip route can be figured out from the output of the command ip -brief address show eth0 , where eth0 is the default interface.

Once everything is configured, try to connect to each server and start the VPN.

For gate:

wg-quick up gate0

For Middleman:

wg-quick up wg0

For Client:

wg-quick up vpn0

Note that, when running the command on Middleman, the current connection will be cut-off, as the SSH will then be only available through the VPN network. You can create complex iptable rules to allow only SSH to access from Public IP, but its in one way, not worth the trouble and it kindof defeats the purpose of having a VPN.

On the client run a traceroute to see if communication is going as expected:

osboxes@osboxes:~$ traceroute 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1 10.10.10.3 (10.10.10.3) 60.068 ms 60.068 ms 60.068ms
2 10.10.10.2 (10.10.10.2) 74.959 ms 74.959 ms 74.959 ms
3 * * *
4 * * *
5 * * *
6 * * *
7 * * *
8 74.125.242.33 (74.125.242.33) 364.959 ms 364.973 ms 108.170.240.225 (108.170.240.225) 366.528 ms
9 74.125.242.33 (74.125.242.33) 365.752 ms 72.14.232.101 (72.14.232.101) 366.475 ms 108.170.240.225 (108.170.240.225) 366.473 ms
10 dns.google (8.8.8.8) 365.681 ms 142.251.52.49 (142.251.52.49) 365.688 ms dns.google (8.8.8.8) 365.687 ms
osboxes@osboxes:~$

Conclusion

Its interesting to use VPN chaining to have a bit of anonymity and improve performance. As you can see, my DNS query to Google is not so fast, but still it might be better for some sites which are slow in normal network

Have a nice day!

--

--

Allan John
Allan John

Written by Allan John

Passionate DevOps and Automation Engineer

Responses (5)