WireGuard VPN on Android

My recent experience with Telstra mobile’s DNS resolver constantly pooping itself, leaving me without working 4G connection on my Pixel 2 Android phone, prompted me to look for solutions. How do I know it was the DNS resolver issue? Well I got myself a ping tool and found that I could ping various servers just fine. I did try the Private DNS feature of Android to no avail. Most of the time it doesn’t do anything!

Unfortunately, Android doesn’t allow manually setting DNS on mobile connection (only on WiFi and VPN). So the only option I had left was to look at VPN tunnels. Forget about OpenVPN and IPSEC. For my use case, they were mind numbingly difficult to setup and I gave up on both very quickly. Then I remembered WireGuard, a tiny feature of Linux kernel brewing at the moment, which lets you define an encrypted network interface with public key cryptography. There is also an app available for Android. This thing is so simple to setup and so reliable that I was hooked right off the bat.

I picked Google Cloud to setup my VPN server. I used a standard Ubuntu 18.10 machine with WireGuard tools setup. The reason for picking Ubuntu 18.10 is due to its more recent version of systemd. That comes in handy later on.

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

You may need to restart after this to load the WireGuard module.

Next, we need two pairs of private/public keys, one for the server, and one for the Android app:

wg genkey | (
  read privk
  echo "server-private-key: $privk"
  echo "server-public-key:  $(echo "$privk" | wg pubkey)"
)
wg genkey | (
  read privk
  echo "android-private-key: $privk"
  echo "android-public-key:  $(echo "$privk" | wg pubkey)"
)

With the keys in hand, server can be setup, which includes two simple systemd network config files. A .netdev file to setup a new WireGuard interface and a .network file to configure it for NAT.

/etc/systemd/network/vpn.netdev:

[NetDev]
Name = wg0
Kind = wireguard

[WireGuard]
ListenPort = 51820
PrivateKey = server private key goes here

[WireGuardPeer]
PublicKey = android public key goes here
AllowedIPs = 10.200.200.2/32

Ensure the file is only readable by root: sudo chmod 600 /etc/systemd/network/vpn.netdev as it contains private key.

/etc/systemd/network/vpn.network:

[Match]
Name = wg0

[Network]
Address = 10.200.200.1/24
IPMasquerade = yes

That’s the server. Don’t forget to open the UDP port 51820 on your firewall. A restart of network daemon should set things up: sudo systemctl restart systemd-networkd.

Easiest way to configure the Android app is to create your WireGuard config file on your desktop and scan a QR code of its content. Here’s the config file content:

[Interface]
Address = 10.200.200.2/24
PrivateKey = android private key goes here
DNS = 8.8.8.8

[Peer]
PublicKey = server public key goes here
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = server IP:51820

Print QR code of this config file on the terminal:

qrencode -t utf8 < config_file

Now open the app and import this configuration using the QR scanner option.

Some notes about this setup and WireGuard in general: