Set up a Wireguard VPN in 15 minutes

Wireguard is the new kid on the block when it comes to VPNs. It offers significant advantages compared to the traditional choices of OpenVPN and IPSec. It is very lean with about 5,000 lines of code. Thanks to that, the codebase has already gone through a security. More importantly, it is extremely easy to set up (especially compared to IPSec). On top of that, it is also much faster (mainly in comparison to OpenVPN). Currently, Wireguard is in the process of being implemented in the Linux kernel. However, it is already available as a Linux kernel module. In this post, you will learn how to set up a simple VPN consisting of a server with public a IP address and two other machines running behind a NAT. First, some theory. Wireguard uses a peer to peer architecture, where each peer has their own private and public key pair. So, the peers authenticate each other by exchanging public keys. And this creates a bidirectional tunnel. As you can see, the key exchange is almost as easy as with SSH. The communication itself uses standard Linux network interface.

Configure a Debian server

Above, I have said that Wireguard is peer to peer. So, where does server suddenly come from? Well, since directly connecting machines behind a NAT is not an easy affair (you would need to use Dynamic DNS or a similar technique), you will need a peer with a public IP address, that the peers behind NAT will connect to. For the sake of clarity, I am just going to go ahead and call this peer a server and the rest clients. Before you start, enable packet forwarding on the server. In order to do that, you need to edit /etc/sysctl.conf and uncomment this line:

net.ipv4.ip_forward=1

Then run:

$ sysctl -p

In Debian, Wireguard is available in the unstable repository. You enable this way:

$ echo "deb https://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list
$ printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable

After that, you can install the wireguard package. To build the module, you also need to install kernel headers:

$ apt update
$ apt install linux-headers-amd64 wireguard

Afterwards, enable the kernel module:

$ modprobe wireguard

Next, you need to generate the private and public keys:

$ cd /etc/wireguard
$ umask 077
$ wg genkey | tee privkey | wg pubkey > pubkey

The above commands create two files - /etc/wireguard/privkey and /etc/wireguard/pubkey. Now you just need to add configuration for the interface in /etc/wireguard/wg0.conf. It should look similar to this:

[Interface]
PrivateKey = PrivkeyOfServer
Address = 10.10.10.1/24

Later on, you will need to add peers. But for now, we are done. The default port for Wireguard is 51820, so make sure it’s open.

Configure a Raspbian client

It’s a common use-case to have a Raspberry Pi, that you might want to connect to from the outside world. Since Raspbian is based on Debian, the installation process is almost identical. The only extra step is to add the GPG key for the Debian repository:

$ echo "deb https://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list
$ printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable
$ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138
$ apt update
$ apt install raspberrypi-kernel-headers wireguard
$ modprobe wireguard
$ cd /etc/wireguard
$ umask 077
$ wg genkey | tee privkey | wg pubkey > pubkey

After that, you need to add Wireguard configuration in /etc/wireguard/wg0.conf again. It should look like this:

[Interface]
PrivateKey = PrivkeyOfRaspberry
Address = 10.10.10.2/24

[Peer]
PublicKey = PubkeyOfServer
Endpoint = IPAddressOfServer:51820
AllowedIPs = 10.10.10.0/24
PersistentKeepalive = 25

In the above, AllowedIPs determines range, that should be routed through the Wireguard interface. If you want to route all your traffic through the VPN, set it to 0.0.0.0/0. PersistentKeepalive lets the client behind NAT keep the connection open.

Configure an Opensuse client

You will probably also want to set up your laptop to use the VPN. In my case, that’s Opensuse Tumbleweed. With the exception of package installation, the process is the same:

$ zypper addrepo -f obs://network:vpn:wireguard wireguard
$ sudo zypper install kernel-devel wireguard-kmp-default wireguard-tools
$ modprobe wireguard
$ cd /etc/wireguard
$ umask 077
$ wg genkey | tee privkey | wg pubkey > pubkey

The configuration in /etc/wireguard/wg0.conf will be almost identical to the Raspberry Pi one. Just update the private key and use a different IP address.

[Interface]
PrivateKey = PrivkeyOfLaptop
Address = 10.10.10.3/24

[Peer]
PublicKey = PubkeyOfServer
Endpoint = IPAddressOfServer:51820
AllowedIPs = 10.10.10.0/24
PersistentKeepalive = 25

Running Wireguard

Now that you’ve set up the clients, you have to add their public keys to the server configuration. Back on the server, edit /etc/wireguard/wg0.conf, so it looks like this:

[Interface] PrivateKey = PrivkeyOfServer
Address = 10.10.10.1/24

# Raspberry
[Peer]
PublicKey = PubkeyOfRaspberry
AllowedIPs = 10.10.10.2/32

# Laptop
[Peer]
PublicKey = PubkeyOfLaptop
AllowedIPs = 10.10.10.3/32

With the configuration ready, you can start Wireguard. On all three machines, run the following command:

$ wg-quick up wg0

And also make sure it starts automatically upon reboot:

$ systemctl enable wg-quick@wg0

Conclusion

That’s it! At this point, you should be able to ping the other machines using their VPN address. As you can see, the setup is fairly straightforward. And in addition to Linux, Wireguard also has Android, iOS, MacOS and Windows clients. For more Raspberry Pi tutorials, go here.