Spinning Up WireGuard on OpenBSD


After the most serendipitous re-discovery of the old Marathon first person shooter series (now released as freeware and available in ports on OpenBSD) from the 1990s, I got an idea to play the games over the internet with a friend from Mastodon. In order to make this happen, I need to simulate a local area network over the internet which means a VPN tunnel of sorts. Since I do not know exactly how the networking portion of the Marathon series works, I am going to start with another little gem that I discovered called WireGuard. The beauty of WireGuard is in its elegance, simplicity, and security. It’s not going to take a, pardon the expression, marathon effort, to get it going. If it turns out that the networking stack of Marathon won’t really work well with TCP/IP, then I am going to have to consider Ethernet over IP using etherip(4). But I digress, this is really about getting WireGuard going.

The first step is to set up the networking environment. For the purposes of examples, I have substituted 192.0.2.1 for the public IP address in the configuration. I am using 100.64.1.0 subnet for the private addresses. Since this is really going to be a simple point to point tunnel, it won’t need to be NAT’d and routed out to the internet at large. First off, on the server end, we enable IP forwarding.

sysctl net.inet.ip.forwarding=1
echo "net.inet.ip.forwarding=1" >> /etc/sysctl.conf

Now we need to create the interface definition file. We are going to use tun0 on both the client and server. For now, we are simply setting up the server side. Create /etc/hostname.tun0.

!ifconfig tun0 inet 100.64.1.1 100.64.1.2 netmask 255.255.255.252 up

Now bring up the interface with a sh /etc/netstart tun0. The tunnel will still be effectively down but at least the interface has been defined and is ready for WireGuard. The next step is to add the necessary packages, wireguard-tools and wireguard-go.

pkg_add wireguard-go wireguard-tools

Once the packages have been downloaded and installed, we need to create a location for the configuration files and the keys. You can pretty much do anything that you want in this regard. I placed mine in /etc/wg. Since some really sensitive data is being stored in this directory, I recommend restricting access to root and members of the wheel group. We are going to generate both the server and client keys here.

mkdir /etc/wg
chmod 0750 /etc/wg
cd /etc/wg
wg genkey > server.key
chmod 0600 server.key
wg pubkey < server.key > server.pub
wg genkey > client.key
chmod 0600 client.key
wg pubkey < client.key > client.pub

You will need to find a secure way to get the client configuation to your machine. It’s not necessary to copy the actual key files because the keys live in the configuration file but make certain to lock down the configuration files to 0640 at the minimum. Below is a sample configuration file for the server and client, /etc/wg.conf. Be sure to change it to suit your environment. You will need to open a UDP port for WireGuard in pf or your firewall. I use 8000.

#Server
[Interface]
PrivateKey=<Server_Private_Key>
ListenPort=8000

[Peer]
PublicKey=<Client_Public_Key>
AllowedIPs=100.64.1.2/32
PersistentKeepalive=30
#Client
[Interface]
PrivateKey=<Client_Private_Key>

[Peer]
PublicKey=<Server_Public_Key>
AllowedIPs=100.64.1.1/32
EndPoint=server.example.com
PersistentKeepalive=30

Now let’s start WireGuard:

rcctl enable wireguard_go
rcctl start wireguard_go
wg setconf tun0 /etc/wg/wg.conf

It’s really that easy! Once you’ve verified that WireGuard is running and that you see a port listening on 8000 (hint: netstat -ln -finet), it’s time to repeat the steps above for installing and enabling wireguard. On the client machine, again, I recommend storing your configuration in /etc/wg/wg.conf and locking down the directory and file in it to 0640 at the minimum. Once this is done, you can bring up WireGuard on the client and test. If all goes well, you should see wonderful, beautiful pings.

PING 100.64.1.1 (100.64.1.1): 56 data bytes
64 bytes from 100.64.1.1: icmp_seq=0 ttl=255 time=37.519 ms
64 bytes from 100.64.1.1: icmp_seq=1 ttl=255 time=20.652 ms
64 bytes from 100.64.1.1: icmp_seq=2 ttl=255 time=16.106 ms
64 bytes from 100.64.1.1: icmp_seq=3 ttl=255 time=64.658 ms

--- 100.64.1.1 ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 16.106/34.734/64.658/19.030 ms

This is a very purpose-built configuration. It works between two endpoints and no further. If you’re looking for a more general-use approach, please read this article. Jasper, an OpenBSD developer, maintains the wireguard-go and wireguard-tools ports. His write-up is detailed and excellent!


See also