WireGuard VPN Setup on Ubuntu 20.04

Mike Holownych
12 min readSep 28, 2021

--

Setting up a WireGuard VPN server couldn’t be easier! This tutorial will go through the steps to easily and quickly setup a WireGuard VPN server on your Ubuntu Linux machine.

What is a VPN?

VPN, or Virtual Private Networking, provides an encrypted tunnel between the VPN server and the VPN client. All public internet data is transmitted through this tunnel, allowing the VPN client to effectively be a part of the remote VPN server’s local network. Historically, this is how companies have enabled their employees to work remotely, regardless of their location, as if in the office.

The encrypted connection makes the data transmitted more secure from sniffing from ISPs or hackers. For this reason, this technology has been used extensively by those that are downloading stuff using Bittorrent clients or Kodi streaming addons. There are a variety of protocols that can be used to accomplish this.

Various VPN Protocols

Each of these different protocols provide different levels of encryption and overheads, which ultimately affect performance (connection speed, bandwidth, etc).

Current status of VPN

VPNs have been in use for a very long time. They are by no stretch of the imagination a new(er) technology. Like I metioned above, they are used by many organizations to enable their remote workforce to be able to work securely as though they are in the office on the local network.

Many of these VPN technologies are out of date and haven’t updated with the times. They are limited in ability to provide effective network speeds, despite the ever-improving network bandwith available. In the corporate world, this has led to companies looking at other means of providing secure connectivity to the office — like zero-trust proxies. This, though, is outside of the scope of this particular tutorial.

A relatively new addition to the VPN technology space, Wireguard VPN, is revolutionizing how VPNs are utilized. Their technology has improved the speed and overhead requirements of traditional VPNs.

Benefits of WireGuard VPN

WireGuard has many advantages over the older, some say archaic, VPN protocols such as OpenVPN and IPsec.

Simplicity: There is nothing simple about the WireGuard VPN protocol, though all the work and effort that has been put into this new protocol has ensured that it can be easily audited, is less prone to attacks, and is accessible to a greater variety of people.

Faster: WireGuard VPN connections are negotiated much faster than older VPN protocols.

Easier Setup: There has been a lot of specialized knowlege required for effectively setting up OpenVPN or IPsec VPNs in the past. WireGuard has simplified this setup and configuration allowing for easier adoption.

Performance: The elegance of the code is that it builds on modern and efficient technology to deliver secure internet traffic MUCH faster due to lower overhead with much simpler setup effort.

Note: While IPsec has the potential to be quite a bit faster than WireGuard, it is also quite a bit more difficult to setup. IPsec is very much an enterprise VPN technology requiring highly specialized knowledge and experience to setup properly.

Install WireGuard

For the purpose of this tutorial, I will be outlining the steps to install and configure WireGuard VPN on Ubuntu 20.04. There are a great deal of other options available for other systems which you can find on the WireGuard website.

WireGuard is available on nearly every popular platform!

WireGuard installation is the easy part. Configuration is a bit more time consuming, though not at all complex.

WireGuard Prerequisites

- Just about any Linux distribution, Router, Windows or Mac with root (Administrator) privileges.

- Familiarity with the Linux command line (except for Windows installations).

- Public IP address (exposed to the internet) or a domain name pointing to your server.

WireGuard setup on Ubuntu 20.04

Since we’re working with an Ubuntu server, installation is quick and painless:

sudo apt update && sudo apt install wireguard

Any dependencies for WireGuard cryptography (encryption) will be checked and installed if required automatically. That’s it. WireGuard is now installed and ready to be configured.

Server Key Generation and Configuration

WireGuard comes with included utilities to allow us to quickly and easily create public/private keypairs. These are used to authenticate incoming traffic to the server. You can think of the private key like the lock on a door, while the public key is like the physical key used to unlock it. The server’s private key should never be shared with anyone! The public key is what gets shared with the clients so that they can connect to the server.

Both of these keys, but ESPECIALLY the private key, must be kept secure. DO NOT send these to your friends or anyone for that matter over an insecure protocol like Facebook Messenger or likewise!

Wireguard Key Security Preparation

To keep everything secure, change to your root account while we run the next set of commands:

sudo -i

cd /etc/wireguard

umask 077

We use the command umask to set permissions for any files we are about to create. Umask is subtractive, in that it removes permissions. In the command above, we are removing all permissions (noted by the 7’s) from “group” and “other” users.

Note: The permission mask only lasts for the current session. When you logout you will need to use the umask command again to ensure that any newly created credentials have the same restricted permissions.

Generate the Private Key (AKA the Lock)

First step is to create the private key. The below set of commands will always start with wg, which is the first set of WireGuard tools we will be using.

wg genkey > server.key

The above command will, by default, output the result to the screen. Since we use the > modifier, the result will instead be pushed into a file (and create the file, if it doesn’t exist). Be aware that this particular modifier will replace any existing content in the file if it already exists.

The above command generated our private key and exported it to a new file called server.key.

Generate the Public Key (AKA the Key)

The next command looks very similar to the previous one, just a little longer. This time, we will use the

server.pub

The result of the above command generates our public key and exports it into a new file called server.pub. The public key is one of the components that will be required to initiate the client connection to the WireGuard server.

With those two components generated, we can now create our WireGuard configuration file, which will allow us to startup the WireGuard server.

Server Configuration File

To configure the WireGuard server, we create the file wg0.conf in the default WireGuard directory (/etc/wireguard). This file will be read by the WireGuard server on startup to create a virtual interface.

You can think of the virtual interface as the door that holds the lock that our key will open. We are adding a virtual ethernet (or wifi) adapter — except that any data that passes through it is automatically encrypted and sent to the other WireGuard device(s).

nano /etc/wireguard/wg0.conf

Add the following lines to the beginning of the file:

Address = 10.2.0.1/24

ListenPort = 51820

SaveConfig = True

Save and close the file. Here we are setting the digital wg0 interface to run on a local set of IP’s. This isn’t strictly required, but helps to organize your machine so there are no conflicts or overlapping IP addresses later on. Note that you can choose any set of IP’s in the private IP ranges (192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12).

We have attached the /24 CIDR notation to the end of the IP address to indicate that it can use a range of addresses. For example, /24 in this scenario represents all addresses from 10.254.0.1 to 10.254.0.254. This gives us the potential to have 253 clients.

The listening port is arbitrary. Select any port you like as long as it’s above 1024 (well-known/system ports), with somewhere between 49152 and 65535 recommended (private/ephemeral ports).

Lastly, we will add our private key (“lock” in the above references) into the configuration. You can output the file to screen using the cat command, copy it, open the file again, and paste it. Or, to do the same thing in a single step we can use the echo command:

echo “PrivateKey = $(cat server.key)” >> /etc/wireguard/wg0.conf

Notice how we use $(cat …). This notation means we will run the command inside the parentheses before the remainder of the command. We are then using echo to print the output to the screen. However, instead of showing it onscreen, we use the >> to append (or add it to the end) the output to the WireGuard configuration file. Note how this is different than using a single > which would overwrite our entire file!

That’s all. We will need to revisit the configuration file shortly, but this is all that’s needed to get the WireGuard server started.

Your finished config file should look something like this (the private key will be different, as mine is just an example):

Address = 10.2.0.1/24

ListenPort = 51820

SaveConfig = True

PrivateKey = mBQr1vM/YKd96WQnRdwq1kQAWMXo7ZcyhKna6ntBLGE=

For now we can logout of the root account, either using Cmd + D or typing:

exit

Starting the WireGuard Server

Wireguard comes with a builtin tool which takes care of most internal networking configuration. This tool will create the new digital WireGuard interface for us and set basic configurations. It will continue to run in the background as a system service. The name of the interface will match the name of the config file we just created.

Startup the WireGuard Server

sudo wg-quick up wg0

The wg-quick utility will attempt to create a new Wireguard interface using the wg0.conf file.

This should give you a sample output similar to this:

ip link add wg0 type wireguard

wg setconf wg0 /dev/fd/63

ip -4 address add 10.2.0.1/24 dev wg0

ip link set mtu 1420 up dev wg0

Enable WireGuard Startup at Boot

To ensure that the Wireguard service is started at system boot, we can enable the service with the following command:

sudo systemctl enable wg-quick@wg0

Systemctl is part of systemd. Systemd controls services and special types of programs that continuously run in the background.

Your Wireguard server is now running!

Server Status

By typing the following command, we can easily have a look at the status:

sudo wg show

You should see something like this:

you@yourserver:~$ sudo wg show

interface: wg0

public key: TeX4gm4EnBY0l3tKhoVsARR7EEi4zcN/TwMo+RdmiiM=

private key: (hidden)

listening port: 51820

We can see that it is running; and we can also see that it’s listening for connections by using the netstat command:

you@yourserver:~$ sudo netstat -uln

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address Foreign Address State

udp 0 0 0.0.0.0:51820 0.0.0.0:*

udp6 0 0 :::51820 :::*

Wireguard is listening on our desired port!

Port Forwarding and Firewalls

If your server is behind a router (like a WiFi router or ISP provided WiFi modem), you will need to forward the selected port (51820 in my case) to the server so that your clients can actually reach the WireGuard server from the public internet. Without this, any request from outside your network will never actually reach your WireGuard server.

If you are running a firewall on your Ubuntu server, you can open up the port quickly with the following command:

sudo ufw allow 51820/udp

So, now we have a functioning WireGuard server that is fully configured and accessible from the public internet. Let’s create a client configuration file and allow it to connect to our server.

Adding Clients to your WireGuard Server

Wireguard is a very simple server, but it should be noted that it does not automatically assign IP addresses like a DHCP server will. We will need to manually assign IP addresses to each client we wish to use Wireguard. This is done with client configuration files.

Create a Client Configuration File

By creating a set of client credentials, we give our devices (like a phone or computer) its own set of “lock” and “key” just like we did for the server. These private and public keys will be used to authenticate with our server. Our server has one “lock” and our client has the “key” to it. Our client also has its own separate “lock” and the server will be given the specific “key”.

This is to ensure only the desired traffic is allowed to connect and go through our Wireguard server. We can add as many clients as well like by creating a new set of credentials for each.

Secure Key Preparation

Like before, we will keep everything secure, but more accessible. As your user, let’s create a directory in our home folder to hold credentials.

cd ~

umask 077

mkdir wireguard && cd wireguard

mkdir client1 && cd client1

Notice that I also created a directory called client1. Call it anything you like, I normally go with something identifiable like “frank-phone” and create a new directory for each of my devices.

Client Key Generation

Just as we did for the server, we will create private and public keys for our client device plus another unique key called a Pre-Shared Key (PSK), for added security. These 3 keys will allow us to create a client.

wg genkey > client1.key

wg pubkey < client1.key > client1.pub

wg genpsk > client1.psk

The only new piece here is the additional Pre-Shared Key (PSK). The PSK is optional, but adds significant security and is very easy to add. If you’ve been following the “lock” and “key” theme so far, this PSK is akin to making the public “key” continuously changing, cloaking its “shape”. Both the client and the server need a copy of this final PSK element.

Prepare the Client Config File

Many clients can read directly from this file, so we will set it up in a familiar format to the server configuration file from before:

nano client1.conf

Paste in the following:

Address = 10.2.0.2/32

Save and close. Notice how the IP address changed: We incremented it above our Wireguard server’s IP (10.2.0.1 in this Wireguard tutorial) and used /32 which only allocates a single address. We essentially defining the IP address for the connecting client.

Note: You will need to increase the last number (octet) by 1 for each additional client you configure in the future.

Let’s add our private key to the end, using the same set of embedded commands as before:

echo “PrivateKey = $(cat client1.key)” >> client1.conf

This top portion of the file will help setup the interface (like a virtual WiFi adapter for your traffic to go through) on your client/device. Now we need to add the server connection details to our client configuration so the device knows where to connect to. It will be added as a “peer”. Using the same “echo” trick from before, we run the following:

echo “” >> client1.conf

echo “Endpoint = 123.456.789.111:51820” >> client1.conf

echo “AllowedIPs = 10.2.0.0/24” >> client1.conf

echo “PublicKey = $(sudo cat /etc/wireguard/server.pub)” >> client1.conf

echo “PresharedKey = $(cat client1.psk)” >> client1.conf

Endpoint is the public IP address of your server that we want our device to connect to. Replace the 123.456.789.111 IP address with your server’s public IP or the domain name of your server.

The AllowedIPs setting let’s us control what IP’s in our network we will have access to. For now we will only focus on connecting to your Wireguard server, so leave this as is.

We then add the public key of our server (not the client). This gives the client the “key” to our server’s “lock”.

Finally we add additional security with the Pre-Shared Key. This is the “cloaking” mechanism so our “key” cannot be cracked.

Add Client1 to your Server Config

Now that the client knows how to find the server, the server needs to know that the client is allowed to connect. We must add our client as a “peer” to the end of our server config file. Let’s use the same echo trick as above to append the details to our server config file as the superuser:

sudo -i

cd /etc/wireguard

echo “” >> wg0.conf

echo “AllowedIPs = 10.2.0.2/32” >> wg0.conf

echo “PublicKey = $(cat /home/you/wireguard/client1/client1.pub)” >> wg0.conf

echo “PresharedKey = $(cat /home/you/wireguard/client1/client1.psk)” >> wg0.conf

Be sure to change the file path inside the cat commands to read the correct files. This completes the exchange of “keys” so that both server and client can communicate.

We’ve now given the client access details for the server (using the public key and pre-shared key), and given our server the details of the client’s credentials as well.

Our server config (wg0.conf) should look like the following (with different keys):

Address = 10.2.0.1/24

ListenPort = 51820

SaveConfig = True

PrivateKey = mBQr1vM/YKd96WQnRdwq1kQAWMXo7ZcyhKna6ntBLGE=

Allowed IPs = 10.2.0.2/32

PublicKey = Von//x4+3A6vRRN5MssjMROxRmYZfUDk9IjLOsZfjVs=

PreSharedKey = IDqQRJy8S69sQU/hhSIVMMyqFrWwu84JOdXmQm3/DMg=

Now all we need to do is restart the Wireguard server to pickup the changes to our configuration file. We can accomplish this one of two ways:

wg-quick down wg0

wg-quick up wg0

This will stop and remove the interface, and then recreate it with the modified configuration. The second option is a sort of soft-reset which does not disrupt any ongoing connections to your Wireguard server:

wg syncconf wg0

--

--

Mike Holownych

Mike is an ITSM Pro who specializes in IT Ops while managing and developing high-performing teams.