WireGuard VPN Overview
Benefits of WireGuard
- Performance and Speed: In benchmarks, WireGuard outclasses both OpenVPN and IPsec in not only throughput, but also latency.
- Ease of Deployment: Setting up a VPN can sometimes be a bit of a bear. With WireGuard, setting up the VPN server is easy and only takes a few steps. It'll take even fewer steps when the WireGuard packages find their way into Raspbian.
- Security: A VPN makes your remote laptop just another device on the network, just as if you were at home. In doing so, this allows you to access all of your network's resources locally. If you don't utilize a VPN, then you have to port forward to make your homelab's local resources available over the internet. Do this enough times and the firewall that separates your home network from the internet starts to look like swiss cheese with all of the holes you've punched through it with those port forwards. VPNs allow you to minimize your network's attack surfaces to a single (very secure) port forward for the VPN server. WireGuard uses the latest, state-of-the-art cryptography.
- Low overhead -> Better Battery Life: WireGuard, as described by its developer, isn't a chatty protocol. The client sends its request and then shuts up. It tries to avoid keep alive handshakes if they're not needed. As a result, when you're working on a laptop on wireless, your wireless card has a higher likelihood of being able to idle down which leads to better battery life. (An idle wifi card uses something like ~20 mW at idle but can easily climb to ~2W under load). Anecdotally, in my own testing, I have noticed a significant improvement in battery life when working remotely on WireGuard compared to OpenVPN.
How The WireGuard VPN Tunnel Works
The above diagram depicts how setting up the WireGuard VPN tunnel works with a Raspberry Pi. With WireGuard, a tunnel is created with a virtual network interface (wg0 in this case). These interfaces are created on both the client and on the RPi VPN server, enabling them to talk to each other.
In order for the client to be able to locate the RPi VPN server across the internet, a dynamic DNS provider is required. This allows us to track our homelab's public IP address with a URL. When our WireGuard client requests the URL, an IP address is returned corresponding to our router's WAN address. In my case, I simply use this site's URL (engineerworkshop.com) since I am self hosted.
In a process known as port forwarding, when our WireGuard client sends a request to engineerworkshop.com on port 51900, the router takes that request and forwards it on to the Raspberry Pi, connected to the router on eth0 with IP address 10.0.20.149 also on port 51900. This is a form of network address translation (NAT).
- Raspberry Pi (or any other Debian-based machine; an Ubuntu VM will also work)
- DDNS (dynamic domain name service)
As mentioned previously, a DDNS service is required to track your Raspberry Pi (i.e. your new WireGuard server) so that your client can find your server. This can be in the form of a formal domain name, such as the one you use if you are self-hosting a website like I am. If you're interested in doing this, more information can be found here:
You do not need to purchase a domain name for this and alternatively you can use one of the widely available (and free) DDNS services such as no-IP and Duck DNS. Ultimately, we just need some way of knowing what your RPi's public (WAN) IP address is.
Install WireGuard On The Raspberry Pi
1. Currently, WireGuard is not included in the Raspbian distribution, therefore we will need to add the Debian distro:
echo "deb http://deb.debian.org/debian/ unstable main" | sudo tee --append /etc/apt/sources.list
2. Next, install the Debian distro keys:
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 04EE7237B7D453EC apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138
3. Prevent RPi from using the Debian distro for normal Raspbian packages:
sudo sh -c 'printf "Package: *\nPin: release a=unstable\nPin-Priority: 90\n" > /etc/apt/preferences.d/limit-unstable'
4. Update your package list:
sudo apt-get update
5. Install WireGuard:
sudo apt install wireguard
Set Up and Configure the WireGuard VPN Server
Generate security keys
To ensure that not just anyone gets access to our network and ensure a secure connection, we'll first need to generate a set of public/private key pairs with the following commands (execute them one line at a time in your RPi):
sudo su cd /etc/wireguard umask 077 wg genkey | tee server_private_key | wg pubkey > server_public_key wg genkey | tee client_private_key | wg pubkey > client_public_key
Retrieve the keys generated above with:
cat server_private_key cat server_public_key cat client_private_key cat client_public_key
We'll need these for later when we create the server and client configuration files below.
Generate server configuration (wg0.conf)
Create the WireGuard Server configuration with:
And add the following:
[Interface] Address = 10.253.3.1/24 SaveConfig = true PrivateKey = <insert server_private_key> ListenPort = 51900 PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE [Peer] PublicKey = <insert client_public_key> AllowedIPs = 10.253.3.2/32
Be sure to replace the key values in the configuration for PrivateKey and PublicKey.
Enable IP Forwarding on the Server
Edit sysctl.conf on the Raspberry Pi with:
Uncomment the line with "net.ipv4.ip_forward=1" and save.
Start Up WireGuard
Set up WireGuard to start automatically on reboot:
systemctl enable wg-quick@wg0 chown -R root:root /etc/wireguard/ chmod -R og-rwx /etc/wireguard/*
Reboot your RPi for all of your changes to take effect.
Set Up Port Forwarding On The Router
Finally, to enable our local client to be able to access our new Raspberry Pi WireGuard server, we need to set up our router to forward any traffic it receives on port 51900 to our Raspberry Pi. This is known as port forwarding and the set up varies from router to router. For an additional reference, see this guide on setting up port forwarding.
In my case, since I'm using a pfSense firewall, I will show you what it looks like on my router:
The above port forwarding rule says that any traffic with a destination of the WAN address (i.e. our public IP address) and port 51900, take that traffic and forward it to 10.0.20.149 on port 51900. You'll most likely have to change this IP address to whatever the IP address is of your Raspberry Pi.
Set Up the WireGuard Client
Generate the WireGuard Client Configuration (wg0-client.conf) File
On your client, create the client configuration file, wg0-client.conf. This can be done using Notepad, if you'll be connecting from Windows, or nano if you're using Ubuntu/Linux:
[Interface] Address = 10.253.3.2/32 PrivateKey = <insert client_private_key> DNS = 188.8.131.52 [Peer] PublicKey = <insert server_public_key> Endpoint = <insert vpn_server_address>:51900 AllowedIPs = 0.0.0.0/0, ::/0
Connecting To Your New WireGuard VPN Tunnel
With your new client configuration (wg0-client.conf) file created, if your client is also a Linux client, check out the following guide for how to connect to your new RPi WireGuard VPN server:
If you're on a Windows machine, jump to step 10 of the following guide:
Update (3/4/20): If you have your WireGuard configuration set improperly, WireGuard can leak if you're using an IPv6 internet connection (common if you're using a cellular hotspot). I have updated the client configuration above to fix the issue. You can read more about the WireGuard IPv6 leak issue on a cellular hotspot in the forum.