Using WireGuard to create a VPN Tunnel

So you've got a server stuck behind a NAT you can't configure, may it's managed by your building's external IT supplier or you just aren't allowed to tinker with the port forwarding settings. How can you allow external access to this device?

This guide heavily leans upon the guide created Justin at DigitalOcean, cheers Justin! Using Wireguard, we can create a VPN tunnel between the server and an external end-point (such as an Google Cloud Compute engine). For this configuration i've got the following set up:

  • Google Compute Engine (called SERVER 1)

    • Zone: us-east1-b (use whichever you'd like)
    • g1-small (1 vCPU, 1.7GB Memory)
    • Static external IP set
    • IP Forwarding turned ON
  • Ubuntu 18.04 LTS Local Server (called SERVER 2)

    • Running in a Hyper-V virtual box
    • 2GB RAM
    • 10GB SSD
    • Network configured using DHCP and has access to internet

Step 1 - installing the required packages

We first need to install the Wireguard package on both servers. This requires adding the Wireguard repo, to do this run the following on both Server 1 and Server 2:

sudo add-apt-repository ppa:wireguard/wireguard

Then run:

sudo apt-get update

And finally:

sudo apt-get install wireguard-dkms wireguard-tools

Step 2 - Create a private key

We need to generate a private key on both Server 1 and Server 2, this allows them to securely authenticate with eachother. Type the following on both servers (without the $):

$ (umask 077 && printf "[Interface]\nPrivateKey = " | sudo tee /etc/wireguard/wg0.conf > /dev/null)
$ wg genkey | sudo tee -a /etc/wireguard/wg0.conf | wg pubkey | sudo tee /etc/wireguard/publickey

Step 3 - Create the configuration file

Open the following file on Server 1 & Server 2 using whichever text editor you prefer (such as nano or vim) and add the following (don't change the private key though!):

/etc/wireguard/wg0.conf

[Interface]
PrivateKey = **generated_private_key**
ListenPort = 5555
SaveConfig = true

You can pick any free port you'd like, for the sake of simplicity we picked 5555. The SaveConfig flag means that the config file is overwritten when the wg service is stopped. Therefore you'll need to stop the service before changing any of the values, otherwise they'll be overwritten.

We need to add a unique address to each server, this gets mapped to the wg0 interface when the tunnel is brought online, for this guide we will use the 10.0.0.0/24 subnet.

Now, on server 1, add the address of: 10.0.0.1 like so:

[Interface]
PrivateKey = **generated_private_key**
ListenPort = 5555
SaveConfig = true
Address = 10.0.0.1/24

On server 2, we'll use 10.0.0.2, like so:

[Interface]
PrivateKey = **generated_private_key**
ListenPort = 5555
SaveConfig = true
Address = 10.0.0.2/24

Defining the peer

We've now finished the 'Interface' section, next is the 'Peer' section which defines the neighbour server (server 1 for server 2 and vice versa). We'll need the public key from the first server. You can get this by typing:

cat /etc/wireguard/publickey

On server 2's copy of wg0.conf, add the following underneath the interface section:

[Peer]
PublicKey = public_key_of_first_server
AllowedIPs = 10.0.0.1/32

Finally, you'll need to add the external IP address of server 1, so that server 2 knows where to connect to:

[Peer]
PublicKey = public_key_of_first_server
AllowedIPs = 10.0.0.1/32
Endpoint = public_ip_of_first_server:5555

Opening the ports

You'll need to open port 5555 on both server, so run the following on both server 1 & 2:

sudo ufw allow 5555

Now, start the wg-quick application, this configures the network adapter to use the settings we configured earlier:

sudo systemctl start [email protected]

Now the service is up, let's see if the interface is up too! To verify this, run:

ip addr show wg0

[email protected]_ubuntu:~$ ip addr show wg0
7: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none 
    inet 10.0.0.2/24 scope global wg0
       valid_lft forever preferred_lft forever

You should see something like the above.

You can use the wg command to view the active VPN configuration:

sudo wg

On server 1, where we haven't yet configured the peer section, you should see something like:

interface: wg0
  public key: public_key_of_this_server
  private key: (hidden)
  listening port: 5555

Whereas on server 2, we see:

interface: wg0
  public key: public_key_of_this_server
  private key: (hidden)
  listening port: 5555

peer: jeGkBcmeX4T184Kp+izStcLM7J/bY19KzUGsXZLr/hs=
  endpoint: public_IP_of_first_server:5555
  allowed ips: 10.0.0.1/32

Adding the missing peer information to Server 1

On server 1, we haven't yet added the peer information, we'll need the public key from server 2, which you can get by running:

sudo wg

Execute the following on server 1 to add the peer information:

sudo wg set wg0 peer public_key_of_second_server endpoint public_IP_of__server:5555 allowed-ips 10.0.0.2/32

Run sudo wg again on both to confirm they're both configured correctly. If so, try pinging eachother!

Server 1 - ping 10.0.0.2
Server 2 - ping 10.0.0.1

If you get a ping response, your tunnel has been configured! To configure the server to automatically start the VPN tunnel on reboot, enter the following on both servers:

sudo systemctl enable [email protected]