WireGuard VPN on Ubuntu 18.04

October 21, 2018

As mentioned in my post about using nsupdate and bind to set up dynamic DNS, I have a home server which I use to store several things. I then use an nginx-proxy from my main server to reach these things. The problem with using a dynamic DNS to reach the server, is that I need to restart nginx every time the address changes. This isn't a huge problem as the address doesn't change that often, but it is annoying when it happens.

My plan here is to set up a VPN between these machines, so that I can reach my home server from my main server using a static address. To achieve this, my home server will connect to my main server using WireGuard. Hopefully, this will give me IPv6 on my home server as well (as my ISP does not provide this…).

This post is mainly written so I can remember what I did in the future. I will shamelessly steal from guides from both DigitalOcean and Linode, and if you're looking for a guide to do this yourself, you should probably check out both.

Going forward my home server will be the client, and my main server will be the server.

Installing WireGuard

Wireguard provides a PPA for Ubuntu, and is quite easy to install. Just run the following commands on both server and client.

$ sudo apt install software-properties-common
$ sudo add-apt-repository ppa:wireguard/wireguard
## Hit enter when prompted if you want to add the new source
$ sudo apt update
$ sudo apt install wireguard-dkms wireguard-tools

Generating keys

Now we need to create the keys. This should be done on both server and client.

$ cd /etc/wireguard
$ umask 077
$ wg genkey | sudo tee privatekey | wg pubkey | sudo tee publickey

This will generate a private key, put it in /etc/wireguard/privatekey and pipe it to the wg pubkey-command, which will create a public key based on the private key and put it in /etc/wireguard/publickey.

Configuration

Configure the server

Edit /etc/wireguard/wg0.conf. It should look something like this:

[Interface]
PrivateKey = <Private Key>
Address = 172.21.12.1/24, fd10:21:12::1/64
ListenPort = 51820
# SaveConfig = true
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eno1 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eno1 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eno1 -j MASQUERADE

# Client
[Peer]
PublicKey = <Client Public Key>
AllowedIPs = 172.21.12.2/32, fd10:21:12::2/128

The addresses are just randomly chosen private addresses. Please note that the PublicKey under [Peer] should be the clients public key.

I have decided to comment out the SaveConfig-option. This option will save any changes you make to the live VPN-connection (using wg) to the config-file. This is nice if you actually make changes live. I prefer to update config-files.

Also note that the AllowedIPs-option works as an ACL on the server-side, and decides what to route through the VPN on the client-side.

The IPTables-rules are only necessary if you want to be able to surf the web through the VPN. If you only want a VPN between the machines, you can remove PostUp and PostDown. If you do want to surfe the web, you will also have to uncomment these two lines in your /etc/sysctl.conf-file:

net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

And then you have to run sudo sysctl -p.

Now we can enable the wireguard-service and start it by running

$ sudo systemctl enable wg-quick@wg0
$ sudo systemctl start wg-quick@wg0

WireGuard should now be good to go on the server.

Configure the client

/etc/wireguard/wg0.conf should look like this:

[Interface]
PrivateKey = <Private Key>
Address = 172.21.12.2/24, fd10:21:12::2/64
#SaveConfig = true

# server
[Peer]
PublicKey = <Server Public key>
Endpoint = <Server Public IP>:51820
AllowedIPs = 172.21.12.0/24, ::/0
PersistentKeepalive = 25

As I mentioned, I don't have IPv6 at home. So, I wish to route all my IPv6 packets through the server. I have IPv4 at home, so I will only route the VPN-net through the VPN.

I've thrown in PersistentKeepalive for good measure, since my home-server is behind NAT. This will send keepalive-packets through the tunnel, so that it stays open even when it's not in any use.

Enable the wireguard service and start it by running

$ sudo systemctl enable wg-quick@wg0
$ sudo systemctl start wg-quick@wg0

Testing the VPN

First, let's ping the client from the server.

$ ping 172.21.12.2 -c3
PING 172.21.12.2 (172.21.12.2) 56(84) bytes of data.
64 bytes from 172.21.12.2: icmp_seq=1 ttl=64 time=8.53 ms
64 bytes from 172.21.12.2: icmp_seq=2 ttl=64 time=8.84 ms
64 bytes from 172.21.12.2: icmp_seq=3 ttl=64 time=9.03 ms

--- 172.21.12.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 8.538/8.806/9.038/0.219 ms

$ ping -6 fd10:21:12::2 -c3
PING fd10:21:12::2(fd10:21:12::2) 56 data bytes
64 bytes from fd10:21:12::2: icmp_seq=1 ttl=64 time=9.75 ms
64 bytes from fd10:21:12::2: icmp_seq=2 ttl=64 time=10.0 ms
64 bytes from fd10:21:12::2: icmp_seq=3 ttl=64 time=9.07 ms

--- fd10:21:12::2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 9.077/9.634/10.073/0.422 ms

Alright! Now, let's ping the server from the client!

$ ping 172.21.12.1 -c3
PING 172.21.12.1 (172.21.12.1) 56(84) bytes of data.
64 bytes from 172.21.12.1: icmp_seq=1 ttl=64 time=7.86 ms
64 bytes from 172.21.12.1: icmp_seq=2 ttl=64 time=8.14 ms
64 bytes from 172.21.12.1: icmp_seq=3 ttl=64 time=9.03 ms

--- 172.21.12.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 7.867/8.347/9.035/0.509 ms

$ ping -6 fd10:21:12::1 -c3
PING fd10:21:12::1(fd10:21:12::1) 56 data bytes
64 bytes from fd10:21:12::1: icmp_seq=1 ttl=64 time=9.23 ms
64 bytes from fd10:21:12::1: icmp_seq=2 ttl=64 time=10.1 ms
64 bytes from fd10:21:12::1: icmp_seq=3 ttl=64 time=8.87 ms

--- fd10:21:12::1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 8.877/9.413/10.125/0.536 ms

And, lastly, let us try to ping google with IPv6, to see if my client can reach the world using Ipv6.

$ ping -6 google.com -c3
PING google.com(arn11s02-in-x0e.1e100.net (2a00:1450:400f:809::200e)) 56 data bytes
64 bytes from arn11s02-in-x0e.1e100.net (2a00:1450:400f:809::200e): icmp_seq=1 ttl=56 time=19.3 ms
64 bytes from arn11s02-in-x0e.1e100.net (2a00:1450:400f:809::200e): icmp_seq=2 ttl=56 time=19.7 ms
64 bytes from arn11s02-in-x0e.1e100.net (2a00:1450:400f:809::200e): icmp_seq=3 ttl=56 time=19.8 ms

--- google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 19.381/19.658/19.875/0.206 ms

Great Success!


Sources