I’ve traditionally used only SSH to connect to my home network while being away, but recently I got tired of using only SSH tunnels and SOCKS proxies, and decided to actually fix a working Wireguard configuration.

My router is running OpenBSD, and I want Wireguard clients to be able to reach several different internal subnets. However, I don’t want to route all traffic through the VPN tunnel, only traffic to my internal network. In addition, also want all DNS traffic to use my internal DNS server. This is required since I otherwise won’t be able to find the internal hosts by their domain name.

Therefore I decided to configure Wireguard directly on the router, create a special subnet for VPN clients, and then route traffic between that subnet and my other internal subnets.

Server (OpenBSD)

I like to avoid installing as many packages as possible on my OpenBSD systems, so these instructions are written to avoid installing wireguard-tools, and thus use only commands from base.

As root do:

mkdir /etc/wireguard
chmod 700 /etc/wireguard
(umask 0077; openssl rand -base64 32 > /etc/wireguard/secret.key)
(umask 0077; openssl rand -base64 32 > /etc/wireguard/psk1.key)

Then we move on to configure the wireguard interface by creating the file /etc/hostname.wg0, which will then automatically configure the interface on boot.

Replace SERVER_PRIV_KEY with the contents of /etc/wireguard/secret.key. And set the correct IP address of the server, you can also change the port from the default 51820, if desired. I also added a group vpnnet which simplifies the /etc/pf.conf configuraion later on.

Don’t fill in wgpeer line yet, leave it commented out.

/etc/hostname.wg0

wgkey SERVER_PRIV_KEY wgport 51820
#wgpeer CLIENT_PUBKEY wgpsk CLIENT_SERVER_PSK wgaip 10.0.7.1/32
inet 10.0.7.254 255.255.255.0 NONE group vpnnet

Make sure to run chmod 640 /etc/hostname.wg0 to restrict permissions of the file since it contains the private key.

After this, bring up the interface without restart, and check the public key.

sh /etc/netstart wg0
ifconfig wg0

Look for wgpubkey line, and copy the public key until later. This is what I will call SERVER_PUB_KEY in the next section.

PF configuration

I added the following lines to my /etc/pf.conf. Since I only use Wireguard for split-tunnel purposes, I don’t configure any NAT.

#######################
# VPN-related traffic #
#######################

# Wireguard traffic from internet to firewall
pass in quick on egress proto udp from any to port 51820

# Clients need access to DNS server, running on the firewall too
pass in quick on vpnnet proto udp from any to port domain

# Allow VPN clients access to LAN, DMZ, and VPN subnets, but not to everything on firewall.
pass in on vpnnet inet from (vpnnet:network) to { (vpnnet:network) (dmznet:network) (internal:network) }
block in on vpnnet inet from any to (vpnnet)

Client (Arch)

I first tried to use netctl, that I use for my wireless connection on Arch, but never got it to work. Instead I opted to use wg-quick, which is included in the wireguard-tools package.

As root:

pacman -S wireguard-tools
cd /etc/wireguard
wg genkey | (umask 0077; tee private.key) | wg pubkey > public.key

Since I had to install wireguard-tools anyway, I opted to use it to generate the keys above. That way you can also get the public key more easily.

After this, create /etc/wireguard/wg0.conf with the following content. Replace CLIENT_PRIV_KEY with the newly created /etc/wireguard/private.key from Arch. You also need te replace SERVER_PUB_KEY with the public key from the previous section. Also, replace CLIENT_SERVER_PSK with the content from /etc/wireguard/psk1.key from the server. This is a shared key between both client and server, while not required, it increases the security against attacks from quantum computers in the future.

[Interface]
Address = 10.0.7.1/32
PrivateKey = CLIENT_PRIV_KEY
DNS = 10.0.7.254

[Peer]
PublicKey = SERVER_PUB_KEY
PresharedKey = CLIENT_SERVER_PSK
Endpoint = your.server.domain.name:51820
AllowedIPs = 10.0.0.0/20

Since I’m setting up a split tunnel, I set AllowedIPs to the IP-ranges I want to reach through the tunnel, in CIDR-notation. In this case 10.0.0.0/20 which translates to 10.0.0.0 – 10.0.15.255, which covers the relevant parts of my local network.

Finishing touches on server

Now after we’ve created the keys on the Arch client, we need to add it to the server as well.

Add the client public key to wgpeer line on the server, together with the PSK from /etc/wireguard/psk1.key, and remove the comment marker so it looks like:

wgkey SERVER_PRIV_KEY wgport 51820
wgpeer CLIENT_PUBKEY wgpsk CLIENT_SERVER_PSK wgaip 10.0.7.1/32
inet 10.0.7.254 255.255.255.0 NONE group vpnnet

Make sure the IP address of the client is what you want it to be.

Finally, reload everything with:

sh /etc/netstart wg0

Connect client

Back on the Arch machine, you’re now ready to connect:

wg-quick up wg0

Done :)