DEV Community

Miguel
Miguel

Posted on • Edited on

Getting Started with WireGuard

WireGuard is a relatively new VPN tunnel protocol that aims to be very fast and easy to setup. It follows the Unix Philosophy closely in that it only does one thing (creating secured VPN tunnels) and does it well.

If you've ever set up an VPN service such as OpenVPN before then you know that it can get complicated because of all the steps you have to go through such as generating certificate authorities, issuing server and client keys and certificates, setting up multiple configuration files, configuring firewall rules, setting up route traffic forwarding, etc. which can either be dreadful or daunting. WireGuard is changing all that by simplifying the process of getting up and running in no time and allowing for easy configuration to connect multiple clients (peers).

Why use WireGuard?

  • A VPN helps protect you from man in the middle attacks.
  • Protect your privacy against ISPs that snoop into your traffic.
  • Get around internet censorship in countries.

Advantages of WireGuard over other VPNs:

  • It's kernel-based; improved performance.
  • Establishes connections in less than 100ms.
  • Small footprint; can be ran in virtually any device, ie. embedded devices.
  • Easy to configure and deploy as SSH; reduces attack surface since there's less complexity.
  • Uses modern and improved cryptographic standards.
  • Simple handshake occurring every few minutes to ensure connection secrecy.
  • IP roaming support meaning you can change wifi networks or disconnect from wifi or celluar and the VPN tunnel connection won't be lost. It just works!

What we'll be going over

This post assumes that you've never installed a VPN service before and we'll be using an Ubuntu machine since it's the most popular distro.

This post is pretty verbose! but you can skip to the TLDR; to see the final scripts and configuration files used if you're familiar with the concepts already.

The steps outlined in this post are:

  1. Setting up a server
  2. Installing WireGuard on server
  3. Generating server keys
  4. Creating server configuration file
  5. Enabling IP forwarding on server
  6. Installing WireGuard on client
  7. Generating client keys
  8. Creating client configuration file
  9. Setting client info on server config
  10. Starting WireGuard service on server
  11. Starting WireGuard service on client
  12. Connecting a mobile client to server

Please note that in WireGuard land there is no "server" and "client" in the traditional sense. Rather, computers and devices connected to each other are known as "peers". For simplicity sake, we'll be using "server" to mean the hosted server that will be forwarding all our traffic to, and we'll be using "client" to refer to the home computer that forwards all it's traffic to the server.

Setting up a server

I'll be using a free tier EC2 micro instance from AWS for the example (and tearing down it afterwards). If you have an AWS account you can launch a new instance by going to:

EC2 → Launch Instance → t2.micro with Ubuntu → Review and Launch → Launch

In this example I'm running Ubuntu 18.04 (Bionic Beaver).

Installing WireGuard on server

To install wireguard on Ubuntu <19.04 run the following comands:

  1. sudo add-apt-repository ppa:wireguard/wireguard
  2. sudo apt-get update
  3. sudo apt-get install wireguard

If your server is using a different distro then look at the WireGuard installation instructions.

ubuntu@ip-172-30-0-233:~$ sudo add-apt-repository ppa:wireguard/wireguard
 WireGuard is a novel VPN that runs inside the Linux Kernel. This is the Ubuntu packaging for WireGuard. More info may be found at its website, listed below.

More info: https://www.wireguard.com/
Packages: wireguard wireguard-tools wireguard-dkms

Install with: $ apt install wireguard
 More info: https://launchpad.net/~wireguard/+archive/ubuntu/wireguard
Press [ENTER] to continue or Ctrl-c to cancel adding it.

<truncated>

Fetched 18.5 MB in 4s (4840 kB/s)

ubuntu@ip-172-30-0-233:~$ sudo apt-get update
Hit:1 http://us-east-1.ec2.archive.ubuntu.com/ubuntu bionic InRelease
Hit:2 http://us-east-1.ec2.archive.ubuntu.com/ubuntu bionic-updates InRelease
Hit:3 http://us-east-1.ec2.archive.ubuntu.com/ubuntu bionic-backports InRelease
Hit:4 http://security.ubuntu.com/ubuntu bionic-security InRelease
Hit:5 http://ppa.launchpad.net/wireguard/wireguard/ubuntu bionic InRelease
Reading package lists... Done

ubuntu@ip-172-30-0-233:~$ sudo apt-get install wireguard
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:

<truncated>

update-alternatives: using /usr/bin/g++ to provide /usr/bin/c++ (c++) in auto mode
Setting up build-essential (12.4ubuntu1) ...
Setting up wireguard-dkms (1.0.20200401-1ubuntu1~18.04) ...
Loading new wireguard-1.0.20200401 DKMS files...
Building for 4.15.0-1057-aws
Building initial module for 4.15.0-1057-aws
Done.

wireguard:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/4.15.0-1057-aws/updates/dkms/

depmod...

DKMS: install completed.
Setting up wireguard (1.0.20200319-0ppa1~18.04) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Enter fullscreen mode Exit fullscreen mode

Let's launch a shell as root with sudo -s to avoid having to type sudo every time from now on:

ubuntu@ip-172-30-0-233:~$ sudo -s
root@ip-172-30-0-233:~#
Enter fullscreen mode Exit fullscreen mode

Run wg to check if installation was successful which should not output anything if everything is OK:

root@ip-172-30-0-233:/etc/wireguard/keys# wg
root@ip-172-30-0-233:/etc/wireguard/keys#
Enter fullscreen mode Exit fullscreen mode

The two WireGuard commands we'll be using are:

  • wg for configuring WireGuard interfaces.
  • wg-quick for starting and stopping WireGuard VPN tunnels.

Generating server keys

WireGuard configuration files will live under /etc/wireguard/ so let's create a directory named keys there to store the keys we'll generate:

root@ip-172-30-0-233:~# mkdir /etc/wireguard/keys
Enter fullscreen mode Exit fullscreen mode

Go into the /etc/wireguard/keys/ directory:

root@ip-172-30-0-233:~# cd /etc/wireguard/keys
Enter fullscreen mode Exit fullscreen mode

Set the directory user mask to 077 by running umask 077. A umask of 077 allows read, write, and execute permissions for the file's owner (root in this case), but prohibits read, write, and execute permissions for everyone else and makes sure credentials don't leak in a race condition:

root@ip-172-30-0-233:/etc/wireguard/keys# umask 077
Enter fullscreen mode Exit fullscreen mode

WireGuard uses asymmetric public/private Curve25519 key pairs for authentication between client and server.

Use the wg genkey command to generate a private key. We can generate both the private and public key at once by piping the private key output to tee to save it to file but also to forward the private key to wg publickey which derived the public key from a private key and the save it to a file.

So the command to run is wg genkey | tee privatekey | wg pubkey > publickey to generate the key pair at once:

root@ip-172-30-0-233:/etc/wireguard/keys# wg genkey | tee privatekey | wg pubkey > publickey
Enter fullscreen mode Exit fullscreen mode

If we do an ls we see there's a privatekey and publickey file:

root@ip-172-30-0-233:/etc/wireguard/keys# ls
privatekey  publickey
Enter fullscreen mode Exit fullscreen mode

Outputting the contents of the private key file shows us the random key it generated in base64 format:

root@ip-172-30-0-233:/etc/wireguard/keys# cat privatekey
wIObajifv6U2emcZsAGNZbbWzkyrs84EEyr+bgmlB3M=
Enter fullscreen mode Exit fullscreen mode

Likewise the public key it derived from the private key is in base64 format:

root@ip-172-30-0-233:/etc/wireguard/keys# cat publickey
H6StMJOYIjfqhDvG9v46DSX9UlQl52hOoUm7F3COxC4=
Enter fullscreen mode Exit fullscreen mode

We'll be needing the private key for the WireGuard server configuration, and the public key for the client configuration.

Creating server configuration file

Go into the /etc/wireguard/ directory and create a new file wg0.conf. WireGuard will create a new network interface named the same as the filename so it's common convention to denote the first WireGuard network interface as wg0 for context:

root@ip-172-30-0-233:/etc/wireguard# touch /etc/wireguard/wg0.conf
Enter fullscreen mode Exit fullscreen mode

Open up the server configuration file /etc/wireguard/wg0.conf in your favorite editor:

root@ip-172-30-0-233:/etc/wireguard# vim /etc/wireguard/wg0.conf
Enter fullscreen mode Exit fullscreen mode

Paste the following configuration into the new config file:

[Interface]
PrivateKey = <server private key>
Address = 10.0.0.1/24
ListenPort = 51820
Enter fullscreen mode Exit fullscreen mode

The config files are in standard INI format.

Replace the PrivateKey value with the private key content you generated earlier:

[Interface]
PrivateKey = wIObajifv6U2emcZsAGNZbbWzkyrs84EEyr+bgmlB3M=
Address = 10.0.0.1/24
ListenPort = 51820
Enter fullscreen mode Exit fullscreen mode

The address 10.0.0.1 was chosen because it's an available private subnet on the server. If your server is using that IP range already, then pick a different address like 192.168.2.1 to avoid conflicts.

To summarize, the server [Interface] section is for configuration the new WireGuard interface we are creating.

  • PrivateKey is your server's private key.
  • Address is the private network IP address range that we're assigning to for this network interface.
  • ListenPort is the host port to run the service on. This port will need to be publicly accessible. The port 51820 is the default port.

Make sure to enable the port 51820 for UDP traffic. If using EC2 then you should allow it under the Security Group for the EC2 instance.

EC2 instance → Security groups → Click on security group → Edit inbound rules → Add rules → Custom UDP → Port range: 51820 → Source: Anywhere → Save rules

The rules immediately take effect.

If your server is behind a NAT then all traffic needs to be forwarded from the default interface to the WireGuard interface.

To find out the name of the default interface run ip route:

root@ip-172-30-0-233:/etc/wireguard/keys# ip route | grep default | awk '{print $5}'
eth0
Enter fullscreen mode Exit fullscreen mode

Now add forwarding rules for forwarding in the server configuration file using the PostUp and PostDown config settings where PostUp value command is ran when the WireGuard service starts and PostDown value command runs when the service is shutting down.

[Interface]
PrivateKey = wIObajifv6U2emcZsAGNZbbWzkyrs84EEyr+bgmlB3M=
Address = 10.0.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
Enter fullscreen mode Exit fullscreen mode

The three iptable rules are:

  • iptables -A FORWARD -i %i -j ACCEPT for allowing inbound traffic received by the interface.
  • iptables -A FORWARD -o %i -j ACCEPT for allowing outbound traffic from the interface.
  • iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE for masking the private IP address of the interface with the external IP address of the default interface.

Enabling IP forwarding on server

By default IP forwarding is disabled meaning that if the interface receives a packet that wasn't intended for it then it'll reject it. Since we need to pass on packets from one interface to another then we need to allow IP forwarding.

Open up the file /etc/sysctl.conf for editing:

root@ip-172-30-0-233:/etc/wireguard# vim /etc/sysctl.conf
Enter fullscreen mode Exit fullscreen mode

Allow forwarding of IP packets by uncommenting out the line net.ipv4.ip_forward=1 near line 28:

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
Enter fullscreen mode Exit fullscreen mode

Run sysctl -p for the changes to take effect without requiring a reboot:

root@ip-172-30-0-233:/etc/wireguard# sysctl -p
net.ipv4.ip_forward = 1
Enter fullscreen mode Exit fullscreen mode

Confirm that IP forwarding is enabled by outputting the contents of /proc/sys/net/ipv4/ip_forward which should return 1:

root@ip-172-30-0-233:/etc/wireguard# cat /proc/sys/net/ipv4/ip_forward
1
Enter fullscreen mode Exit fullscreen mode

The server is almost fully configured. It's only now missing information about the client so let's set up the client next.

Installing WireGuard on client

Jump back to your client machine and install WireGuard. My client machine is running Arch linux but the process will be the same for most linux distros. If you're running Ubuntu on the client then do the same install steps you did on the server above or look at the official WireGuard installation instructions.

Ubuntu WireGuard install instructions:

$ sudo add-apt-repository ppa:wireguard/wireguard
$ sudo apt-get update
$ sudo apt-get install wireguard
Enter fullscreen mode Exit fullscreen mode

If running Arch like I am, then these are the WireGuard install instructions:

$ sudo pacman -S wireguard-tools wireguard-dkms
Enter fullscreen mode Exit fullscreen mode

Let's launch a shell as root with sudo -s to avoid having to type sudo every time from now on:

$ sudo -s
[root@archlinux ~]#
Enter fullscreen mode Exit fullscreen mode

Generating client keys

The process of generating WireGuard keys on the client is the same as how it's done on the server. Create the directory /etc/wireguard/keys and set the user mask to 077.

[root@archlinux ~]# mkdir /etc/wireguard/keys
[root@archlinux ~]# cd /etc/wireguard/keys
[root@archlinux keys]# umask 077
Enter fullscreen mode Exit fullscreen mode

Generate a private and public key pair for the client using the same command as we did on the server:

[root@archlinux keys]# wg genkey | tee privatekey | wg pubkey > publickey
Enter fullscreen mode Exit fullscreen mode

Output the key contents which we'll be needing soon in our configuration files:

[root@archlinux keys]# cat privatekey
cAqmevIKScn5l4Jg1F69KEIty6gVb8wGNqNlApvzc0c=
[root@archlinux keys]# cat publickey
vi4TCAo8TNRkpf4ZpiMsp3YHaOLrcouSDkrm4wJxezw=
Enter fullscreen mode Exit fullscreen mode

Creating client configuration file

On the client create the configuration /etc/wireguard/wg0.conf:

[root@archlinux keys]# vim /etc/wireguard/wg0.conf
Enter fullscreen mode Exit fullscreen mode

Paste the configuration into your client configuration file:

[Interface]
Address = 10.0.0.2/32
PrivateKey = <client private key>
Enter fullscreen mode Exit fullscreen mode

Replace the PrivateKey value with your client's private key:

[Interface]
Address = 10.0.0.2/32
PrivateKey = cAqmevIKScn5l4Jg1F69KEIty6gVb8wGNqNlApvzc0c=
Enter fullscreen mode Exit fullscreen mode

Optionally, you can set the DNS resolver to use. We'll set the DNS resolver IP to Cloudflare's public DNS resolver 1.1.1.1 which is fast and secure:

[Interface]
Address = 10.0.0.2/32
PrivateKey = cAqmevIKScn5l4Jg1F69KEIty6gVb8wGNqNlApvzc0c=
DNS = 1.1.1.1
Enter fullscreen mode Exit fullscreen mode

To summarize, the client [Interface] section is for configuration the new WireGuard interface we are creating.

  • Address is the private network IP address range that we're assigning to for this network interface.
  • PrivateKey is your client's private key.
  • DNS is the DNS resolve to use.

Setting server peer on client config

The next step is to set information about the server in the client configuration file under the [Peer] section:

[Interface]
Address = 10.0.0.2/32
PrivateKey = cAqmevIKScn5l4Jg1F69KEIty6gVb8wGNqNlApvzc0c=
DNS = 1.1.1.1

[Peer]
PublicKey = <server public key>
Endpoint = <server public ip>:51820
AllowedIPs = 0.0.0.0/0
Enter fullscreen mode Exit fullscreen mode

Replace the PublicKey value to your server's public key and set the Endpoint to be your server's public IP address:

[Interface]
Address = 10.0.0.2/32
PrivateKey = cAqmevIKScn5l4Jg1F69KEIty6gVb8wGNqNlApvzc0c=
DNS = 1.1.1.1

[Peer]
PublicKey = H6StMJOYIjfqhDvG9v46DSX9UlQl52hOoUm7F3COxC4=
Endpoint = 54.225.123.18:51820
AllowedIPs = 0.0.0.0/0
Enter fullscreen mode Exit fullscreen mode

If your server is behind a NAT and not accessible via a public IP, then under the peer section you'll need to set PersistentKeepalive to keep the connection alive. It's important that you only set PersistentKeepalive if your server in an internal server, otherwise you'd be wasting bandwidth and battery life for no good reason.

PersistentKeepalive = 25
Enter fullscreen mode Exit fullscreen mode

To summarize, the client [Peer] section is for configuration information about the peer it's connecting to, which in this case it's the client connection to the server.

  • PublicKey is the public key of the server.
  • Endpoint is your server's public IP and port the server's interface is listening, configured with ListenPort in the server's config.
  • AllowedIPs is the IP range to allow forwarding from. Setting it to 0.0.0.0/0 will forward all traffic over the tunnel.
  • PersistentKeepalive is the interval to periodically send keepalive packets to the server.

If you're not sure what your server's public address is, you can do an IP lookup by doing a DNS query request to myip.opendns.com:

root@ip-172-30-0-233:/etc/wireguard# dig +short myip.opendns.com @resolver1.opendns.com
54.225.123.18
Enter fullscreen mode Exit fullscreen mode

If your server is an EC2 instance, you get query the metadata endpoint to get the public IP address:

root@ip-172-30-0-233:/etc/wireguard# curl http://169.254.169.254/latest/meta-data/public-ipv4
54.225.123.18
Enter fullscreen mode Exit fullscreen mode

Setting client peer on server config

Go back into the server and edit the config. We're going to add information about the client so that the server and client can authenticate with each other.

root@ip-172-30-0-233:/etc/wireguard/keys# vim /etc/wireguard/wg0.conf
Enter fullscreen mode Exit fullscreen mode

Add the [Peer] section to the server config:

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

[Peer]
PublicKey = <client public key>
AllowedIPs = 10.0.0.2/32
Enter fullscreen mode Exit fullscreen mode

Replace the PublicKey value with your client's public key:

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

[Peer]
PublicKey = vi4TCAo8TNRkpf4ZpiMsp3YHaOLrcouSDkrm4wJxezw=
AllowedIPs = 10.0.0.2/32
Enter fullscreen mode Exit fullscreen mode

To summarize, the server [Peer] section is for configuration information about the peer it's connecting to, which in this case it's the servers connection to the client.

  • PublicKey is the client's public key.
  • AllowedIPs are allowed client IP addresses.

Starting WireGuard service on server

Now that the server has the client peer information we can start the WireGuard service with wg-quick up wg0 on the server:

root@ip-172-30-0-233:/etc/wireguard/keys# 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 8921 up dev wg0
[#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Enter fullscreen mode Exit fullscreen mode

To start WireGuard across reboots you'll need to enable the service to add it to the systemd init system by running systemctl enable wg-quick@wg0.service:

root@ip-172-30-0-233:/etc/wireguard/keys# systemctl enable wg-quick@wg0.service
Created symlink /etc/systemd/system/multi-user.target.wants/wg-quick@wg0.service → /lib/systemd/system/wg-quick@.service.
Enter fullscreen mode Exit fullscreen mode

Check the status by running systemctl status wg-quick@wg0.service and if you see Active: active (exited) then if everything is good so far:

root@ip-172-30-0-233:/etc/wireguard/keys# systemctl status wg-quick@wg0.service
● wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0
   Loaded: loaded (/lib/systemd/system/wg-quick@.service; indirect; vendor preset: enabled)
   Active: active (exited) since Thu 2020-04-02 06:35:22 UTC; 1s 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: 10730 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS)
 Main PID: 10730 (code=exited, status=0/SUCCESS)

Apr 02 06:35:21 ip-172-30-0-233 systemd[1]: Starting WireGuard via wg-quick(8) for wg0...
Apr 02 06:35:22 ip-172-30-0-233 wg-quick[10730]: [#] ip link add wg0 type wireguard
Apr 02 06:35:22 ip-172-30-0-233 wg-quick[10730]: [#] wg setconf wg0 /dev/fd/63
Apr 02 06:35:22 ip-172-30-0-233 wg-quick[10730]: [#] ip -4 address add 10.0.0.1/24 dev wg0
Apr 02 06:35:22 ip-172-30-0-233 wg-quick[10730]: [#] ip link set mtu 8921 up dev wg0
Apr 02 06:35:22 ip-172-30-0-233 wg-quick[10730]: [#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; ipt
Apr 02 06:35:22 ip-172-30-0-233 systemd[1]: Started WireGuard via wg-quick(8) for wg0.
Enter fullscreen mode Exit fullscreen mode

Verify that new iproute rules have been applied with iptables -L -n:

root@ip-172-30-0-233:/etc/wireguard# iptables -L -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
Enter fullscreen mode Exit fullscreen mode

Running the command ifconfig shows the new network interface wg0 with the internal IP address we specified 10.0.0.1:

root@ip-172-30-0-233:/etc/wireguard# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
        inet 172.30.0.233  netmask 255.255.255.0  broadcast 172.30.0.255
        inet6 fe80::1097:5bff:fe30:d57  prefixlen 64  scopeid 0x20<link>
        ether 12:97:5b:30:0d:57  txqueuelen 1000  (Ethernet)
        RX packets 1151269  bytes 524679242 (524.6 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1022229  bytes 345390292 (345.3 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 526  bytes 48787 (48.7 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 526  bytes 48787 (48.7 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wg0: flags=209<UP,POINTOPOINT,RUNNING,NOARP>  mtu 8921
        inet 10.0.0.1  netmask 255.255.255.0  destination 10.0.0.1
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 1000  (UNSPEC)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
Enter fullscreen mode Exit fullscreen mode

Starting WireGuard service on client

First take note of your current public IP address on the client machine:

[root@archlinux wireguard]# dig +short myip.opendns.com @resolver1.opendns.com
65.88.88.4
Enter fullscreen mode Exit fullscreen mode

After we start the WireGuard service on the client then the public IP address will be resolved to the server's public IP address.

Start the WireGuard service using wg-quick just like we did previously on the server:

[root@archlinux wireguard]# wg-quick up wg0
Enter fullscreen mode Exit fullscreen mode

Now that WireGuard is running, check the public IP address again of the client and it should now be the public IP address of the server:

[root@archlinux wireguard]# dig +short myip.opendns.com @resolver1.opendns.com
54.225.123.18
Enter fullscreen mode Exit fullscreen mode

Success! WireGuard is correctly configured and the peers are connected.

Connecting a mobile client to server

Download the WireGuard app for iOS or Android on your device.

For this example we'll create a second client (an iPhone) to connect to the WireGuard server. The same steps will need to be followed from when we setup the first client.

We can generate keys directly on the device and set up the configuration manually but that's not quick and ideal. Instead we can generate the keys and configuration on the server and then securely transfer the information into the WireGuard app.

Run wg genkey but specify different filenames this time to distinguish them from the server keys:

root@ip-172-30-0-233:/etc/wireguard# cd /etc/wireguard/keys
root@ip-172-30-0-233:/etc/wireguard/keys# wg genkey | tee iphone_privatekey | wg pubkey > iphone_publickey
root@ip-172-30-0-233:/etc/wireguard/keys# cat iphone_privatekey
kFnMqMSiAluwb/xWgemXhjLh/II/sb92OoYCbh7yaWw=
root@ip-172-30-0-233:/etc/wireguard/keys# cat iphone_publickey
cKIxzfp5ESpdM34vT2Qk/S7yvprOff6Le4YnyOTI4B8=
Enter fullscreen mode Exit fullscreen mode

Open up the server config /etc/wireguard/wg0.conf in your favorite editor:

root@ip-172-30-0-233:/etc/wireguard/keys# vim /etc/wireguard/wg0.conf
Enter fullscreen mode Exit fullscreen mode

Add the second peer section and include the client's public key and IP address:

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

[Peer]
PrivateKey = wIObajifv6U2emcZsAGNZbbWzkyrs84EEyr+bgmlB3M=
AllowedIPs = 10.0.0.2/32

[Peer]
PublicKey = cKIxzfp5ESpdM34vT2Qk/S7yvprOff6Le4YnyOTI4B8=
AllowedIPs = 10.0.0.3/32
Enter fullscreen mode Exit fullscreen mode

Create a new configuration file for the iPhone client on the server. We'll name it wgo-iphone.conf:

root@ip-172-30-0-233:/etc/wireguard/keys# vim /etc/wireguard/wg0-iphone.conf
Enter fullscreen mode Exit fullscreen mode

Paste client configuration but remember to use a different private IP that differs from the first client.

[Interface]
PrivateKey = kFnMqMSiAluwb/xWgemXhjLh/II/sb92OoYCbh7yaWw=
Address = 10.0.0.3/32
DNS = 1.1.1.1

[Peer]
PublicKey = H6StMJOYIjfqhDvG9v46DSX9UlQl52hOoUm7F3COxC4=
Endpoint = 54.225.123.18:51820
AllowedIPs = 0.0.0.0/0
Enter fullscreen mode Exit fullscreen mode

Install qrencode on the server to generate a QRCode from the configuration file.

You'll be scanning this qrcode in the WireGuard app to download the configuration. This is a safer way to transport credentials since the keys and configuration files don't need to be zipped and moved.

Generate the text based qrcode image in your terminal with qrencode -t ansiutf8 < wg0-iphone.conf

root@ip-172-30-0-233:/etc/wireguard# qrencode -t ansiutf8 < wg0-iphone.conf
<qrcode image>
Enter fullscreen mode Exit fullscreen mode

In the WireGuard app go to: Add a tunnel → Create from QRCode

Scan the qrcode code generated in the terminal and make sure to Allow the VPN configuration in the settings popup.

Enable the VPN by toggling on the switch.

Visit ipchicken.com in the browser to verify the public iP address has changed.

Generating vanity addresses

It's easy to lose track of which keys belong to which devices since they all look like random strings. To make it easier to associate keys to devices you can use this vanity address generator to generate public keys that contain a custom array of characters.

For example, we'll generate a key pair where the public key starts with "iPho" to denote that it's a key pair to be used on the iPhone client.

First install the vanity address generator with cargo:

$ cargo install wireguard-vanity-address
Enter fullscreen mode Exit fullscreen mode

Now just specify the list of characters that you want in the public key base64 output:

$ wireguard-vanity-address ipho
searching for 'ipho' in pubkey[0..10], one of every 149796 keys should match
one trial takes 83.6 us, CPU cores available: 8
est yield: 1.6 seconds per key, 638.83e-3 keys/s
hit Ctrl-C to stop
private YPpudjAoVCnaPUJdcEVhj5Ttedq7WP1ozL+ZdtuTC1g=  public cHklbipHoMS9CA8XlRdKMBOOIfQC28Ut8SVyYsqmox0=
private kD6FSIZehv1DKJ28MKJQcmSDdd69U3s4s11ymtP1Ekc=  public iPHoaaQye7+OJNq/TfOvXjMr99pq9ADDDlGynRQ6KQ8=
private aEJ33LXCeipouhiAoQjfMjtwrHPfZDvKLguE8XlawnY=  public iPHoEoUy4WgkUXr4e47IkA06IZqVI/AqHNS2RZlGhHM=
^C
Enter fullscreen mode Exit fullscreen mode

It'll keep generating until you manually stop it when you see a key pair that you like.

Automation

A nice tool to automate the process of setting up a WireGuard VPN is Algo.

Algo is a set of Ansible scripts to help you set up and configure WireGuard on the remote server from your local machine.

To get started, clone the algo repository and install the python dependencies:

~$ git clone https://github.com/trailofbits/algo.git
~$ cd algo/
~/algo$ pip install virtualenv
~/algo$ python3 -m virtualenv --python="$(command -v python3)" .env && source .env/bin/activate && python3 -m pip install -U pip virtualenv && python3 -m pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Now run the algo executable file to start the walkthough of deploying an Algo server to the cloud:

(.env) ~/algo$ ./algo
[Cloud prompt]
What provider would you like to use?
    1. DigitalOcean
    2. Amazon Lightsail
    3. Amazon EC2
    4. Microsoft Azure
    5. Google Compute Engine
    6. Hetzner Cloud
    7. Vultr
    8. Scaleway
    9. OpenStack (DreamCompute optimised)
    10. CloudStack (Exoscale optimised)
    11. Install to existing Ubuntu 18.04 or 19.10 server (for more advanced users)

Enter the number of your desired provider
:
<truncated>
Enter fullscreen mode Exit fullscreen mode

Troubleshooting

The following are additional steps users reported they needed to take after getting the following errors.

If you tried wg-quick up wg0 and received the following:

root@ubuntu:/etc/wireguard# wg-quick up wg0
[#] ip link add wg0 type wireguard
RTNETLINK answers: Operation not supported
Unable to access interface: Protocol not supported
[#] ip link delete dev wg0
Cannot find device "wg0"
Enter fullscreen mode Exit fullscreen mode

The error "RNETLINK answers: Operation not supported" when trying to start the wg0 interface could mean that you need install you install additional kernel modules that are required.

To install the required wireguard kernel modules on Ubuntu, run:

root@ubuntu:/etc/wireguard# apt-get install wireguard-dkms wireguard-tools linux-headers-$(uname -r)
Enter fullscreen mode Exit fullscreen mode

Running modprobe wireguard should not output anything if the kernel modules were installed successful:

root@ubuntu:/etc/wireguard# modprobe wireguard
Enter fullscreen mode Exit fullscreen mode

If you're seeing errors then there's a chance that the Secure Boot feature is blocking the unsigned WireGuard kernel module. To fix this you'll need to disable Secure Boot or sign the WireGuard module for the kernel to trust it. See this answer for instructions.

After rebooting try loading the interface with the ip link command:

root@ubuntu:/etc/wireguard# ip link add dev wg0 type wireguard
Enter fullscreen mode Exit fullscreen mode

There should be no output if successful.

If you tried wg-quick up wg0 and received the following:

root@ubuntu:/etc/wireguard# wg-quick up wg0
[#] ip link add configfile type wireguard
[#] wg setconf configfile /dev/fd/63
[#] ip address add 10.0.0.1/24 dev configfile
[#] ip link set mtu 1420 dev configfile
[#] ip link set configfile up
[#] resolvconf -a configfile -m 0 -x
/usr/bin/wg-quick: line 31: resolvconf: command not found
[#] ip link delete dev configfile
Enter fullscreen mode Exit fullscreen mode

it could mean that resolveconf is not installed on your machine, so you'll need to install the openresolv package:

root@ubuntu:/etc/wireguard# apt-get install openresolv
Enter fullscreen mode Exit fullscreen mode

See this Github issue thread for more context.

TLDR;

Here's a summary of the server and client configuration and commands used in this post:

Server

Server commands:

sudo -s
apt-get install wireguard
mkdir -p /etc/wireguard/keys
cd /etc/wireguard/keys
umask 077
wg genkey | tee privatekey | wg pubkey > publickey
vim /etc/wireguard/wg0.conf # see server config below
vim /etc/sysctl.conf # uncomment line "net.ipv4.ip_forward=1"
sysctl -p
wg-quick up wg0
systemctl enable wg-quick@wg0.service
Enter fullscreen mode Exit fullscreen mode

Server config /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = <server private key>
Address = 10.0.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = <client public key>
AllowedIPs = 10.0.0.2/32
Enter fullscreen mode Exit fullscreen mode

Client

Client commands:

sudo -s
apt-get install wireguard
mkdir -p /etc/wireguard/keys
cd /etc/wireguard/keys
umask 077
wg genkey | tee privatekey | wg pubkey > publickey
vim /etc/wireguard/wg0.conf # see client config below
wg-quick up wg0
Enter fullscreen mode Exit fullscreen mode

Client config /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = <client private key>
Address = 10.0.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = <server public key>
Endpoint = <server public ip>:51820
AllowedIPs = 0.0.0.0/0
Enter fullscreen mode Exit fullscreen mode

Resources

Top comments (13)

Collapse
 
atrull profile image
Alex Trull

Great analysis of the steps involved. I absolutely love Wireguard.

If you're interested in integrating wireguard with an existing aws infra I recommend looking at the terraform module github.com/jmhale/terraform-aws-wi... (I made some contributions to this).

Collapse
 
oshanwisumperuma profile image
Oshan Wisumperuma

thanks for the comprehensive article @miguelmota . I tried server setup using ansible scripts(algo). it take few minutes to setup the server configurations. I was looking for something fast so I can dispose the server instance and re create quickly whenever I want. this shell script just do the job
github.com/angristan/wireguard-ins...

Collapse
 
zaffacy profile image
Zafar Karimov

Experiencing problem with CORS headers. It says:
Access to XMLHttpRequest at '' from origin 'https://drive.google.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Anybody experienced such problem?

Collapse
 
shawnngtq profile image
Shawn Ng • Edited

@miguelmota

Nice tutorial, I managed to set it up.

I noticed that despite the IP address shows the correct server IP (via ipchicken.com/), I am still unable to bypass my country's firewall, and Google home page still display my home country instead of the server's country. Am I missing something?

Collapse
 
prashanthmgvr profile image
Prashanth Mogaveera

Great Blog!!

I was able to setup the till wg-quick up wg0. When I ran systemctl status wg-quick@wg0.service getting error as systemd[1]: Failed to start WireGuard via wg-quick(8) for wg0.

Any Idea what might be the reason here? I'm not able to get the logs for wireguard. Any help would be appreciated!

Collapse
 
jeffprod profile image
JeffProd

Great article. Some suggestions :

In "Generating client keys", you wrote:

[root@archlinux ~]# mkdir /etc/wireguard/keys
[root@archlinux ~]# umask 077
...
[root@archlinux keys]# wg genkey | tee privatekey | wg pubkey > publickey

you missed "cd /etc/wireguard/keys"

In "Starting WireGuard service on server", when i type on Ubuntu "wg-quick up wg0" I had the error "RTNETLINK answers: Operation not supported".
If it helps, the solution found on StackOverflow is "apt-get install wireguard-dkms wireguard-tools linux-headers-$(uname -r)"

Collapse
 
miguelmota profile image
Miguel

The post has the corrections and error solution now. Thanks!

Collapse
 
rizowski profile image
Rizowski

This is the longest most extensive article that doesn't just end before the point is made. Well done. I applaud the effort. 👍👏

Collapse
 
starpebble profile image
starpebble

Fantastic quick start. My little feedback: Looks like connecting is the most fun part. 😇

Collapse
 
greenteabiscuit profile image
Reishi Mitani

Thanks so much for the great tutorial! I was able to connect my raspberry pi and my EC2 instance from your instructions.
I had a bit of problems with the modules but it worked out fine in the end.

Collapse
 
artis3n profile image
Ari Kalfus

I would also recommend tailscale.com/ to abstract away the wireguard internals. Makes it really simple for the everyday person.