Build a VPN Tunnel with WireGuard

Uncomplicated

© Lead Image © Roman Sakhno, 123RF.com

© Lead Image © Roman Sakhno, 123RF.com

Author(s):

A recent addition to the Linux kernel, WireGuard lets you build a VPN tunnel that relies on encryption to reduce potential security issues.

As a result of the COVID-19 pandemic, many employees have exchanged the office for their home to accommodate social distancing guidelines. In addition to getting used to working from home, many telecommuters must also deal with security issues when contacting colleagues or accessing company servers. While large corporations may take care of these issues for their employees, self-employed telecommuters and small businesses need to find their own solution.

WireGuard [1], the modern virtual private network (VPN) tunnel software developed by security researcher Jason Donenfeld, offers an easy-to-implement solution that relies on encryption to secure the connection between two endpoints. WireGuard found its way into the Linux kernel 5.6 at the end of March at the same time WireGuard v1.0.0 was released. The VPN program is now available for all common operating systems such as Linux, macOS, Windows, Android, and iOS.

Competition

Before WireGuard conquered the market in 2015, IPsec and OpenVPN were the top two contenders under a free license. Compared to WireGuard, however, both IPsec and OpenVPN are more difficult to set up, which is why WireGuard was already in use before becoming a kernel module.

Linux Torvalds had hoped WireGuard would be merged to the kernel in 2018. In comparison to OpenVPN and IPSec, Torvalds has called WireGuard "a work of art" [2]. If you have followed Torvalds' statements over the years, you know that he is generally very sparing with praise.

WireGuard gets by with only about 4,000 lines of source code. In comparison, OpenVPN together with the required OpenSSL weigh in at around 600,000 lines of code, while IPsec and StrongSwan use more than 400,000 lines. WireGuard offers far less attack potential than its competitors. The software also relies on modern algorithms: ChaCha20 [3] is used for encryption, while Curve25519 handles the key exchange [4].

Fast and Frugal

WireGuard shows its advantages over the established solutions in terms of speed and resource consumption. This manifests itself in far faster and more stable connections, especially when roaming. While OpenVPN often consumes 30 percent of battery power on Android, WireGuard keeps this in the lower single-digit range.

We tested WireGuard with Ubuntu 20.04 LTS, which comes with the backported module for WireGuard in kernel 5.4. Ubuntu users were already interested in WireGuard before its inclusion in the kernel, as evidenced by over 20,000 installations from the WireGuard PPA. There is also a backport for Debian 10 Buster.

Not Just for Linux

WireGuard can also be used with OpenBSD, FreeBSD, NetBSD, macOS, and Microsoft Windows (a stable version is imminent for Windows). For road warriors, there are apps for Android and iOS. You will want to use the original apps rather than third-party apps [5].

You can use WireGuard with modest hardware resources. In terms of the server, you don't need anything faster than an older laptop, a single board computer like the Raspberry Pi, or a rented V-Server on the web. In our test, we used a ThinkPad X220, a device that has been out of service for quite some time (see the box "DynDNS and Port Forwarding"). WireGuard supports constellations with two clients or with one server and multiple clients.

DynDNS and Port Forwarding

A local VPN network on your own LAN only makes sense in very rare cases. The typical application scenario involves dialing into the company network or your home LAN from somewhere outside. In this scenario, you need a DynDNS address, provided by something like the free DynDNS Service [6]. You also need to forward the port used by WireGuard (in our example port 51820/UDP) from the WLAN router to the computer used as a server. Details of the required configuration are usually provided in your device's operating manual. In the case of a FRITZ!Box, call the device's administration interface by typing the FRITZ!Box URL in your browser and then open the wizard in Internet | Shares | Port Shares by clicking on Add Device for Shares, which helps you set up port forwarding.

Tunneled

After completing the setup, the laptop, which acts as a server in our case, will take responsibility for transporting the network packets and will reside between the client and, for example, any websites it visits, accepting requests and returning responses. This connection is encrypted in both directions. Visited websites only see the server's IP address, not your own.

Setting up a VPN with WireGuard is easier than with its competitors (which sometimes require a demanding configuration that is easily beyond a beginner's capabilities). With the recent addition of WireGuard to the mainline kernel, its adoption is expected to continue to grow; over time, the configuration is likely to be simplified with additional tools.

Installing WireGuard

Unlike its competitors, WireGuard uses the same software on the server and the clients. After installing the wireguard package via the server's and the clients' package managers, start the process of generating private and public keys; this is comparable to the same procedure in SSH. You need to create a key pair for each device that will have access to the VPN. The two computers on either end of the WireGuard tunnel each need the public keys from the other end. WireGuard does not care whether the server is on the Internet or a local network.

If you are using Ubuntu 20.04, the best way to install WireGuard is to type the following at the command line

sudo apt install wireguard

rather than using the graphical package manager, which only gives you an outdated third-party snap package (Figure 1). Also make sure that the header files are installed to match the kernel.

Figure 1: Ubuntu 20.04 LTS offers two different WireGuard packages. The Ubuntu Software Center gives you an outdated third-party snap. Instead, use the wireguard package, which you can install at the command line.

After installing the package, you still need to enable IP forwarding on the designated WireGuard server. As root, open the /etc/sysctl.conf file in an editor and uncomment the lines #net.ipv4.ip_forward=1 for IPv4 or #net.ipv6.conf.all.forwarding=1 for IPv6 (Listing 1). Then reload the system configuration (Listing 2) by typing:

sudo sysctl -p

Listing 1

Enabling IP Forwarding

[...]
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
[...]
# Uncomment the next line to enable packet forwarding for IPv6
#  Enabling this option disables Stateless Address Autoconfiguration
#  based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
[...]

Listing 2

Reloading WireGuard

### Install Wireguard
$ sudo apt update
$ sudo apt install wireguard resolvconf
### Only on the Wireguard server:
$ sudo nano /etc/sysctl.conf
$ sudo sysctl -p

Key Services

Now create the required private and public keys on the server and clients (shown in Listing 3). Finally, check that the keys have been created with the ls command (Figure 2). It is best to copy both public keys into a text file and save them on a USB stick for later configuration.

Listing 3

Creating Private and Public Keys

$ sudo -s
$ cd /etc/wireguard
### Generate key on server:
$ umask 077; wg genkey | tee <client1>.key | wg pubkey > <client1>.pub
### Generate key on client:
$ umask 077; wg genkey | tee <client2>.key | wg pubkey > <client2>.pub
### Check key on server:
$ ls -al
total 24
drwx------   2 root root  4096 Apr 30 19:49 .
drwxr-xr-x 131 root root 12288 Apr 30 19:47 ..
-rw-------   1 root root    45 Apr 30 19:49 client1.key
-rw-------   1 root root    45 Apr 30 19:49 client1.pub
$ cat /etc/wireguard/client1.key
YBwK1N1O7OwOEtWCFnxwF9aVB0GK5YUNxEtU1pyVuUs=
$ cat /etc/wireguard/client1.pub
LnEReQTHUY7FIMaAR6qVcCfk95ucPY6O/zb4OfdfYh4=
Figure 2: Creating the cryptographic keys is reminiscent of SSH. Repeat the commands on every computer that is involved.

Building an Interface

The next step is to create one virtual network interface per device for WireGuard. This is the equivalent of eth0 or wlan0. However, since traffic is tunneled separately with WireGuard, the system requires one interface for routing. The default for the first interface in WireGuard is wg0 (which we will use for simplicity's sake). If you prefer a different name, this is not a problem as long as you use it consistently.

The interface you created requires a specific IP range. In order to distinguish it from the 192.168.<x>.<y> common on LANs, use IPs from the private network address range 10.0.10.x [7] for wg0, which you then make available to the outside world via masquerading [8]. For the configuration, save Listing 4 (server) and Listing 5 (client) in the /etc/wireguard/wg0.conf file.

Listing 4

Server Configuration

[Interface]
Address = 10.0.10.1/24,fd42:42:42::1/64
SaveConfig = true
PrivateKey = <Key from client1.key>
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -j MASQUERADE; iptables -A FORWARD -o wg0 -j ACCEPT
PostUp = ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -j MASQUERADE; ip6tables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -F; iptables -t nat -F
PostDown = ip6tables -F; ip6tables -t nat -F
DNS = <IP Address of the WLAN Router>
[Peer]
PublicKey = <Key from client2.pub>
AllowedIPs = 10.0.10.2/32,fd42:42:42::/64

Listing 5

Client Configuration

[Interface]
Address = 10.0.10.2/32,fd42:42:42::2/64
PrivateKey = <Key from client2.key>
DNS = 10.0.10.1
[Peer]
PublicKey = <Key from client1.pub>
Endpoint = <beispiel.dyndns.com>:51820
AllowedIPs = 0.0.0.0/0,::/0
PersistentKeepalive = 20

Be sure to enter the cryptographic keys from the key files. You will also want to tell the server to use the WLAN router as a DNS server using the DNS = [...] line. The WireGuard client, on the other hand, needs to use the DNS = 10.0.10.1 option to query the WireGuard computer as its DNS server. The server configuration includes the same rules for starting up and shutting down the interface.

WireGuard uses port 51820 as the default port. If you want to use a different port, adjust the ListenPort = 51820 line accordingly. You then control the connection setup with the command:

sudo wg-quick up wg0

You can shut down the VPN again by typing:

sudo wg-quick down wg0

The sudo wg command tells WireGuard to display information on the current status (Figure 3). To activate wg0 automatically at system startup time, type the following command on both computers:

sudo systemctl enable wg-quick@wg0
Figure 3: The sudo wg command delivers information and statistics on the status of your WireGuard VPN.

UFW

The easiest way to configure the port sharing settings is via the Uncomplicated Firewall (UFW) iptables front end (Listing 6), which is preinstalled on Ubuntu and included in most distributions' package sources. There is also the Gufw graphical interface. After installation, if necessary, allow port 22/TCP for SSH on both devices and open 51820/UDP or your chosen port (Figure 4).

Listing 6

Configuring Port Sharing with UFW

$ sudo ufw allow 22/tcp
$ sudo ufw allow <51820>/udp  ### Or the port chosen by the system
$ sudo ufw enable
$ sudo ufw status verbose
Status: Active
Logging: on (low)
Default: deny (incoming), allow (outbound), deny (sent)
New profiles: skip
To                         Action      From
--                         ------      ---
22/tcp                     ALLOW IN    Anywhere
51820/udp                  ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)
51820/udp (v6)             ALLOW IN    Anywhere (v6)
Figure 4: Using UFW, you can allow access via SSH and open up the port for WireGuard. Setting up the iptables firewall is not absolutely necessary, but it does give the system additional security.

Conclusions

If you have no errors in the configuration, you should be able to ping the other IP address. From our personal experience, we found that configuration errors can happen easily. However, WireGuard can be set up quite quickly with about an hour of concentrated work. You can then extend the configuration to include additional clients, such as Android smartphones, using the same principle.

Infos

  1. WireGuard: https://www.wireguard.com/
  2. "Linux Torvalds Is Hoping WireGuard Will Be Merged Sooner Rather Than Later" by Michael Larabel, August 3, 2018, https://www.phoronix.com/scan.php?page=news_item&px=Linus-Likes-WireGuard
  3. ChaCha20: https://cr.yp.to/chacha.html
  4. Curve25519: https://cr.yp.to/ecdh.html
  5. Installation: https://www.wireguard.com/install
  6. DynDNS Service: https://dyndnss.net/eng/
  7. Private IP addresses: https://en.wikipedia.org/wiki/Private_network
  8. Masquerading: https://www.tldp.org/HOWTO/IP-Masquerade-HOWTO/ipmasq-background2.1.html