Setting up WireGuard

Update Nov 11, 2021: Added a note about UFW support.

Recently I decided to set up WireGuard on a Ubuntu 18.04 VM just to try it out. These are my notes on how I did it, including setup instructions for Android and macOS. They largely duplicate a lot of existing articles on how to do this, but I found many articles omit something or other that can take a while to figure out if you haven’t set up a VPN before.

The Server

This was set up using Ubuntu 18.04.3 on DigitalOcean. First, you need to install wireguard:

$ sudo add-apt-repository ppa:wireguard/wireguard
$ sudo apt update
$ sudo apt install wireguard

Next, we need to generate the private and public keys

$ sudo su
# cd /etc/wireguard
# umask 077     # so permissions on the files are 600
# wg genkey | tee privatekey | wg pubkey > publickey
# exit

Now we can create our initial config file /etc/wireguard/wg0.conf. Replace <ServerPrivateKey> with the contents of /etc/wireguard/privatekey.

[Interface]
Address = 10.0.0.1/24
Address = fd86:ea04:1111::1/64
SaveConfig = true
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i %i -j ACCEPT; ip6tables -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; ip6tables -D FORWARD -i %i -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820
PrivateKey = <ServerPrivateKey>

The %i refers to the interface name, which is specified when using wg-quick. All the iptables stuff is to allow traffic to pass through the VPN and to the external world, using the external IP address of the server.

NOTE: If you’re using UFW, you may find you need to add the following to PostUp and PostDown:

PostUp = [...]; ufw route allow in on wg0 out on eth0; ufw route allow in on eth0 out on wg0
PostDown = [...]; ufw route delete allow in on wg0 out on eth0; ufw route delete allow in on eth0 out on wg0

The VPN works fine without those additions, but you may see UFW BLOCK logging messages about certain IP addresses (even though you can ping those IPs just fine through the VPN); I noticed it mostly with 1.1.1.1 and 8.8.8.8.

To allow forwarding of IP traffic to the external world, you’ll also need to ensure you have the following 2 settings in /etc/sysctl.conf (they’re commented out by default):

net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

Reload sysctl using:

$ sudo sysctl --system

Now let’s allow traffic to port 51820 that we set above:

$ sudo ufw allow 22/tcp         # in case you've never set this before
$ sudo ufw allow 51820/udp
$ sudo ufw enable

And now we can bring up the interface:

$ sudo systemctl enable wg-quick@wg0
$ sudo systemctl start wg-quick@wg0

You can check on the interface using:

$ sudo wg show

Setting up some clients

When setting up clients, we need to generate a key pair on the client, and also decide on an IP address for said client. Let’s say we’re setting up our first client, so for simplicity, the IP addresses will be the server’s plus one; i.e. 10.0.0.2/32, fd86:ea04:1111::2/128.

Now on the server, we’ll add the new peer:

$ sudo wg set wg0 peer <ClientPublicKey> allowed-ips 10.0.0.2/32,fd86:ea04:1111::2/128
$ sudo wg-quick save wg0   # just in case

On the client side, we’ll have a config that looks like this:

[Interface]
PrivateKey = <ClientPrivateKey>
Address = 10.0.0.2/32, fd86:ea04:1111::2/128
DNS = 1.1.1.1

[Peer]
PublicKey = <ServerPublicKey>
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = <ServerExternalIP>:51820

Depending on your client, you will have different ways of inputting those values (Android gives you a form UI, macOS gives a field in which you type that config).

Some general notes:

  • On Android, if you click “Exclude private IPs”, it may append a blank /32 at the end of the allowed IPs, which is invalid (probably a bug), so you’ll want to remove that.
  • On macOS, you can also set “Exclude private IPs” instead of sending everything through the tunnel
  • If excluding private IPs, you may want to add 10.0.0.0/24 to the list of allowed IPs so that you can ping your peers.
  • On Android you can leave the DNS Servers field blank, but on macOS you have to set it to something.
  • On macOS you should use “Create tunnel from scratch” so you can write your own config
Published on December 20, 2019.