Chaining Wireguard VPN to OpenVPN

Categories: OpenVPN, Wireguard


What ?

We want Wireguard clients to connect to a middleman box that will route out to the internet via an OpenVPN client.

Why ?

Some of our sites have poor performance to the OpenVPN server. Wireguard clients are more seamless and battery/resource saving on mobile devices. We have a Wireguard server in a datacenter closer to these users. Basically a band-aid fix / POC because it is Sunday so why not ?

How ?

Quick and dirty to get proof of concept:

 

1) Install Wireguard server on Linux instance in a data-center with great connectivity to the OpenVPN server and positioned close to the clients. Ensure ufw and firewalld are not installed or the Wireguard install script will detect them and create PostUp/PostDown instructions for them. We are going to work with plain old iptables but the concept I outline here can of course be adapted to ufw / firewalld. We use CSF and plain old iptables here at my gig. Live and let live šŸ™‚

 

2) Connect a Wireguard client device to the server and confirm it can ping the RFC1918 / ULA addresses of the Wireguard network and is routing to the internet via the Wireguard server.

 

3) Install OpenVPN client to the actual target network on the Wireguard server. You will want different RFC1918 / ULA prefixes. To be clear, if your Wireguard RFC1918 is 192.168.20.0/24 make sure there is no overlap with the OpenVPN network. Same goes for the IPv6 prefix/ULA.

 

4) Before starting the OpenVPN client modify the OpenVPN configuration file to prevent automatic route pulls. Otherwise the OpenVPN client will start and the VPS’ default route will be the OpenVPN server which may break Wireguard or your access to other services such as SSH on this VPS.

route-nopull
pull-filter ignore route
pull-filter ignore route-ipv6

I expected route-nopull to get the job done on its own but for some reason I needed the two pull-filters. Comments / improvements welcome.

 

5) Start the OpenVPN client. Make sure it is reboot persistent. How this is done depends on your flavor of Linux. In the case of CentOS 8 you make sure the OpenVPN config file ends in .conf and drop it into /etc/openvpn/client/ and you can then use systemd to control it via [email protected][filename]. For example if your config file is torguard1.ovpn you need to rename it to torguard1.conf, copy it into /etc/openvpn/client/ and then you can start it with systemctl enable –now [email protected] (no .conf there!).

 

6) Verify that Wireguard client is still performing as per 2).

 

7) Verify that VPS is still reachable as normal, else review 4).

 

8) Now we modify the /etc/wireguard/wg0.conf to NAT Wireguard clients via tun0 instead of the VPS’ WAN interface. Comment out the existing PostUp = and PostDown = lines and put in these each on a single line:

PostUp = iptables -A FORWARD -i wg0 -o tun0 -j ACCEPT; iptables -A FORWARD -i tun0 -o wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT; iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -o tun0 -j ACCEPT; ip6tables -A FORWARD -i tun0 -o wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT; ip6tables -t nat -A POSTROUTING -o tun0 -j MASQUERADE;

PostDown = iptables -D FORWARD -i wg0 -o tun0 -j ACCEPT; iptables -D FORWARD -i tun0 -o wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT; iptables -t nat -D POSTROUTING -o tun0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -o tun0 -j ACCEPT; ip6tables -D FORWARD -i tun0 -o wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT; ip6tables -t nat -D POSTROUTING -o tun0 -j MASQUERADE

This will take care of NAT and forwarding. Again, this is probably not very elegant. If anyone has a more efficient way of getting it done, please comment.

 

9) We are yet to set up policy-based routing. We want the Wireguard client subnets to go out via the OpenVPN tunnel. Up until the previous step they would have routed via the Wireguard server as verified in step 6) . After making the changes in step 8) they will be broken because they are sent to an interface without a route. Let’s use iproute2

Assuming your Wireguard server’s RF1918 and ULA are 192.168.20.0/24 and fdcd:cd61:1234:1234::/64 (use your own values!)

echo "1 broker" >> /etc/iproute2/rt_tables
ip route add 0.0.0.0/0 dev tun0 table broker
ip rule add from 192.168.20.0/24 lookup broker
ip -6 route add ::/0 dev tun0 table broker
ip -6 rule add from fdcd:cd61:1234:1234::/64 lookup broker

Execute this from the shell and your Wireguard client should now route through the Wireguard server and exit from the OpenVPN server.

 

10) Your Wireguard client now loses its ability to reach the Wireguard network. If connectivity to the Wireguard server via its Wireguard address or connectivity between Wireguard clients is desired you can customize /etc/iproute2/rt_tables accordingly by having a higher priority entry in the table directing traffic for them them to another inferface.

 

11) Next step is to make bash scripts for PostUp/PostDown because it is getting too long / messy for wg0.conf

Change your /etc/wireguard/wg0.conf:

PostUp = /etc/wireguard/postup.sh
Postdown = /etc/wireguard/postdown.sh

Create and make executable:

cat /etc/wireguard/postup.sh

#!/bin/bash
iptables -A FORWARD -i wg0 -o tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -o wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
ip6tables -A FORWARD -i wg0 -o tun0 -j ACCEPT
ip6tables -A FORWARD -i tun0 -o wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -t nat -A POSTROUTING -o tun0 -j MASQUERADE;
echo "1 broker" >> /etc/iproute2/rt_tables
ip route add 0.0.0.0/0 dev tun0 table broker
ip rule add from 192.168.20.0/24 lookup broker
ip -6 route add ::/0 dev tun0 table broker
ip -6 rule add from fdcd:cd61:1234:1234::/64 lookup broker

Create and make executable:

cat /etc/wireguard/postdown.sh

#!/bin/bash
iptables -D FORWARD -i wg0 -o tun0 -j ACCEPT
iptables -D FORWARD -i tun0 -o wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -D POSTROUTING -o tun0 -j MASQUERADE
ip6tables -D FORWARD -i wg0 -o tun0 -j ACCEPT
ip6tables -D FORWARD -i tun0 -o wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -t nat -D POSTROUTING -o tun0 -j MASQUERADE;
echo "1 broker" >> /etc/iproute2/rt_tables
ip route del 0.0.0.0/0 dev tun0 table broker
ip rule del from 192.168.20.0/24 lookup broker
ip -6 route del ::/0 dev tun0 table broker
ip -6 rule del from fdcd:cd61:1234:1234::/64 lookup broker

My postdown.sh is sloppy. Comments/improvements would be appreciated.

Note: Timing is important. If your Wireguard service starts up before the OpenVPN tunnel is up the tun0 interface may not be there yet or lack addressing and our PostUP instructions may fail. You will want to ensure systemd starts OpenVPN first and Wireguard after this is done. Or make some dirty @reboot cronjob to restart them in the right order.

 

Outcome:

 

Before: OpenVPN direct to our destination. Our ISP routing is via the scenic route:

 

After: Wireguard to a jump server near us. Getting away from our ISP within 60ms

and then onward via a proper backbone:

In this scenario it was worth it. Also expecting less issues with mobile devices due to

sessions being stateless and the client being leaner.

«
»

    Leave a Reply

    Your email address will not be published.