I recently decided to try out the hot new VPN protocol on the block, WireGuard. It took me about 2 hours of debugging and diagnostics to make sense of things, so I'm logging my notes here for future reference.

Once you understand what's going on and how the config works, it all makes a lot more sense.

To get the server (or client) installed there are many guides that cover it. I used this one from Linode.

For a client, there are good native macOS and iOS apps available on their respective App Stores. I haven't tried configuring clients on other operating systems yet.

Note: If you're using an iOS and macOS like me, you can copy/paste the keys between devices easily with Universal Clipboard.

Configuring the server

To configure the server you need /etc/wireguard/wg0.conf which will contain the configuration for wg0, a virtual network adapter. It seems like you can have multiple of these.

Your configuration file will look something like this:

[Interface]
Address = ip-address-here
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o ens3 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o ens3 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o ens3 -j MASQUERADE
ListenPort = 51820
PrivateKey = base64-string-here

[Peer]
PublicKey = base64-string-here
AllowedIPs = ip-address-range-here

If you have multiple clients, you can have multiple Peer blocks.

There are a few very important things to check here:

  1. Address should be an IP address, and probably should be on a private range. This is the IP address of your server on the virtual network, not on the public internet.
  2. Change PrivateKey to your actual private key.
  3. Make sure that the iptables commands in PostUp and PostDown use your actual network adapter. I had this set to eth0 for ages before realising that the actual interface on my VPS was ens0.
  4. Change Peer's PublicKey to the public key from your client.
  5. Set AllowedIPs to a virtual address within the virtual network range. This should be CIDR, so for a single address it would have a /32 suffix for IPv4.

On the client:

  1. Set the Addresses to the same /32 range in the server's AllowedIPs block
  2. Set the Endpoint to the server's public IP address, not the virtual network address.
  3. Set the PublicKey to the server's public key. The server's configuration only defined the private key, but you can find the public key by running wg at a shell prompt on the server.
  4. Set AllowedIPs to 0.0.0.0/0 to forward all traffic over the VPN.
  5. You should probably also set a DNS server. I used Cloudflare (1.1.1.1).

Notes on IP addresses

I'm not sure if/how you can run DHCP inside the virtual network, but given the AllowedIPs definitions I'm not sure it's possible.

AllowedIPs sounds like some kind of ACL, but what it really means is "traffic to any of these IPs will be routed over the VPN to this peer." A misunderstanding here was the single biggest contributor to my long hours debugging.

Therefore, AllowedIPs is unique. You cannot have multiple peers with the same IP range.

On the client, AllowedIPs of 0.0.0.0/0 will route all your traffic to the server, which will then forward it thanks to ip_forward and MASQUERADE.

On the server, AllowedIPs of x.x.x.x/32 will send all traffic destined for the client back over the VPN, including responses to traffic forwarded on it's behalf.

You pretty much have to manually keep track of the addresses in your subnet. Clients get a static IP which goes into their configuration, and the server acknowledges/recognizes/etc. it with it's own AllowedIPs block.

It all looks like it's set up to be a lot more flexible and allow for some wickedly complex scenarios, but bugger if I can figure out how to get anything more demanding than 0.0.0.0/0 working.

Congratulations, you just became a human DHCP server.