Wireguard VPN setup

Wireguard logo

Wireguard is a modern, easy to setup, VPN. It has clients for Windows, Mac, Linux, iPhone, Android, and other OSes.

In this post we are following the guide at https://serversideup.net/how-to-set-up-wireguard-vpn-server-on-ubuntu-20-04/

First, Order a VM. This will be the ‘server’ for the VPN.

You don’t need a lot of memory or disk to run a VPN server. Choose a location for the VM appropriate to your needs. In the sample order link we are using a Debian 11 image.

On your new Linux server, install wireguard, iptables, and ufw.

root@au:~# sudo apt-get install wireguard iptables ufw qrencode
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  apparmor busybox firmware-linux-free initramfs-tools initramfs-tools-core klibc-utils libklibc linux-base
  linux-image-5.10.0-11-rt-amd64 linux-image-rt-amd64 pigz wireguard-tools

You may get an kernel/initramfs error like ‘update-initramfs: Generating /boot/initrd.img-5.10.0-11-rt-amd64’ This is safe to ignore if your VM boots from a host provided kernel.

If you are using a RimuHosting provided kernel, ensure (via uname -a) you are on a 5.10 kernel or newer. Debian 11 installs will use a new kernel.

Now you can proceed with configuring your wireguard server.

# Create the key
root@au:~# 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
z2dUkW5ynTVRi7VQFbUsJoQgRIrZbYZoNW0VIai8kS0=

# Show the server's private key
root@au:~# cat /etc/wireguard/keys/server.key
OEITDW0RKcxR36JvFaKGhfGY8OT2lt0zi3q/lwJkK34=

# Find default interface
root@au:~# ip -o -4 route show to default | awk '{print $5}'
eth0

# Create the wg0.conf file
# echo "
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = $(cat /etc/wireguard/keys/server.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
" | tee /etc/wireguard/wg0.conf

[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = OEITDW0RKcxR36JvFaKGhfGY8OT2lt0zi3q/lwJkK34=
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

# Set permissions
root@au:~# sudo chmod 600 /etc/wireguard/wg0.conf /etc/wireguard/keys/server.key

# Bring up the interface

root@au:~# sudo wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.0.0.1/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# see how it is going
root@au:~# sudo wg show wg0
interface: wg0
  public key: z2dUkW5ynTVRi7VQFbUsJoQgRIrZbYZoNW0VIai8kS0=
  private key: (hidden)
  listening port: 51820

# Enable wireguard on boot up
root@au:~# sudo systemctl enable wg-quick@wg0
Created symlink /etc/systemd/system/multi-user.target.wants/wg-quick@wg0.service → /lib/systemd/system/wg-quick@.service.

# check this setting is enabled, and not commented out
root@au:~# grep net.ipv4.ip_forward /etc/sysctl.conf
#net.ipv4.ip_forward=1

# edit the file with vi or nano or sed
root@au:~# sed -i 's/^#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g'  /etc/sysctl.conf
root@au:~# grep net.ipv4.ip_forward /etc/sysctl.conf
net.ipv4.ip_forward=1

# set that setting from the sysctl.conf file
root@au:~# sudo sysctl -p
net.ipv4.ip_forward = 1

# add a firewall rule for the wireguard connection
root@au:~# sudo ufw allow 51820/udp
Rules updated
Rules updated (v6)

# 22 being your ssh port
root@au:~# sudo ufw allow 22/tcp
Rules updated
Rules updated (v6)
root@au:~# sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

# how is that all looking?
root@au:~# sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
root@au:~# sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
51820/udp                  ALLOW IN    Anywhere                  
22/tcp                     ALLOW IN    Anywhere                  
51820/udp (v6)             ALLOW IN    Anywhere (v6)             
22/tcp (v6)                ALLOW IN    Anywhere (v6)             

Grab a client from https://www.wireguard.com/install/

Some of the available wireguard clients

MacOS client setup

On your client you add the interface. It would look something like this (on MacOS):

Configuring the client interface

The interface file is like:

[Interface]
PrivateKey = iKGIGvTjy76qaY4zDAW1Ns6nKumN883OY67cLLhqCWU=

Address = 10.0.0.3/24
DNS = 1.1.1.1, 1.0.0.1

[Peer]
PublicKey = z2dUkW5ynTVRi7VQFbUsJoQgRIrZbYZoNW0VIai8kS0=
AllowedIPs = 0.0.0.0/0
Endpoint = 43.239.97.140:51820

The public key string was created was created by the MacOS client and is shown in the tunnel creation dialog.

On the client save and activate the connection.

Back on the server you tell it to accept the client, now that you have the public key.

root@au:~# sudo wg set wg0 peer VCPIn/OV+P0U9VsY2xyiBy4wcljvu9bxG0Iy18xvihs= allowed-ips 10.0.0.3          

On the client then save and activate the connection.

You can now visit https://dnsleaktest.com/ and it should report the IP address as your servers:

dnsleaktest page accessed from client, showing the server IP

Server-side setup of client config

Some clients (for example the MacOS client) generate public/private keys for the client. Other clients (e.g. the iPhone one) may not. So it can be handy to pre-create those on the server.

The following creates a config for a client, called ‘mobile’.

root@au:~# clientname=mobile
root@au:~# clientip=10.0.0.4

# create the client private key, and show the public key.
root@au:~# sudo mkdir -p /etc/wireguard/clients
root@au:~# wg genkey | sudo tee /etc/wireguard/clients/$clientname.key | wg pubkey | sudo tee /etc/wireguard/clients/$clientname.key.pub
U/IT6VKR0aF4emCesUjzj0tAJhQZkdMqVqSQWADmA0o=

echo "
[Interface]
PrivateKey = $(cat /etc/wireguard/clients/$clientname.key)
Address = $clientip/24
DNS = 1.1.1.1, 1.0.0.1

[Peer]
PublicKey = $(cat /etc/wireguard/keys/server.key | wg pubkey)
AllowedIPs = 0.0.0.0/0
Endpoint = $(hostname -I | awk '{print $1}'):51820
" | tee /etc/wireguard/clients/$clientname.conf

[Interface]
PrivateKey = YOkK0aeJiCR5+hXvKE44IsR2y4LhOwnHMJazo/XOVFQ=
Address = 10.0.0.4/24
DNS = 1.1.1.1, 1.0.0.1

[Peer]
PublicKey = z2dUkW5ynTVRi7VQFbUsJoQgRIrZbYZoNW0VIai8kS0=
AllowedIPs = 0.0.0.0/0
Endpoint = 43.239.97.140:51820

# then create a qr code with that config in it:
root@au:~# qrencode -t ansiutf8 < /etc/wireguard/clients/$clientname.conf
█████████████████████████████████████████████████████████████████
█████████████████████████████████████████████████████████████████
████ ▄▄▄▄▄ █ ▀▄▄▄ ▄▄██ ▀ ▄ ▀ ▀█▄█▄▄▀▄█▄▄ █ ███  █▄▄ ██ ▄▄▄▄▄ ████
████ █   █ █ ▀███   ▀▀ ▀▄ █ ▄▄ █▀▄ ▀▄▄▄▄▄█  ▀▄▀ ▄▀▄ ██ █   █ ████
████ █▄▄▄█ █▀█▀ ▀  ▄ ██▄ █▀▄██ ▄▄▄ ▀█ ▀▄ ▄▀ ▀▀ ▀  ▀▄██ █▄▄▄█ ████
████▄▄▄▄▄▄▄█▄█▄▀ ▀▄█▄█▄█▄█▄█ █ █▄█ █▄█▄▀▄█ █ █ █ ▀ ▀▄█▄▄▄▄▄▄▄████
████▄▄▀█  ▄▀▀▄▄▀  ▀ ▄█ ▄██▀▄█▄  ▄  ▀█▀ █  █▄██▄██ █▄▀█▀▄█▄▄ ▄████
████▄  ▄██▄▀▄ ▀▄█▀█▀ ▀ ▄█▄ ▀ ██▄▄ █▄▄▄ ▄████▄▄█▀▀█▄ █▄ █▄▄▄█▀████
████  ▀█ ▄▄▀█▄ █▄▄ █▄▄▀ ▄▀█ ▄▀▀▀█▄ ▄▄ █▄█▄ ▀▀▀  ▄▄█   █ █▄   ████
████▀▀▄█ ▄▄█▀▀▄█▀▀█▀██▄█▄▀  ▄▄▀█ ▀▀█▄ ▄ ▄▄█▄▀▄▄█ ▄▄██▄ ▀ ▀█▀█████
████▀▀ █▀▀▄ ▄█ ▄▀█▄ █▄ ▄ ▄█ ▀ ▄▀█▀ ▄▀ █▀  ▀      ▄██ █▀ ▀▄▀▄▀████
████▀▄▀▀▄█▄▄▀▄▀▄▄▄ ██▄ ▀ ▄▄ ▄▀█  ▀██▀▀█  █▄▄▄ ██▀ ▀▀▀▄▄▄▀█ ▄▀████
████ █ ▄ █▄ ▄█ ▄█▀▀▄█▀ ▄▄█▀▄ ▀ ▀▄▄ ▄ ▀▄▄ ▄▀████▀▄█ ██▄▀ ▀▄▄▀ ████
████▄ ▄█▄ ▄█▄▀ ▄ ▀ ▀ ▄█▀ ▄█▀█▄█ ▀ ▀ █▀▀ ▀██   ▄▄▀█▄ ▄█▄ ██▄██████
████ ▀██▄▄▄█ █ ▀██ █▀█▀  █▀ ▀█ ▀▄ ▄▄ ▄██▀▄  ▄ ▀▀▀█▀█▀▄▀▄█▄█▄ ████
█████▄█  ▄▄▄  ▄▄██▀▀ ▄█▄▀▀█▀▄█ ▄▄▄ ██▀▄ ██▀  █▄██ ██ ▄▄▄ █▄▄█████
██████▀▄ █▄█ ▀█▄█▀▀ █▀ █ ▄▄  ▄ █▄█ ▀▄▀▄▄██ █    █▀▄█ █▄█ ▀▄ ▄████
████▄▄ ▀▄ ▄  ██▄▀ ▀ █  █▀▀▀ ██▄   ▄▀▀ ▀ ▀██ ▀ █▀█▀ ▄ ▄ ▄ ▀█ ▄████
████   █▀▀▄ ███▄▄▀ █▄▄▄▄▀▄▀▄▀ ▄▀█▄██ ▄▀ ▀▄▀██ ▀█ ██▀▀▄▀▀▄█   ████
████ ▀██▄ ▄ ▀▀ ▀  ███▄▀ ▄▄█ ▄▄ ▀█▀▄▀   ▄▀▄  ▄▀ ▀▀▀ ▄▀█ ▄ ▀▀▄▀████
████▀█ ▀█▄▄▀▀▄▄▀▀█ ▀▀▄▄▀ █▀▀▄▀ ▀▀█▀ ▄█ ▀▄▀█▀█▄██  ▄▄▀▄▄ ▄▄ █ ████
████▀█▀▀▄ ▄█ ▄ ██ ▄▄█▄█▄█ ▄▄ ▀█▄██▀████  ▄█▄▀▀▀█ ▄▄▄ █ ▀▀▀▄▄█████
████▄██▄█▀▄▀▀▄▄▄▀ █ ▄ ▄▀▄▄█▀▀█▀▄▀▀ ▀█▀ █▀  ▀▄█ ▄▄██▀▀▀▄█ ██  ████
██████▀  ▄▄▄▀█ ▄▄▄█▀ ▀ ▄▄▄ ▀▄▀▄ █ ▄   ▄▄█▀▀█▄▀▀▀ ▀ █ ▄▀ ▀██▀▄████
████▄███▀▄▄  ▀▀█ █▀▄█▄▀▄█▀█   ▄ ▄▀▄ █ █▀▄█▀ ▀ ▀ █▀█▀▀█ ▀▄██ ▀████
████ ▀ ▀▀▄▄▄▀▀█▄█▄█▀█▄██▄ ▀ ▀▄ ▀▄████ ▄ ██▄ ▄▄ █▄▀█▄▀ ▀▀ ▄▄▀█████
██████████▄█ ▄▄██▀▄▀▄ ▄█▀▄█    ▄▄▄ ▄▀ █▀  █▀▀█ █ ▄▀▀ ▄▄▄ █ ▄▀████
████ ▄▄▄▄▄ █▀▀▀▄██▀ █▄▀  ▄█▀▄  █▄█ ▀█▀█ ▄▄███  ▄▀▀▄  █▄█ ▀▄ ▀████
████ █   █ █▄▀█ ▄▄▀▄█▄ ▄▄▀▄▄   ▄▄▄ █▄▄▀ ▄▄█ █▀▀▀▄▄▀█  ▄  █▀▀▀████
████ █▄▄▄█ █▀ ▀▀██ ▀ ▄█▀  █▀█▀ ▀▄▀█▀█    ▄█▀ ▀▀▀▀█▀▄█  ▀▄▀ ██████
████▄▄▄▄▄▄▄█▄█▄▄█▄█████▄▄█▄███▄▄█▄▄▄▄▄██▄▄▄█▄█▄█▄▄▄█▄▄▄▄▄█▄█▄████
█████████████████████████████████████████████████████████████████
█████████████████████████████████████████████████████████████████

# then add the peer to the VPN

root@au:~# echo  sudo wg set wg0 peer $( cat /etc/wireguard/clients/$clientname.key | wg pubkey) allowed-ips $clientip  | tee /etc/wireguard/clients/$clientname-peer.sh
sudo wg set wg0 peer U/IT6VKR0aF4emCesUjzj0tAJhQZkdMqVqSQWADmA0o= allowed-ips 10.0.0.4
root@au:~# bash /etc/wireguard/clients/$clientname-peer.sh

iPhone setup

Install the wireguard app (from the App Store).

Then add a tunnel via the above QR code. After the tunnel is added, activate it on the iPhone.

Then browse to https://dnsleaktest.com/ on your iPhone and it should load and report the IP address of your VPN server.