16th January 2019 - I have updated the article to include DNS lookups over VPN too, where as previously they would have been going out via your ISP/WiFi/mobile provider.
WireGuard is the new kid on the block when it comes to VPNs. I could try and explain what it is and why you should switch from OpenVPN or IPsec to it, but they do a great job of that themselves:
WireGuard® 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.
“Great” I hear you say, “but IPSec and OpenVPN are a pain to setup, let alone setup securely”. Fear not, WireGuard has you covered:
WireGuard aims to be as easy to configure and deploy as SSH. A VPN connection is made simply by exchanging very simple public keys – exactly like exchanging SSH keys – and all the rest is transparently handled by WireGuard.
This guide will walk you through how to setup WireGuard in a way that all your client outgoing traffic will be routed via another machine (server). This is ideal for situations where you don’t trust the local network (public or coffee shop wifi) and wish to encrypt all your traffic to a server you trust, before routing it to the Internet.
Server Setup Guide
I am making some assumptions here, such as using Ubuntu for your server OS, so please tweak to fit your situation.
First up, we need to make sure you’ve got the kernel headers installed, as well as enabling IPv4 forwarding:
sudo apt install linux-headers-$(uname -r) sysctl net.ipv4.ip_forward=1 echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-sysctl.conf # Make the change persistent
Because WireGuard isn’t currently part of the distributed Ubuntu packages, we’ll add the helpful PPA repository to keep things easy and up to date.
sudo add-apt-repository ppa:wireguard/wireguard sudo apt update sudo apt install wireguard sudo modprobe wireguard
With WireGuard now installed, we need to generate a public and a private key – fortunately, this is a simple one-liner:
wg genkey | tee /etc/wireguard/server-privatekey | wg pubkey > /etc/wireguard/server-publickey
Next up, we need to create a WireGuard config file:
sudo nano /etc/wireguard/wg0.conf [Interface] Address = 10.200.200.1/24 Address = fd86:ea04:1115::1/64 SaveConfig = true DNS = 10.200.200.1 # Change eth0 to your network interface if it differs PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; iptables -A INPUT -s 10.200.200.0/24 -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT; iptables -A INPUT -s 10.200.200.0/24 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE ListenPort = 51820 PrivateKey = <contents of /etc/wireguard/server-privatekey>
We also need a DNS server running, to forward our requests from the clients rather than letting the clients go out to their local/ISP provided DNS. I have pinched most of this from ck’s Wireguard setup guide.
apt-get install unbound unbound-host curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache
sudo nano /etc/unbound/unbound.conf server: num-threads: 4 #Enable logs verbosity: 1 #list of Root DNS Server root-hints: "/var/lib/unbound/root.hints" #Use the root servers key for DNSSEC auto-trust-anchor-file: "/var/lib/unbound/root.key" #Respond to DNS requests on all interfaces interface: 0.0.0.0 max-udp-size: 3072 #Authorized IPs to access the DNS Server access-control: 0.0.0.0/0 refuse access-control: 127.0.0.1 allow access-control: 10.200.200.0/24 allow #not allowed to be returned for public internet names private-address: 10.200.200.0/24 # Hide DNS Server info hide-identity: yes hide-version: yes #Limit DNS Fraud and use DNSSEC harden-glue: yes harden-dnssec-stripped: yes harden-referral-path: yes #Add an unwanted reply threshold to clean the cache and avoid when possible a DNS Poisoning unwanted-reply-threshold: 10000000 #Have the validator print validation failures to the log. val-log-level: 1 #Minimum lifetime of cache entries in seconds cache-min-ttl: 1800 #Maximum lifetime of cached entries cache-max-ttl: 14400 prefetch: yes prefetch-key: yes Last but not least, we need to tidy up some permissions and give unbound a kick to bring it to life. ```shell sudo chown -R unbound:unbound /var/lib/unbound sudo systemctl enable unbound sudo systemctl start unbound
At this point, WireGuard on the server is complete and we could start it up if we wanted, but first, lets configure our client.
iOS Client Setup Guide
Our first client is an Apple iOS device. Currently WireGuard isn’t built into the operating system, unlike IPSec or IKEv2. However, we can easily overcome this hurdle thanks to the WireGuard iOS App which is currently in alpha and can be installed easily via TestFlight. Alternatively you can check out another 3rd party client produced by TunSafe which again can be installed via TestFlight.
With one of the two apps installed, lets generate a config server-side and we can transfer it later with a simple QR code. We could manually enter a config within the app, however moving around those keys can be a nightmare…
First up, client private and public keys:
cd /etc/wireguard wg genkey | tee mobile-privatekey | wg pubkey > mobile-publickey
We need to configure our mobile client as a peer within
wg0.conf, so that we can connect to our server.
[Interface] [...] [Peer] # Our mobile client details PublicKey = <contents of mobile-publickey> AllowedIPs = 10.200.200.2/32, fd86:ea04:1115::2/128
That is everything we need to do for our server config - simple right?
To split things up a little, lets start WireGuard. We can bring the interface up with
wg-quick up wg0, as well as down with
wg-quick down wg0.
However if you would rather run it as a service so that it is always brought up on start-up or after reboots, we can utilise
systemctl enable wg-quick@wg0 # Enable to start at boot-up systemctl start wg-quick@wg0 # Start to.. well, start.
You can get the current status of WireGuard by simply running
root@lon-vpn:/etc/wireguard# wg interface: wg0 public key: 3YjKyxxxxxxxxxxxxxxxxxxxxxxxxxxxsx856vfcQc= private key: (hidden) listening port: 51820 peer: x8roC6GOxxxxxxxxxxxxxxxxxxxxxxxdi7Uhol6xY= allowed ips: 10.200.200.2/32, fd86:ea04:1115::2/128
With WireGuard successfully running, lets create a
conf file for our iOS device which we will transfer via QR code. We can do all of this whilst we are still on our server.
cd /etc/wireguard nano mobile.conf [Interface] PrivateKey = <contents of mobile-privatekey> Address = 10.200.200.2/32, fd86:ea04:1115::2/128 DNS = 22.214.171.124 [Peer] PublicKey = <contents of server-publickey> Endpoint = <server-ip>:51820 AllowedIPs = 0.0.0.0/0, ::/0
Mobile config done. Lets get it transferred to our device. We will do this using a QR code, which we can create on our server using
qrencode. You can install this via
apt install qrencode.
To generate the QR code and display it on the screen:
qrencode -t ansiutf8 < /etc/wireguard/mobile.conf
Simply scan this code using one of the iOS apps mentioned previously, and you will be all setup! Enjoy routing all of your traffic via your server. You can verify this by visiting https://canihazip.com or similar on your device.