WireGuard is an open-source general-purpose VPN (Virtual Private Network) designed for fast, secure, and easy-to-use connections between devices. It uses state-of-the-art cryptography and is designed to be simple, lightweight, and efficient.
It is currently available on multiple platforms, including Linux, Windows, and macOS. It supports both IPv4 and IPv6 connections.
WireGuard uses public and private keys to establish encrypted tunnels between peers to ensure security. It is much faster compared to other VPN protocols such as OpenVPN and IPSec.
In this tutorial, we are going to learn how to set up WireGuard on an Ubuntu 22.04 server.
First, let’s take a look at the prerequisites needed for this tutorial and make sure you have everything ready before proceeding further.
Table of Contents
Pre-Requisites
For this tutorial, we need:
- An Ubuntu 22.04 server that supports both IPv4 and IPv6 connections.
- An Ubuntu 22.04 peer machine with which WireGuard Server will connect. We are using our local machine as our peer for this tutorial but a remote server can also be used.
- A non-root user with sudo privileges.
Execute the below commands in their respective order to make sure everything is up to date.
sudo apt update sudo apt upgrade
Now that we have fulfilled all the prerequisites, we can begin the tutorial. Follow this step-by-step guide to set up WireGuard on Ubuntu 22.04 server.
Install WireGuard
The first step is to install WireGuard VPN on our server. WireGuard will be installed when the below command is executed.
sudo apt install wireguard
You might be prompted to enter the sudo password when executing the above command. And then, the system will ask you whether you want to proceed with the installation. Enter Y to continue.
After the WireGuard installation is complete, it is time to generate the public and private keys needed for encrypted communication between peers.
Generate Keypair
First, we are going to generate a private key using the below command. The wg genkey
command is used to generate private keys while the wg pubkey
command is used to generate public keys.
wg genkey | sudo tee /etc/wireguard/private.key
The output of the above command is the private key, as shown in the picture below.
cFqdP6KW7gaOdeIlVIoXqHbMHhNmeZ2LaVj5vPBETmc=
The private key will be printed on the terminal. Make a note of it. A copy of this private key is also stored at /etc/wireguard/private.key
file.
Now we have to change access to this key file so that only root users can access the private key file. The below command will achieve this.
sudo chmod go= /etc/wireguard/private.key
Now the last step is to generate a corresponding public key to our private key. This is done by using the wg pubkey
command in the following way. First, take a look at the following command, and then we’ll dissect the command to understand it better.
sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
The above command will also return a single line output which is the public key associated with the private key we generated first. Make a note of this key, as any peer wishing to connect to the server will need this public key to get access.
Now let’s dissect the above command. The above command is made up of three different commands chained together using the | (pipe) operator:
sudo cat /etc/wireguard/private.key
: this command fetches the private key.wg pubkey
: this command takes the output of the first command as input and uses it to generate a respective public key.sudo tee /etc/wireguard/public.key
: this command takes the output public key and places it into the/etc/wireguard/public.key
file.
Select IPv4 and IPv6 Address
Now that we have installed WireGuard and generate key pairs that will be used to encrypt traffic from and to the server. We can proceed to the next step which is configuring the IPv4 and IPv6 addresses that will be used for communication between the Server and peers wanting to connect to it.
For IPv4
For IPv4 peers, the server needs a range of IPv4 addresses for clients and its tunnel interface. Any range of IP addresses can be selected from the following reserved blocks of addresses:
10.0.0.0 to 10.255.255.255 (10/8 prefix) 172.16.0.0 to 172.31.255.255 (172.16/12 prefix) 192.168.0.0 to 192.168.255.255 (192.168/16 prefix)
For this tutorial we are selecting the 10.8.0.0/24 block of IP addresses as this range will allow up to 255 peer connections. The WireGuard server is going to use the above-selected range to assign IPs to peers.
For IPv6
If you want to use WireGuard with IPv6, you will have to generate a unique IPv6 prefix based on the RFC algorithm.
According to RFC the best way to get a unique IPv6 prefix is to combine the time of the day with a unique value from the system such as a serial number or device ID. The resulting set of bits can be used as a unique address within the reserved private “fd00::/8” block of IPs once those values have been hashed.
To get started, collect a 64-bit timestamp for your system by executing the below command.
date +%s%N
The above command will generate an output similar to the one written below which is the time elapsed in seconds since the Unix Epoch (00:00 UTC 1 January 1970).
1662132483303862200
Make sure to note down this value too, along with the private and public keys, as all this information will be used in server configuration.
Next, copy the machine id for your server as this value is unique for every server. Execute the below command to get the machine id.
cat /var/lib/dbus/machine-id
8d87100241cbed3b363218d362a9f92f
Now the last step is to combine the timestamp and the machine id using the SHA-1 algorithm. It will also hash the result value. The general format of the command is written below.
printf <timestamp><machine-id> | sha1sum
Substitute your timestamp and machine id in the above command and run it. By inserting the above value, the command will look as follows (you should insert your own machine id and timestamp to generate a unique IPv6 prefix).
printf 16621324833038622008d87100241cbed3b363218d362a9f92f | sha1sum
The output will be a hash value similar to the one shown below.
a311a36a27ac476015998855190908d5a3acc4fd -
Now run the above command again combined with the cut
command to trim the above output in accordance with the RFC algorithm, which is to get the last 5 hexadecimal encoded bytes from the above hash.
printf a311a36a27ac476015998855190908d5a3acc4fd | cut -c 31-
d5a3acc4fd
In the above example output, the set of bytes is d5 a3 ac c4 fd
.
The IPv6 prefix is generated by appending the above 5 bytes with the fd
prefix while separating every 2 bytes with a ":"
for readability. And for simplicity, we are restricting the subnet size to /64
.
So the above output will become:
fdd5:a3ac:a4fd::/64
This fdd5:a3ac:a4fd::/64
will be used to assign IP addresses to your WireGuard tunnel interface. For example, to allocate an IP to the server, add 1 after the ::
character.
Configure WireGuard
Before beginning the configuration, make sure that you have executed the above steps and have the necessary data i.e private key, IPv4, or IPv6 address range.
Create a new configuration file using the nano text editor. You can use any other editor if you prefer.
sudo nano /etc/wireguard/wg0.conf
Now paste the following lines in the file while putting in your respective private key and IP address values.
[Interface] PrivateKey = cFqdP6KW7gaOdeIlVIoXqHbMHhNmeZ2LaVj5vPBETmc= Address = 10.8.0.1/24, fdd5:a3ac:a4fd::1/64 ListenPort = 51820 SaveConfig = true
Save the file by pressing Ctrl+X and then enter Y to exit.
Configure WireGuard Network
You do not need to complete this step if you are merely connecting a peer to the WireGuard Server to access server-side services.
To configure forwarding, open the /etc/sysctl.conf
file using nano
editor by executing the below line.
sudo nano /etc/sysctl.conf
The file looks like below:
Uncomment the following lines by removing the # sign.
For IPv4:
Uncomment the next line to enable packet forwarding for IPv4 net.ipv4.ip_forward=1
For IPv6:
# 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
If you plan to use both IPv4 and IPv6 you have to uncomment both lines.
Press Ctrl+X to save changes and then enter Y to exit.
Now to confirm that the changes have been made you can execute the below command which will read the file and load new values for the current terminal session.
sudo sysctl -p
net.ipv4.ip_forward = 1 net.ipv6.conf.all.forwarding = 1
Now our WireGuard Server can forward traffic coming from the virtual VPN ethernet device to peers on the server and to the public internet. This configuration will allow you to route web traffic from your WireGuard peer via your server IP while hiding your client’s IP address.
However, we will first need to configure some firewall rules for the proper flow of traffic.
Configure WireGuard Server Firewall
Now we are going to configure the WireGuard server Firewall so that the traffic from and to the server is routed correctly.
First, we are going to find the public network interface of our WireGuard server by executing the below-mentioned command.
ip route list default
default via 172.22.32.1 dev eth0
The above output shows that eth0 is the public interface.
Now we add the Firewall rules to the server by editing the WireGuard configuration file. Execute the below command to edit the file using nano
.
sudo nano /etc/wireguard/wg0.conf
Paste the following lines at the bottom of this file.
PostUp = ufw route allow in on wg0 out on eth0 PostUp = iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE PostUp = ip6tables -t nat -I POSTROUTING -o eth0 -j MASQUERADE PreDown = ufw route delete allow in on wg0 out on eth0 PreDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE PreDown = ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
Then press Ctrl+X to save and then enter Y to exit the file.
If you are using just IPv4 exclude the ip6tables lines. In the same manner, if you are only using IPv6 then remove the iptables
lines. Otherwise past the above lines as it is.
The last thing left is to allow traffic on the WireGuard UDP port. The default port is 51820 but if you configured another port in the configuration file, edit the below command to mention that port before execution.
To open the 51820 port execute the below command.
sudo ufw allow 51820/udp
Rules updated Rules updated (v6)
To open the SSH port if you have not enabled it, execute the below command.
sudo ufw allow OpenSSH
Rules updated Rules updated (v6)
Now shut down and restart the Firewall to confirm that all changes have taken effect. Execute the below commands in their respective order to disable and enable Firewall.
sudo ufw disable sudo ufw enable
Then execute the below command to check the status.
sudo ufw status
Status: active To Action From -- ------ ---- Apache ALLOW Anywhere 51820/udp ALLOW Anywhere OpenSSH ALLOW Anywhere Apache (v6) ALLOW Anywhere (v6) 51820/udp (v6) ALLOW Anywhere (v6) OpenSSH (v6) ALLOW Anywhere (v6)
Start the Server
Now we are going to configure the WireGuard server to run as a service using the built-in wg-quick
script. By making it a service, we can configure WireGuard to start at boot. Run the below command to do this.
sudo systemctl enable [email protected]
Created symlink /etc/systemd/system/multi-user.target.wants/[email protected] → /lib/systemd/system/[email protected].
Now start the service:
sudo systemctl start [email protected]
[email protected] - WireGuard via wg-quick(8) for wg0 Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled) Active: active (exited) since Mon 2022-04-18 17:22:13 UTC; 2s ago Docs: man:wg-quick(8) man:wg(8) https://www.wireguard.com/ https://www.wireguard.com/quickstart/ https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8 https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8 Process: 98834 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS) Main PID: 98834 (code=exited, status=0/SUCCESS) CPU: 193ms Apr 18 17:22:13 thats-my-jam wg-quick[98834]: [#] wg setconf wg0 /dev/fd/63 Apr 18 17:22:13 thats-my-jam wg-quick[98834]: [#] ip -4 address add 10.8.0.1/24 dev wg0 Apr 18 17:22:13 thats-my-jam wg-quick[98834]: [#] ip -6 address add fdd5:a3ac:a4fd::1/64 dev wg0 Apr 18 17:22:13 thats-my-jam wg-quick[98834]: [#] ip link set mtu 1420 up dev wg0 Apr 18 17:22:13 thats-my-jam wg-quick[98834]: [#] ufw route allow in on wg0 out on ens3 Apr 18 17:22:13 thats-my-jam wg-quick[98890]: Rule added Apr 18 17:22:13 thats-my-jam wg-quick[98890]: Rule added (v6) Apr 18 17:22:13 thats-my-jam wg-quick[98834]: [#] iptables -t nat -I POSTROUTING -o ens3 -j MASQUERADE Apr 18 17:22:13 thats-my-jam wg-quick[98834]: [#] ip6tables -t nat -I POSTROUTING -o ens3 -j MASQUERADE Apr 18 17:22:13 thats-my-jam systemd[1]: Finished WireGuard via wg-quick(8) for wg0.
The output shows that the server is up and running without defined IPv4 and IPv6 addresses.
Set Up WireGuard on the Client Side
Now we are going to take a look at how to configure a WireGurad peer so that clients can connect to your server.
Install WireGuard
First, we need to install WireGuard on the client machine by executing the below lines.
sudo apt update sudo apt install wireguard
Generate Peer Keypair
Now we need to generate a key pair for the clients the same way we did for the server in Generate Keypair section.
Execute the below command to generate the private key.
wg genkey | sudo tee /etc/wireguard/private.key
The above command will return a single-line output. Please note it down.
This command will edit the access of the file so that only root users can view it.
sudo chmod go= /etc/wireguard/private.key
Now execute the below command to generate a public key.
sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
Make sure to note down this public key too.
Create WireGuard Peer Configuration File
To do this, make sure you have the necessary information, which includes the private key for the peer, the IPv4 and IPv6 ranges defined on the Server, the public key from the Server, the Public Address and IP port of the WireGuard Server.
After making sure that you have the above information execute the below line to create a configuration file using the nano
editor.
sudo nano /etc/wireguard/wg0.conf
Then paste the following lines in it.
[Interface] PrivateKey = private_key of peer Address = 10.8.0.3/24 Address = fdd5:a3ac:a4fd::3/64 [Peer] PublicKey = JySX9hMJFyAqZA+mNvJsArKW7yY8I7ROsQKTZZR/RH8= AllowedIPs = 10.8.0.0/24, fdd5:a3ac:a4fd::/64 Endpoint = 209.23.10.202:51820
Now press Ctrl+X to save and then enter Y to exit the file. The first address is the IPv4 address from the 10.8.0.0/24
subnet we configured, and the second address is the IPv6 address from the subnet. Just keep in mind to make these addresses different from the IP configured for the Server.
Add Public Key of Peer to the Server
Run the below command to check the public key of the WireGuard peer.
sudo cat /etc/wireguard/public.key
5EyjWrD3EuPputqrX0+B5Kepeow9XBuJ1RGEI1w2+VM=
Now login to the server and execute the below command.
sudo wg set wg0 peer PeURxj4Q75RaVhBKkRTpNsBPiPSGb5oQijgJsTa29hg= allowed-ips 10.8.0.2,fdd5:a3ac:a4fd::2
Anytime in the future, if you wish to update allowed IPs for a peer, execute the above command by replacing the IP addresses mentioned with the updated ones.
Now run the below command to check the status of the tunnel.
sudo wg
Connect Peer to the Tunnel
Run the below command to start the tunnel on the peer.
sudo wg-quick up wg0
You will get the following output.
[#] ip link add wg0 type wireguard [#] wg setconf wg0 /dev/fd/63 [#] ip -4 address add 10.8.0.3/24 dev wg0 [#] ip -6 address addfdd5:a3ac:a4fd::3/64 dev wg0 [#] ip link set mtu 1420 up dev wg0 [#] resolvconf -a tun.wg0 -m 0 -x
You can run the below command to confirm the status of the tunnel on the peer.
sudo wg
Conclusion
In this tutorial, we learned about everything there is to know about setting up the WireGuard VPN on the Ubuntu 22.04 server.
We learned how to install WireGuard on the server and how to select the range of IPv4 and IPv6 addresses for the server. This same process has to be done for the peer who is going to connect to the server.
Then we configured WireGuard for the peer and added the public key of the peer to the server so that the peer can connect to the server.