Connect FreeBSD to OpenBSD using WireGuard
622 words, 3 minutes
I have deployed a monitoring VPS somewhere on someone else’s computer and I want all my other servers to send it their metrics and logs and alerts etc. But in order to cruise the Wild Wild Web in a safer way, I connect all those nodes using WireGuard.
Recently I deployed a FreeBSD instance in such a way that it has to initiate the connection to the OpenBSD monitoring server using WireGuard. That’s what those notes are about.
Initialization on the OpenBSD node
On the OpenBSD server, follow the WireGuard pseudo-device manual
page
to create a wg interface and write
down its public key. I use OpenBSD 7.9 but the configuration process
hasn’t change in releases.
# openssl rand -base64 32
change_me-openbsd-private-key=
# cat > /etc/hostname.wg0
wgkey change_me-openbsd-private-key= wgport 10101
inet 192.0.2.10/24
inet6 2001:db8::10 64
up
# sh /etc/netstart wg0
# ifconfig wg0 | grep wgpubkey
wgpubkey change_me-openbsd-public-key=
Configuration on the FreeBSD node
I use FreeBSD 14.4, but FreeBSD 15.x may not be that different. The WireGuard manual page is worth reading to get of full overview on the subject.
As I understood it, the wg module and a mix of ifconfig and wg
spells are enough to have it working. There are also wireguard tool
packages that can be installed and used. But as this machine will be
client only, I’ll stick with the default shipped-in tools.
# man if_wg
# echo 'if_wg_load="YES"' >> /boot/loader.conf
# kldload if_wg
# ifconfig wg0 create
# wg genkey | wg set wg0 listen-port 10101 private-key /dev/stdin
# ifconfig wg0 inet 192.0.2.76/24
# ifconfig wg0 inet6 '2001:db8::76/64'
# ifconfig wg0
Now that the interface has been created, the connection to the remote OpenBSD server can be initiated. Note that it won’t be established until we complete the configuration on the remote end.
# wg genpsk | wg set wg0 peer 'change_me-openbsd-public-key=' \
preshared-key /dev/stdin endpoint openbsd.example.com:10101 \
allowed-ips 192.0.2.10/32,2001:db8::10/128
A private key and a preshared key have been generated on the fly during
the FreeBSD initialisation phase. Both are required to configure FreeBSD
on the next reboot. As I’m not using the wireguard ports stuff, I’ll be
keeping those information in /etc.
The manual page says that loading keys is only possible using files:
Both private-key and preshared-key must be files, because command line arguments are not considered private.
The public and preshared keys are required on the OpenBSD side to establish the connection.
# wg show wg0 private-key > /etc/wg0_private.key
# wg show wg0 preshared-keys | cut -f 2 > /etc/wg0_preshared.key
# chmod 0400 /etc/wg0_private.key /etc/wg0_preshared.key
# wg show wg0 public-key
change_me-freebsd-public-key=
# wg show wg0 preshared-keys | cut -f 2
change_me-preshared-key=
To configure the WireGuard interface on FreeBSD, I use a mix of
rc.conf configuration and wg commands launched from rc.local.
# cat << EOF >> /etc/rc.conf
cloned_interfaces="wg0"
ifconfig_wg0="inet 192.0.2.76/24"
ifconfig_wg0_ipv6="inet6 2001:db8::76/64"
EOF
# cat << EOF >> /etc/rc.local
echo -n "WireGuard "
wg set wg0 listen-port 10101 private-key /etc/wg0_private.key
wg set wg0 peer 'change_me-openbsd-public-key=' preshared-key /etc/wg0_preshared.key \
endpoint openbsd.example.com:10101 allowed-ips 192.0.2.10/32,2001:db8::10/128
EOF
Everything is now configured on the FreeBSD side. But the servers won’t see each other until the configuration is completed on the OpenBSD side.
Configuration on the OpenBSD node
The FreeBSD public and preshared keys are referenced on the OpenBSD side. Then, the configuration is applied so that the connection can be established.
# cat >> /etc/hostname.wg0
wgpeer change_me-freebsd-public-key= \
wgdescr freebsd \
wgaip 192.0.2.76/32 \
wgaip 2001:db8::76/64 \
wgendpoint freebsd.example.com 10101 \
wgpsk change_me-preshared-key=
# sh /etc/netstart wg0
Ping the peer from each node to verify that the connection is established.
Time to reboot the FreeBSD host and ensure everything connects properly.
So far, sending collectd metrics every 10 seconds to a remote
VictoriaMetrics database works like a charm.