Configure WireGuard

wg(4) allows us to create a WireGuard pseudo-device interface for VPNs. Packets sent over WireGuard are securely encrypted and transported over UDP.

In this setup, we will configure two OpenBSD machines, wg1 and wg2, to connect together using wg(4). In our examples, these two machines will have IP addresses 192.168.5.2 and 192.168.5.3, respectively. These two addresses must be replaced with publicly routable IP addresses.

Configuring wg(4) interfaces

On the first machine, we generate a private key. We then use ifconfig(8) to create a wg(4) interface, which we use to obtain the public key:

wg1# openssl rand -base64 32
LizlMGTl5tM8EgGl6btVbT++PrtYdtgrvGQ2lO6yfrU=
wg1# ifconfig wg0 create wgport 7111 wgkey LizlMGTl5tM8EgGl6btVbT++PrtYdtgrvGQ2lO6yfrU=
wg1# ifconfig wg0 | grep 'wgpubkey' | cut -d ' ' -f 2
1XuhX5G1c3VeEkXiqkfC9vC/75HPWgy28bnRtRMkxk8=

Repeat this process with the second machine:

wg2# openssl rand -base64 32
dBV9BYAAnIVU2Aw+Um6Z8CWGsZE8Vgb03sZkFrJm2MU=
wg2# ifconfig wg0 create wgport 7222 wgkey dBV9BYAAnIVU2Aw+Um6Z8CWGsZE8Vgb03sZkFrJm2MU=
wg2# ifconfig wg0 | grep 'wgpubkey' | cut -d ' ' -f 2
Mqud/KzSVrKRaKzxLz9aU8/1lRChbBwkmOz0hQq1RxM=

We now use this information to create the interface file /etc/hostname.wg0. On machine wg1:

wg1# cat /etc/hostname.wg0
wgport 7111 wgkey LizlMGTl5tM8EgGl6btVbT++PrtYdtgrvGQ2lO6yfrU=
wgpeer Mqud/KzSVrKRaKzxLz9aU8/1lRChbBwkmOz0hQq1RxM= wgendpoint 192.168.5.3 7222 wgaip 10.0.5.2/32 wgpka 20
inet 10.0.5.1 0xffffff00
wg1# sh /etc/netstart wg0

On machine wg2:

wg2# cat /etc/hostname.wg0
wgport 7222 wgkey dBV9BYAAnIVU2Aw+Um6Z8CWGsZE8Vgb03sZkFrJm2MU=
wgpeer 1XuhX5G1c3VeEkXiqkfC9vC/75HPWgy28bnRtRMkxk8= wgendpoint 192.168.5.2 7111 wgaip 10.0.5.1/32 wgpka 20
inet 10.0.5.2 0xffffff00
wg2# sh /etc/netstart wg0

Replace the public key and private key with your own uniquely generated strings. Replace @192.168.5.2@ and @192.168.5.3@ with the publicly routable IP addresses of the two machines. Replace 10.0.5.1 and 10.0.5.2 with the IP addresses of the WireGuard interfaces (these IP addresses will not be publicly routable).

Verify that wireguard is working:

wg2# ping 10.0.5.1
PING 10.0.5.1 (10.0.5.1): 56 data bytes
64 bytes from 10.0.5.1: icmp_seq=0 ttl=255 time=2.378 ms
64 bytes from 10.0.5.1: icmp_seq=1 ttl=255 time=0.775 ms

wg1# tcpdump -ne -i wg0 'icmp'
tcpdump: listening on wg0, link-type LOOP
01:10:08.043339 10.0.5.2 > 10.0.5.1:icmp: echo request
01:10:08.043353 10.0.5.1 > 10.0.5.2:icmp: echo reply
01:10:09.060209 10.0.5.2 > 10.0.5.1:icmp: echo request
01:10:09.060220 10.0.5.1 > 10.0.5.2:icmp: echo reply

Client-server

Typically, one machine will act as the server, and the other as the client. Beyond the basic configuration, we will configure wg1 to act as server, and wg2 as client. All traffic from wg2 will be tunneled to wg1 and forwarded to the broader Internet.

First, what we must do is set wg2's default interface to use a different rdomain(4). For example, if wg2 normally uses static networking, we would have:

# cat /etc/hostname.if0
rdomain 1
inet 192.168.5.3 0xffff0000
!route -T1 add default 192.168.5.1

Replace 192.168.5.3 with your device's actual IP address, replace 192.168.5.1 with the actual default gateway, and replace if0 with the actual interface name.

If WiFi and DHCP are used instead, the configuration might be:

# cat /etc/hostname.if0
join NWID wpakey PRIVKEY
rdomain 1
inet autoconf
up

We update machine wg2's /etc/hostname.wg0 to make 10.0.5.1 the default route. We use the rtable 1 to connect to our WireGuard peer and we loosen the wgaip restrictions on wg1's wg(4) interface (since replies will come from source IPs all over the Internet):

wg2# cat /etc/hostname.wg0
wgport 7222 wgkey 'dBV9BYAAnIVU2Aw+Um6Z8CWGsZE8Vgb03sZkFrJm2MU='
wgpeer 1XuhX5G1c3VeEkXiqkfC9vC/75HPWgy28bnRtRMkxk8= wgendpoint 192.168.5.2 7111 wgaip 0.0.0.0/0 wgpka 20
wgrtable 1
inet 10.0.5.2 0xffffff00
!route add -inet default 10.0.5.1

Now traffic from machine wg2 is routed through wg1.

In order for DNS to work, wg2 can either use an external IP address in resolv.conf, or use a local resolver such as unwind.

Note: You may have errors using 127.0.0.1 (localhost) for your caching nameserver because of another routing table.

Next, we configure NAT. NAT is one method to allow packets coming from wg2 get routed properly to the public Internet. On machine wg1, we add this line to /etc/pf.conf?:

match out on egress from (wg0:network) to any nat-to (egress:0)
# pfctl -f /etc/pf.conf

Finally, make sure to update the sysctls:

wg1# sysctl net.inet.ip.forwarding=1
net.inet.ip.forwarding: 0 -> 1
wg1# cat /etc/sysctl.conf
net.inet.ip.forwarding=1