Wireguard > OpenVPN
This post will guide you through the most basic WireGuard scenario: connecting from a remote device (“peer”) to a server somewhere out there through which you want to route your traffic securely.
I’ve always been on a crusade to improve VPN performance since I do a fair bit of work remotely with reasonable bandwidth at my disposal. Until WireGuard, I’d not been happy with the performance hit most VPN implementations impose. With WireGuard, I can get 900+mbps out of a gigabit link with minimal CPU overhead.
WireGuard is a kernel module that creates a virtual interface (wg0
) that can be manipulated using standard tools like route
and ifconfig
. As such, you’ll need to be running a reasonably recent Linux kernel. If you’re running a custom or older kernel, you might want to first see the requirements to make sure you’re good to go.
The examples shown below are run on an Ubuntu 16.04 install with a 4.4 kernel and a peer running macOS Mojave.
1. Install WireGuard on your server
SSH in and install the WireGuard packages:
sudo add-apt-repository ppa:wireguard/wireguard
sudo apt update
sudo apt install wireguard-dkms wireguard-tools
If you see any errors, particularly with DKMS, you should really go read the requirements above.
2. Generate a keypair for your server
Please take good care of your keys. Don’t leave them sitting around!
You need to have a public and private key on every system that runs WireGuard. You’ll be running this command a lot, so it helps to understand what’s going on.
First, your umask
is set to 077
. This ensures that the resulting files, privatekey
and publickey
are readable only by you. Then, we use the Wireguard command wg
to generate the private key, and then use the private key to generate a public key.
umask 077; wg genkey | tee privatekey | wg pubkey > publickey
3. Create the configuration file
Configs are held in /etc/wireguard
. We’ll configure this as /etc/wireguard/wg0.conf
:
[Interface]
Address: 10.20.90.1/24
PostUp: iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o br0 -j MASQUERADE
PostDown: iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o br0 -j MASQUERADE
ListenPort: 51820
PrivateKey: <contents of “privatekey” generated earlier>
SaveConfig: true
Note that in your case, you will likely need to substitute eth0
for my example above. I have a bridge interface (br0
) on my host that contains my eth0
interface. If you want to do IPv6, you’ll need to add corresponding IPv6 rules using ip6tables
. You’ll also have to add an IPv6 address to the [Interface]
configuration right after your IPv4 network, separated by a comma.
In this example, you’ll see that we are allocating 10.20.90.1/24
to the wg0
interface. Peers that connect will have addresses within this subnet.
4. Permit incoming traffic
Make sure your firewall permits incoming traffic to the ListenPort defined above. Since we defined the port as 51820
, that’s what needs to be allowed in. Wireguard uses UDP, so make sure you allow UDP and not TCP traffic:
ufw allow 51820/udp
5. Optional: set WireGuard to start on boot
This ensures that WireGuard will start and listen for connections after system reboots.
systemctl enable wg-quick@wg0
6. Start WireGuard
Wireguard ships with a helper, called wg-quick
, that you’ll use to start/stop the service as well as perform other duties.
wg-quick up wg0
At this point, your WireGuard server is ready to go. It’s listening for incoming connections from other peers (clients) and will start automatically should you reboot your server.
Adding Peers
For each client, you’ll follow the same procedure as outlined below. For mobile devices, you can craft a configuration file as seen below and encapsulate it within a QR code that WireGuard apps can use to quickly import. To do so, use qrencode -t ansiutf8 < wg0.conf
.
1. Generate a keypair for your peer
I did warn that you’ll be using these commands again!
umask 077; wg genkey | tee privatekey | wg pubkey > publickey
2. Create the configuration file
Just like on the server, create /etc/wireguard/wg0.conf
[Interface]
PrivateKey: <contents of the privatekey file you generated on the client>
Address: 10.20.90.101/32
DNS: 8.8.8.8
[Peer]
PublicKey: <contents of the publickey file generated on the server>
AllowedIPs: 0.0.0.0/0, ::/0
Endpoint: <ip of your Wireguard server>:51820
PersistentKeepalive: 25
3. Add the peer to the server
Because we specified SaveConfig above, don’t edit wg0.conf
by hand. Instead, use the ‘wg’ CLI to add the peer:
wg set wg0 peer <contents of the publickey file on your client> allowed-ips 10.20.90.101/32
4. Connect to the server
You should now be able to start WireGuard on the client and it will connect and route all its traffic through the WireGuard server. On the client side, use wg-quick
to turn up the interface, just like on the server: wg-quick up wg0
On either the client or server, you can use ‘wg’ to see client status. Before a client connects, it’ll look similar to this:
# wg
interface: wg0
public key: <…>
private key: (hidden)
listening port: 51820
peer: <…>
allowed ips: 10.20.90.101/32
Once a client connects, you’ll see more detail, like this:
# wg
interface: wg0
public key: <…>
private key: (hidden)
listening port: 51820
peer: <…>
endpoint: <your remote public IP and port>
allowed ips: 10.20.90.102/32
latest handshake: 4 seconds ago
transfer: 16.76 KiB received, 10.14 KiB sent
That’s it! There are many settings you can play with to adjust how traffic flows such as routing smaller subnets of traffic through the Wireguard tunnel and leaving the rest alone. Because WireGuard uses a simple interface, you can use all your standard host utilities to manipulate traffic just as you would a traditional Ethernet interface.