An initial and basic set up of Wireguard on OpenBSD
One great thing about OpenBSD is that it comes with many services included. Wireguard is one of them, meaning it can be set up without installing anything.
Here is my initial and quite basic setup of Wireguard on OpenBSD without using anything other than what is included in the base system. I already feel I will have to get back to this and improve the setup for maintainability, but for a first setup it works and that is good enough right now.
I normally use doas to execute commands as root, but for this setup it’s easier to just su to root and execute them directly.
First off I set a strict umask to make sure everything is created with permissions for root only, then create the directory that will hold the keys and configuration, and finally create our private key as well as a preshared key for our first peer:
umask 077
mkdir /etc/wireguard
openssl rand -base64 32 > /etc/wireguard/wg0.private
openssl rand -base64 32 > /etc/wireguard/peer-a-wg0.preshared
Then I create the /etc/hostname.wg0
file which creates the interface, sets
up the listening port, adds peers and adds our IP for this interface and
network:
# Set our private key
wgkey `cat /etc/wireguard/$1.private`
# Set the listen port
wgport 51820
# Add peers
!/etc/wireguard/add-peers.sh $1
# Add our IP
inet 10.0.0.1 255.255.255.0
The add-peers script looks like this:
#!/bin/sh
INTERFACE=$1
PEER="peer-a"
PUBKEY=$(cat /etc/wireguard/${PEER}-${INTERFACE}.pubkey)
PRESHARED=$(cat /etc/wireguard/${PEER}-${INTERFACE}.preshared)
ifconfig ${INTERFACE} wgpeer ${PUBKEY} \
wgdescr ${PEER} \
wgpsk ${PRESHARED} \
wgendpoint peerIP peerPORT \
wgaip "10.0.0.10/32" \
This is very simple and probably a little naive. If I were to add another peer I would have to duplicate everything from PEER and down, which sounds like something a loop of some kind should solve.
For this to work I will also need to get the public key from the peer and put it in its respective file, as well as giving them my public key and the preshared key that is unique to our connection.
I am using preshared keys to add another layer of symmetric-key encryption to the connection, to make it more secure against future quantum computers.
Given this preshared key needs to be kept secret, how do I transport it safely from my server to the peer or vice versa? If someone is recording my internet traffic and storing it in order to crack current encryption when quantum computers become powerful enough, what then?
It seems OpenSSH is ahead of the curve here and implemented a fix for this already in April 2022 with the release of version 9.0:
* ssh(1), sshd(8): use the hybrid Streamlined NTRU Prime + x25519 key
exchange method by default ("sntrup761x25519-sha512@openssh.com").
The NTRU algorithm is believed to resist attacks enabled by future
quantum computers and is paired with the X25519 ECDH key exchange
(the previous default) as a backstop against any weaknesses in
NTRU Prime that may be discovered in the future. The combination
ensures that the hybrid exchange offers at least as good security
as the status quo.
We are making this change now (i.e. ahead of cryptographically-
relevant quantum computers) to prevent "capture now, decrypt
later" attacks where an adversary who can record and store SSH
session ciphertext would be able to decrypt it once a sufficiently
advanced quantum computer is available.
I’ve made changes to my ssh config so only sntrup (or now in 2025, mlkem) is used, so it should be safe to transfer the preshared keys with ssh. I’ll write about that later.
Now then to start my interface: sh /etc/netstart wg0
When the same has been done on the peer, I can try to connect:
ping 10.0.0.10
PING 10.0.0.10 (10.0.0.10): 56 data bytes
64 bytes from 10.0.0.10: icmp_seq=0 ttl=64 time=12.413 ms
64 bytes from 10.0.0.10: icmp_seq=1 ttl=64 time=12.507 ms
64 bytes from 10.0.0.10: icmp_seq=2 ttl=64 time=12.304 ms
64 bytes from 10.0.0.10: icmp_seq=3 ttl=64 time=12.294 ms
64 bytes from 10.0.0.10: icmp_seq=4 ttl=64 time=13.072 ms
64 bytes from 10.0.0.10: icmp_seq=5 ttl=64 time=12.660 ms
^C
--- 10.0.0.10 ping statistics ---
6 packets transmitted, 6 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 12.294/12.542/13.072/0.268 ms
Success!
ifconfig wg0
will give more information when run as root:
wg0: flags=80c3<UP,BROADCAST,RUNNING,NOARP,MULTICAST> mtu 1420
index 9 priority 0 llprio 3
wgport 51820
wgpubkey <redacted>
wgpeer <redacted>
wgdescr: peer-a
wgpsk (present)
wgendpoint <peerIP> <peerPORT>
tx: 11880, rx: 10184
last handshake: 23 seconds ago
wgaip 10.0.0.10/32
groups: wg
inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255