Wireguard is a modern and very easy to setup VPN available on multiple operating system. The application is available in the Ubuntu 20.04 official repositories, so it is also very easy to install. Unlike other software like OpenVPN which is based on the use of ssl certificates, Wireguard is based on the use of key-pairs. In this tutorial we will see how to configure, in few easy steps, a VPN server and a client peer on the latest stable version of Ubuntu.
In this tutorial you will learn:
- How to install Wireguard on Ubuntu 20.04 Focal Fossa
- How to create public and private key pair
- How to configure the server and a client peer
- How to redirect all incoming traffic to the VPN
Software Requirements and Conventions Used
|Category||Requirements, Conventions or Software Version Used|
|System||Ubuntu 20.04 Focal Fossa|
|Conventions||# – requires given linux commands to be executed with root privileges either directly as a root user or by use of
$ – requires given linux commands to be executed as a regular non-privileged user
Wireguard is officially available in the “universe” repository of Ubuntu 20.04, therefore we can install it via
apt. The available version, at the moment of writing is
$ sudo apt install wireguard
The system will ask us to confirm we want to install the program and its dependencies, and will complete the operation in a matter of seconds.
We must generate a public and a private key for each machine we want to use in our VPN. The private key should be kept secret on the machine, the public one is used to access the machine from the other peers.
To generate the keys we can use the
wg utility. Inside the Wireguard configuration file we will need to reference the private key of the machine, while the public one will be used on the other peers. Notice that we will reference the keys directly, so theoretically we don’t need to store them to files. We will, however do it anyway, just for convenience.
To generate the private key for our server, we must use the
genkey subcommand of
wg. The command outputs the created key to
stdout; to write the key to a file we can use the power of shell redirections:
$ wg genkey > server_private_key
The command will generate the key and store it to the
server_private_key file, but will raise the following warning:
Warning: writing to world accessible file. Consider setting the umask to 077 and trying again.
This is because with the default user umask (
002) the files are created with mode
664, so are world-readable, which is not recommended. To solve this problem we can either change the umask used in the current shell session before creating the files:
$ umask 077
Or change the files permissions to
600 after creation. Here we will go for the latter solution.
Once our private key is ready, we can generate the public one which is based on it. To accomplish the task we use the
pubkey subcommand of
wg. Just as before we use shell redirections: first to pass the content of the
server_private_key file to the
stdin of the command, and then and to redirected the generated key to the
$ wg pubkey < server_private_key > server_public_key
To spare some typing we can generate both keys, with just one command, which involves the use of the shell
| (pipe) operator and the
$ wg genkey | tee server_private_key | wg pubkey > server_public_key
The output of the command on the left side of the pipe operator (
|) is passed to the standard input of the program on its right side. The
tee command, instead allow us to redirect the output of a command to both a file and to standard output ( more about shell redirections here).
Once our keys are ready we can create the server configuration file.
Server configuration file
To configure our Wireguard installation, we can create a configuration file called
wg0.conf with the following content:
[Interface] PrivateKey = <private key of the server (the content of the server_private_key file)> Address = 10.0.0.1/24 ListenPort = 51820
Notice that the name of the file is arbitrary, but it should be based on the name we will use for our interface,
wg0 in this case. This name will be referenced when starting the service, as we will see below.
In our example. the
[interface] section of the configuration file contains the following fields:
The PrivateKey field value is nothing more than the server private key we generated earlier.
In the Address field we specified the address to assign to the interface in the VPN together with the subnet mask using the CIDR notation. In this case we used
10.0.0.1/24, so our Wireguard “server” address inside the VPN will be
10.0.0.1, which is in the available range of addresses that goes from
Finally, in the ListenPort field, we specified what port Wireguard will listen on for incoming traffic. A rule to allow said traffic must also be added to our firewall. We will do this in the next section.
We can now change the permissions of the files and move them to the
$ chmod 600 server_public_key server_private_key wg0.conf $ sudo mv server_private_key server_public_key wg0.conf /etc/wireguard
We can now start the
wg-quick service specifying the name of the Wireguard interface after
@ in the unit name. What is this notation? It is a feature of systemd: with it we can generate multiple unit files on the base of a “template” one, passing the value that will be substituted in the template, after the
@ symbol in the name of the unit. This is the content of the
[Unit] Description=WireGuard via wg-quick(8) for %I After=network-online.target nss-lookup.target Wants=network-online.target nss-lookup.target Documentation=man:wg-quick(8) Documentation=man:wg(8) Documentation=https://www.wireguard.com/ Documentation=https://www.wireguard.com/quickstart/ Documentation=https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8 Documentation=https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8 [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/wg-quick up %i ExecStop=/usr/bin/wg-quick down %i Environment=WG_ENDPOINT_RESOLUTION_RETRIES=infinity [Install] WantedBy=multi-user.target
The value we will specify after the
@ in the unit name when starting or stopping it, will replace
%i in the
ExecStop lines. In this case we will use
$ sudo systemctl enable --now wg-quick@wg0
With the command above we started the service and also make so that is automatically started at boot. To verify our configuration has been applied we can run the
wg command. The output produced should display information about the
$ sudo wg interface: wg0 public key: nNx3Zpcv9D2dtgHDsoYGBNr64zG5jTJ4Z4T2sE759V4= private key: (hidden) listening port: 51820
Now, let’s proceed and configure our firewall and packet forwarding.
Firewall and network setup
In this tutorial I will assume the use of
ufw. As we said before, we must add a rule to allow incoming traffic through the port we specified in the configuration file,
51820. We do it by running a very simple command:
$ sudo ufw allow 51820/udp
We also need to allow packet forwarding on our system. To accomplish the task we to remove the comment from line
28 of the
/etc/sysctl.conf file, so that it looks like this:
# Uncomment the next line to enable packet forwarding for IPv4 net.ipv4.ip_forward=1
To make the changes effective without rebooting the system, we need to run the following command:
$ sudo sysctl -p
In the next step we will configure the client.
Client key generation
Let’s now move on the system we want to use as a client. We need to install Wireguard on it; once done, we can generate a key-pair just as we did on the server:
$ wg genkey | tee client_private_key | wg pubkey > client_public_key
Just like we did server-side we create the
wg0.conf configuration file. This time with this content:
[Interface] PrivateKey = <client_private_key> Address = 10.0.0.2/24 [Peer] PublicKey = <server_public_key> EndPoint = <server_public_ip>:51820 AllowedIPs = 0.0.0.0/0
We already saw the meaning of the fields contained in the
Interface section, when we generated the server configuration. Here we just adapted the values to our client (it will have the
10.0.0.2 address in the VPN).
In this configuration, we used a new section,
[Peer]. In it, we can specify the information relative to a peer, in this case the one we use as a “server”. The fields we used are:
In the PublicKey field, we specify the public key of the peer, so, in this case, the public key we generated on the server.
The EndPoint is the public IP address or hostname of the peer followed by a colon and the port number the peer listens on (in our case
Finally, the value passed to the AllowedIPs field, is a comma-separated list of IP addresses and subnet mask with CIDR notation. Only traffic directed to the peer which comes from the specified addresses will be allowed. In this case we used
0.0.0.0/0 as a value: it works as a “catch-all” value, so all the traffic will be sent to the VPN peer (the server).
Just like we did server-side, we set the appropriate permissions and move the keys and the configuration file to the
$ chmod 600 client_public_key client_private_key wg0.conf $ sudo mv client_public_key client_private_key wg0.conf /etc/wireguard
With the configuration file in place, we can start the service:
$ sudo systemctl enable --now wg-quick@wg0
[Peer] section relative to our client, must be added to the configuration file we previously created on the server. We append the following content to it:
[Peer] PublicKey = <public key of the client> AllowedIPs = 10.0.0.2/32
At this point we restart the service:
$ sudo systemctl restart wg-quick@wg0
The information about the associated peer should be now reported in the output of the
$ sudo wg interface: wg0 public key: nNx3Zpcv9D2dtgHDsoYGBNr64zG5jTJ4Z4T2sE759V4= private key: (hidden) listening port: 51820 peer: t5pKKg5/9fJKiU0lrNTahv6gvABcmCjQq5gF3BxwiDQ= allowed ips: 10.0.0.2/32
At this point, from the “client” system, we should be able to ping the server at the
$ ping -c 3 10.0.0.1 PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data. 64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=2.82 ms 64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=38.0 ms 64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=3.02 ms --- 10.0.0.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 2.819/14.613/37.999/16.536 ms
In this tutorial we saw how to create a VPN using Wireguard on the latest stable version of Ubuntu: 20.04 Focal Fossa. The software is really simple to install and configure, especially if compared to other solutions, as for example OpenVpn.
We saw how to generate the public and private keys used for our setup, and how to configure both the server and a client so that all traffic is redirected to the VPN. Following the given instruction you will have a working setup. For more information, please take a look at the project page.