I replaced OpenVPN with WireGuard

So it has been a while since I actually wrote something on my blog now. I guess I have been to busy, or not really felt inspired to write something new.

Introduction

I am a big fan of hosting things myself, and during the start of my self-hosting experience, I was not able to modify (or control) the gateway I was behind. I was renting an apartment, and the gateway controlling the incoming traffic was controlled by the landlords, so port forwarding was not an option.

It started with my blog post (Nextcloud + reverse proxy with autossh) where I would forward port by port over SSH, but this would be a very tedious process. It only supported tcp, and the overhead to get a new service running was quite substantial- *shivers down my spine*.. I could not host SA-MP servers that required UDP, for instance.

Then, my creativity kicked in a year later: Using OpenVPN, I could talk directly to a VPS somewhere else, and use a secondary / floating IP to route all traffic to my OpenVPN interface. That way, I no longer had to set up one and one port for something to host from home. Until yesterday, this has been my primary way of hosting things at home. Even when I am able to control my home router as of today, I simply did not want the hassle of exposing my home to the internet, and I will get to the details as to why a bit later.

Introducing WireGuard

…what? Isn’t that just the same thing as OpenVPN?

In practical terms, both OpenVPN and WireGuard seem to be solving the same problem. Both are Virtual Private Network based software, and they allow one or more clients to connect together in a mesh of devices, creating a ..private network. WireGuard claims it is much faster and reliable than OpenVPN, and it is actually a part of the linux kernel in most cases(!).

Let’s have a look at WireGuards official documentation:

Please note that these graphs are from a third gen i7 CPU, so these are OLD graphs.

WireGuard is comparing the latency and the throughput for the two technologies, alongside IPsec. Even though these numbers might be super old, it just signifies the huge difference in performance between them. This was one of the reasons for me to consider WireGuard instead of OpenVPN. Take it with a grain of salt though, they say nothing about the configuration they used.

I wanted less latency, and more throughput. Did I get it?

Latency

This graph shows my forum, which currently sits behind a proxy. The blue part is when I switched to WireGuard. To be fair, I do not see a big reduction in latency here, this could be because I am behind Cloudflare and that the reduction is minimal in comparison to the time it takes for the request to travel from my home in North Norway to my proxy (currently in Helsinki, Finland). Like this: Home, proxy, back to home (inside WG tunnel) and then out of proxy again, then back home. (Grrr why are there no good datacenters in Northern Scandinavia?)

Another example is my Java Minecraft server on the same node:

I do not really see a big difference in latency that would be significant enough, other than maybe a 2-3 ms difference in average.

Throughput

When it comes to throughput, I have seen a big difference. Uploading and downloading files to my server through the WireGuard proxy is up to 3x faster than before. This alone justifies the switch.

From Client’s perspectiveOpenVPN (TCP)WireGuard (UDP)
Download~6mb/s~28mb/s
Upload~7mb/s~28mb/s

Now that UDP finally worked with WireGuard, the results were reflecting very pawsitively. 🦊-approved!

How did I set up?

I am not going to make this a guide, but I will outline what I did, so that you get an idea of my setup. My main source of help was from the official WireGuard Quick Start:

https://www.wireguard.com/quickstart

Also, you will need the wireguard-tools installed for the below commands to work.

  1. I created a new interface:
    ip link add dev wg0 type wireguard
  2. Then, I created a private and public key to use with my interface:
    umask 077 && wg genkey > wg.private && wg pubkey < wg.private > wg.pubkey
    (Yes, 3 different steps, but written in one line)
  3. Do step 1. and 2. on the VPS as well.
  4. Made a file (on both servers) under /etc/wireguard/wg0.conf with the necessary config
  5. Made a systemd service file [email protected] to help auto-start on boot.
  6. Profit

How to use an entire IP on the VPS (secondary IP) to route to home server?

I used the exact same technique as described in OpenVPN – Use secondary VPS IP to access your home-hosted websites and game servers – where I used IPTables to forward packets to the wg0 interface/ip. So I need the packets to always exit the secondary interface, and I want all the packets received on the secondary interface sent back to the wg0 interface (and hence back to my home server). Here is the same systemd service config as I used in OpenVPN config:

[Unit]
Before=network.target
[Service]
Type=oneshot
ExecStart=/sbin/iptables -t nat -A POSTROUTING -s 10.8.0.1/32 ! -d 10.8.0.1/32 -j SNAT --to 159.120.120.10
ExecStart=/sbin/iptables -I INPUT -p udp --dport 51820 -j ACCEPT
ExecStart=/sbin/iptables -I FORWARD -s 10.8.0.1/32 -j ACCEPT
ExecStart=/sbin/iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
ExecStop=/sbin/iptables -t nat -D POSTROUTING -s 10.8.0.1/32 ! -d 10.8.0.1/32 -j SNAT --to 159.120.120.10
ExecStop=/sbin/iptables -D INPUT -p udp --dport 51820 -j ACCEPT
ExecStop=/sbin/iptables -D FORWARD -s 10.8.0.1/32 -j ACCEPT
ExecStop=/sbin/iptables -D FORWARD -m state --state 
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

Where 159.120.120.10 is my secondary IP, and 10.8.0.1/32 is the interface IP for wg0 (as an example).

Reliability

Since you have two servers responsible making sure one connection stay open, you suddenly have twice as many factors (maybe a bit more) to consider. The probability of the connection being affected is higher.

This was often a slight problem for me on OpenVPN. I never could make my client and server reconnect quickly enough after an outage, so I would often manually go in and forcibly restart the service(s) to trigger it to reconnect. I am 200% sure that I could get away with a better configuration in the first place, but it never annoyed me enough to investigate further.

Testing

I did some easy tests. Things that would trigger an indefinite timeout and no recovery, would be if my apartment’s gateway would go offline momentarily, and the server loses ability to talk with the outside world. The OpenVPN connection would go stale and at this point I would need to SSH in and trigger a service restart. I unplugged my server’s ethernet cable, and waited 30 seconds, then I plugged it back in… * It works *.

Not only did it work, but it was fairly instant as well. WireGuard does a phenomenal job restoring its connection, and this is also a huge improvement over what I had before. Less configuration, yet, better overall experience.

Future considerations

Well, I am using ZeroTier for some internal routing of prometheus/node exporter data, and I use it to route all my personal devices via my home network when travelling. One thing that I could do is set up a small tool to help me generate configurations on the fly, and use WireGuard as a primary tool for the internal routing. It is very lightweight, seems to be supported in new kernels by default, and requires 5-8 lines of configuration to work. This is yet something for me to discover more about.

Summary

Moving WireGuard was a overall positive experience. The examples provided on the homepage for WireGuard were really helpful. I am not looking back at OpenVPN again, that’s for sure.

denNorske

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.