How to set up WireGuard VPN server on Ubuntu 20.04

What we’re talking about

This post covers how to configure the WireGuard VPN server. All of our clients will connect to this machine first, then route out to the Internet. This is what it looks like:

https://serversideup.net/wp-content/uploads/2020/05/Wireguard-Diagram-Server-1-300x267.png 300w, https://serversideup.net/wp-content/uploads/2020/05/Wireguard-Diagram-Server-1-768x683.png 768w, https://serversideup.net/wp-content/uploads/2020/05/Wireguard-Diagram-Server-1-1536x1366.png 1536w, https://serversideup.net/wp-content/uploads/2020/05/Wireguard-Diagram-Server-1-2048x1821.png 2048w, https://serversideup.net/wp-content/uploads/2020/05/Wireguard-Diagram-Server-1-709x630.png 709w" alt="" width="1024" height="911" class="wp-image-2648 medium-zoom-image" style="box-sizing: border-box; border-width: 0px; border-style: solid; border-color: rgba(229,231,235,var(--tw-border-opacity)); --tw-border-opacity: 1; --tw-shadow: 0 0 #0000; --tw-ring-inset: var(--tw-empty, ); --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; height: auto; max-width: 100%; display: block; vertical-align: bottom; cursor: zoom-in; transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) 0s !important; margin-top: 0px; margin-bottom: 0px; padding-left: 5.25rem; padding-right: 5.25rem;" decoding="async" loading="lazy" />

Prerequisites

We will be installing WireGuard VPN on a brand new Ubuntu 20.04 LTS server. I assume you have:

  • A server (you can get a server for $5 with Digital OceanVultr, or Linode)
  • Root access
  • Ability to open firewall ports (if you have a separate firewall that sits in front of your server)

Prepare your server

Once you have your server up and running, connect via SSH. Always run updates before running any installations.

sudo apt update && sudo apt upgrade

Check to see if your server needs a reboot:

cat /var/run/reboot-required

If it comes back with *** System restart required ***, then you need to restart your server:

sudo reboot

Install WireGuard VPN Server

Since we are on the latest version of Ubuntu 20.04, the install is very easy:

sudo apt install wireguard

It is possible to install this on Ubuntu 18.04 too, but you will need to follow the Ubuntu ≤ 19.04 steps listed on WireGuard’s website

Generate server keys

Just like SSH, we need a pair of public and private keys in order for our server to work.

sudo mkdir -p /etc/wireguard/keys; wg genkey | sudo tee /etc/wireguard/keys/server.key | wg pubkey | sudo tee /etc/wireguard/keys/server.key.pub

This places our keys under our /etc/wireguard/keys directory that we created. DO NOT share your private key with anyone else, otherwise your VPN will be compromised.

We will need to reference the private key for configuration in the future. You can view your private key by running the cat command:

cat /etc/wireguard/keys/server.key

Determine your “default” interface

We will need to know what is your default network interface for connecting to the Internet. Run this command to find out:

ip -o -4 route show to default | awk '{print $5}'

Mine returned back eth0, so I will be using eth0 for my interface in the rest of the guide.

Configure the “wireguard interface”

WireGuard works by adding a network interface to our server. Just like how we saw eth0 before, we will be adding a network interface called wg0.

We need to create a file called /etc/wireguard/wg0.conf

sudo nano /etc/wireguard/wg0.conf

Contents of /etc/wireguard/wg0.conf:

[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = YOUR_SERVER_PRIVATE_KEY
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
SaveConfig = true

IMPORTANT: You need to replace YOUR_SERVER_PRIVATE_KEY and set the default interface on PostUp and PostDown (mine is eth0 in this example).

TO SAVE: While in nano, press CTRL + O to save and CTRL + X to quit.

If you want to know what the heck these configuration options mean, I go through these configuration options in detail in an earlier post. I would recommend reading that if you want to learn more.

Set proper permissions

We need to make sure that our configuration and private key are only accessible by the root user.

sudo chmod 600 /etc/wireguard/wg0.conf /etc/wireguard/keys/server.key

Bring up the “wireguard interface”

Run this command to “bring up” the wg0 interface we just created:

sudo wg-quick up wg0

You should get output similar to the screenshot below

https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-Wireguard-InterfaceUp-300x149.png 300w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-Wireguard-InterfaceUp-768x382.png 768w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-Wireguard-InterfaceUp-1536x763.png 1536w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-Wireguard-InterfaceUp-1200x596.png 1200w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-Wireguard-InterfaceUp.png 2020w" alt="" width="1024" height="509" class="wp-image-2548 medium-zoom-image" style="box-sizing: border-box; border-width: 0px; border-style: solid; border-color: rgba(229,231,235,var(--tw-border-opacity)); --tw-border-opacity: 1; --tw-shadow: 0 0 #0000; --tw-ring-inset: var(--tw-empty, ); --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; height: auto; max-width: 100%; display: block; vertical-align: bottom; cursor: zoom-in; transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) 0s !important; margin-top: 0px; margin-bottom: 0px; padding-left: 5.25rem; padding-right: 5.25rem;" decoding="async" loading="lazy" />

We can check the status of the wg0 interface by running this command:

sudo wg show wg0
https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-Wireguard-Status-300x149.png 300w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-Wireguard-Status-768x382.png 768w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-Wireguard-Status-1536x763.png 1536w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-Wireguard-Status-1200x596.png 1200w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-Wireguard-Status.png 2020w" alt="" width="1024" height="509" class="wp-image-2549 medium-zoom-image" style="box-sizing: border-box; border-width: 0px; border-style: solid; border-color: rgba(229,231,235,var(--tw-border-opacity)); --tw-border-opacity: 1; --tw-shadow: 0 0 #0000; --tw-ring-inset: var(--tw-empty, ); --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; height: auto; max-width: 100%; display: block; vertical-align: bottom; cursor: zoom-in; transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) 0s !important; margin-top: 0px; margin-bottom: 0px; padding-left: 5.25rem; padding-right: 5.25rem;" decoding="async" loading="lazy" />

Start the “wireguard interface” automatically at boot

We can have the server automatically bring up the wg0 VPN interface at boot:

sudo systemctl enable wg-quick@wg0>

Configuring server networking & firewall

We need to allow traffic forwarding in order for the VPN to work correctly.

Allow traffic forwarding

We will need to modify the /etc/sysctl.conf file.

sudo nano /etc/sysctl.conf

You need to uncomment the line that says net.ipv4.ip_forward=1. It should look like this:

https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-WireguardVPN-IPForwarding-300x149.png 300w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-WireguardVPN-IPForwarding-768x382.png 768w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-WireguardVPN-IPForwarding-1536x763.png 1536w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-WireguardVPN-IPForwarding-1200x596.png 1200w, https://serversideup.net/wp-content/uploads/2020/05/Ubuntu20.04-WireguardVPN-IPForwarding.png 2020w" alt="" width="1024" height="509" class="wp-image-2561 medium-zoom-image" style="box-sizing: border-box; border-width: 0px; border-style: solid; border-color: rgba(229,231,235,var(--tw-border-opacity)); --tw-border-opacity: 1; --tw-shadow: 0 0 #0000; --tw-ring-inset: var(--tw-empty, ); --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; height: auto; max-width: 100%; display: block; vertical-align: bottom; cursor: zoom-in; transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) 0s !important; margin-top: 0px; margin-bottom: 0px; padding-left: 5.25rem; padding-right: 5.25rem;" decoding="async" loading="lazy" />

TO SAVE: While in nano, press CTRL + O to save and CTRL + X to quit.

Apply our changes after saving:

sudo sysctl -p

Open the WireGuard server port

In our config file, we set our listening port to 51820. This uses UDP, so we will need to open that port on the built-in Ubuntu software firewall on our server using ufw.

sudo ufw allow 51820/udp

Let’s allow SSH too:

sudo ufw allow 22/tcp

Now enable the firewall:

sudo ufw enable

You can verify everything by checking the status

sudo ufw status verbose

If you have a hardware firewall in front of your server, you will need to open up the UDP port on your firewall/router.

Adding clients

Your server is now ready to add clients. Before you do that, it is important to understand how authentication works. I cover the important concepts in an earlier post, but what I want to illustrate for you right now is that we do need to add the client’s public key to our server. Without this, anyone would be able to connect.

The “quick solution” to this is to run this command on your server the wg set command on your server:

sudo wg set wg0 peer YOUR_CLIENT_PUBLIC_KEY allowed-ips YOUR_CLIENT_VPN_IP

IMPORTANT: You need to replace YOUR_CLIENT_PUBLIC_KEY and YOUR_CLIENT_VPN_IP

If the “quick solution” is not enough, I have specific instructions how to configure each type of client. Pick what you need:

Checking a trillion combinations per second, and running continuously for 40 years you'd go through 1.261×1021 keys. That's one sextillion, 261 quintillion! Sure sounds impressive, doesn't it? It is, but even so, you'd have made no progress... that rather impressive number still only amounts to about 0.000000000000000000000000000000000000000000000000000001% of the keyspace.

What if you can go faster, you ask? Let's go as fast as physics will let us go, cost and technological constraits be damned. Here's what Bruce Schneier had to say about brute-forcing 256-bit symmetric keys in the seminal tome Applied Cryptography:

One of the consequences of the second law of thermodynamics is that a certain amount of energy is necessary to represent information. To record a single bit by changing the state of a system requires an amount of energy no less than kT, where T is the absolute temperature of the system and k is the Boltzman constant. (Stick with me; the physics lesson is almost over.)

Given that k = 1.38×10-16 erg/°Kelvin, and that the ambient temperature of the universe is 3.2°Kelvin, an ideal computer running at 3.2°K would consume 4.4×10-16 ergs every time it set or cleared a bit. To run a computer any colder than the cosmic background radiation would require extra energy to run a heat pump.

Now, the annual energy output of our sun is about 1.21×1041 ergs. This is enough to power about 2.7×1056 single bit changes on our ideal computer; enough state changes to put a 187-bit counter through all its values. If we built a Dyson sphere around the sun and captured all its energy for 32 years, without any loss, we could power a computer to count up to 2192. Of course, it wouldn't have the energy left over to perform any useful calculations with this counter.

But that's just one star, and a measly one at that. A typical supernova releases something like 1051 ergs. (About a hundred times as much energy would be released in the form of neutrinos, but let them go for now.) If all of this energy could be channeled into a single orgy of computation, a 219-bit counter could be cycled through all of its states.

These numbers have nothing to do with the technology of the devices; they are the maximums that thermodynamics will allow. And they strongly imply that brute-force attacks against 256-bit keys will be infeasible until computers are built from something other than matter and occupy something other than space.

The hilarious neutrino joke aside, the conclusion is inescapable (even though Schneier is talking about brute-forcing symmetric keys and we aren't quite dealing with those):

Brute-forcing of 256-bit seed phrases ain't happening until computers are built from something other than matter and occupy something other than space.

1. ‘diffusion-limited C-rate’ (DLC) introduced by Heubner et al. [A. Nickol, T. Schied, C. Heubner, M. Schneider, A. Michaelis, M. Bobeth and G. Cuniberti, J. Electrochem. Soc., 167(9), 90546 (2020).]. The DLC of a porous Li-insertion electrode determines the intrinsic rate performance limit caused by Li-depletion in the electrolyte. For C-rates higher that the DLC, the attainable capacity is reduced significantly.

In LiNi0.5Co0.2Mn0.3O2 For temperatures < 0°C, the charge transfer reaction at the solid/electrolyte interface becomes the limiting mechanism and makes the largest contribution to the total overpotential https://doi.org/10.1149/1945-7111/ac6243.

 Screenshot_from_2022-04-28_13-50-46.png