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 wireguardYou 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
[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.
[Match] Name = wg0 [Network] Address = 10.200.200.1/24 IPMasquerade = yes
That’s the server. Don’t forget to open the UDP port
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 = 220.127.116.11 [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:
- Without a registered public key on the server, WireGuard server will not respond to packets and so port scanners will not detect it.
- WireGuard Android app is still in beta as of this writing.
- WireGuard itself is not in the mainline Linux.
- WireGuard Android app routes private IPs through the VPN as well. This means, while the VPN is active, you won’t be able to talk to other devices on your local WiFi for instance (e.g. Chromecast).
- You can register multiple clients on your server by copying the
[WireGuardPeer]section with different IP and public key.
- WireGuard talks UDP and has excellent support for roaming. This means that you can start a download while on WiFi and switch to 4G without disruptions.