Set up a Wireguard VPN on Ubuntu and connect from Mac and Android


How to set up a Wireguard server on Ubuntu and set up clients on Mac and Android.

About Wireguard

Wireguard is a relatively new VPN technology that according to the website:

is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN.

Bear in mind that Wireguard has not been audited and is still in development, so use it at your own risk.

Let’s set one up and see if it meets expectations!

Set up Wireguard server on Ubuntu

First get hold of a Linux VPS on a cloud provider of your choice. I use an AWS EC2 micro with Ubuntu 18.04. A Digital Ocean droplet would also be a good choice.

When setting up the firewall you will need to add an inbound rule for UDP traffic on port 51820, or whichever port you want to run the Wireguard server on. In AWS you can configure this in the security group when setting up the sever.

Install Wireguard

Once you’re set up and SSH’d into your server, install Wireguard as follows:

  1. Install the software-properties-common package so we can use add-apt-repository

    1
    
    sudo apt-get install -y software-properties-common
    
  2. Install Wireguard

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

Enable IP forwarding

In order to be able to access the internet once connected to the VPN server we need to enable IP forwarding. To enable it immediately run

1
sudo sysctl -w net.ipv4.ip_forward=1

And to make this change persist after reboots, edit /etc/sysctl.conf and uncomment the line net.ipv4.ip_forward=1.

Create server config

  1. First generate a public/private key pair

    1
    2
    
    umask 077
    wg genkey | tee privatekey | wg pubkey > publickey
    
  2. For extra security you can also generate a pre-shared key for each client. This adds an extra layer of symmetric key encryption for post quantum resistance:

    1
    2
    3
    
    wg genpsk > client1
    wg genpsk > client2
    ...
    
  3. Create the file /etc/wireguard/wg0.conf and enter the following contents, replacing the placeholders with the correct values for your setup:

    1
    2
    3
    4
    5
    6
    
    [Interface]
    Address = <wireguard_internal_server_ip>
    PrivateKey = <server_private_key>
    ListenPort = 51820
    PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens5 -j MASQUERADE;
    PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens5 -j MASQUERADE;
    
    • <wireguard_internal_server_ip> is a private IP address for the wg0 interface. It’s best to pick one on a different subnet to your LAN. If you’re not sure use 10.0.0.1/32.

    • <server_private_key> is the private key we generated in step 1.

    • If you chose a different port for the Wireguard server then replace 51820 with your value.

    • In the PostUp and PostDown commands replace ens5 with the name of the network interface that has access to the internet. Yours may be called eth0 for example.

    • The PostUp gets executed after the Wireguard server is started. The command specified here adds some firewall rules that will allow you to connect to the internet through the VPN server. PostDown gets executed when the Wireguard server is shut down and the command specified here removes the firewall rules created in PostUp.

  4. If you’re setting up the server behind NAT (e.g. if the server is on your home network behind a router) then you may want to add the additional setting:

    7
    
    PersistentKeepalive = 25

    This will send an empty authenticated packet every 25 seconds to keep your firewall or NAT mapping persistent.

  5. We will need to add a section to this config file for each client that will connect to the server. First we’ll create the client configs and then return to add these sections.

Set up Wireguard client on Mac

Install and configure client config

  1. Install the official Wireguard app from the App store https://itunes.apple.com/us/app/wireguard/id1451685025?mt=12.

  2. Click on the wireguard tray icon and select ‘Manage Tunnels’

    manage tunnels

  3. Create a new empty tunnel and enter the following configuration, replacing the tokens with the correct values for your setup:

    add tunnel

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    [Interface]
    PrivateKey = <auto_generated>
    Address = <wireguard_internal_client_ip>
    DNS = 1.1.1.1
    
    [Peer]
    PublicKey = <server_public_key>
    PresharedKey = <client_server_preshared_key>
    AllowedIPs = 0.0.0.0/0, ::/0
    Endpoint = <server_public_ip_address>:51820
    
    • <auto_generated> is a private key automatically generated by the Wireguard app.

    • <wireguard_internal_client_ip> is the private IP address for the client’s Wireguard network interface. It should be on the same subnet as <wireguard_internal_server_ip>. If you used 10.0.0.1/32 for the server put 10.0.0.2/32 here.

    • <server_public_key> is the public key for the server generated in the previous section.

    • <client_server_preshared_key> is the optional pre-shared key generated in the previous section.

    • <server_public_ip_address> is the public IP address of your server. If you used a different port, change 51820 to value you used.

    • The DNS can be set to any provider you like. Here we’re using Cloudflare’s 1.1.1.1 public DNS.

    • AllowedIPs is the set of IP addresses to redirect down the VPN tunnel. Here we’ve set it to match all IP addresses, i.e. all non local traffic will get sent over the VPN. If you want to configure split tunneling you can adjust this range of IP addresses to suit your setup.

Add client to server config

When creating the server config we said we’d need to add some extra configuration for each client. Now that we’ve generated the client config we are ready to add these sections.

  1. Open /etc/wireguard/wg0.conf on the Wireguard server and append the following (repeating this block if there are multiple clients):

    1
    2
    3
    4
    
    [Peer]
    PublicKey = <client_public_key> 
    PresharedKey = <client_server_preshared_key>
    AllowedIPs = <wireguard_internal_client_ip>
    
    • <client_public_key> is the client’s public key.

    • <client_server_preshared_key> is the optional pre-shared key for this client.

    • <wireguard_internal_client_ip> is the private IP address for the client’s wireguard network interface. If you used 10.0.0.2/32 in the previous section then enter that here.

  2. Save and close the config file.

Start up Wireguard

Now that everything is configured it’s time to start all the applications.

Start the server

  1. On the server run

    1
    
    sudo wg-quick up wg0
    

    To verify that everything has started run

    1
    
    sudo wg show
    

    You should see a print out of the server interface and configured clients.

  2. To start Wireguard automatically on startup enable the service

    1
    
    sudo systemctl enable wg-quick@wg0
    

Connect from the client

In the Wireguard app select your tunnel in the list and check the box next to ‘Status Inactive’. If all is well you should see the status change to ‘Active’ and some information about when the last successful handshake was.

tunnel connected

Set up an Android client

Install the Wireguard app from the app store https://play.google.com/store/apps/details?id=com.wireguard.android.

There are a number of ways to set up the client config. You can either create a config within the app and set up the server in the same way as setting up the Mac client, or you can create the client config on you server/mac and generate a QR code to scan it in.

To generate a QR code you’ll need to install qrencode. On Linux run:

1
sudo apt install qrencode

On Mac:

1
brew install qrencode

To generate the QR code from a config called mobile.conf run

1
qrencode -t ansiutf8 < mobile.conf

This will print out a QR code in the terminal which you can scan in.

References