Josh's Webpage

OpenBSD WireGuard VPN Server

OpenBSD WireGuard WireGuard

OpenBSD is a Unix-like operating system known for its strong security, code correctness, and proactive measures to mitigate vulnerabilities. It's considered one of the most secure operating systems available due to it's small code-base and strong default security configurations compared to other distributions such as Debian and Fedora.

WireGuard is a VPN protocol released in 2015 that has gained traction due to its faster performance compared to older VPN protocols such as IPsec and OpenVPN. Similar to OpenBSD, WireGuard has a small attack surface due to its smaller code base compared to other VPN protocols. As of writing this, WireGuard has roughly 4,000 lines of code compared to the 400,000 lines of code in IPSec and 70,000 lines of code in OpenVPN.

When used together, WireGuard and OpenBSD form a very solid and secure VPN server, great for accessing remote clients securely over SSH. The system's small footprint allows it to use less than 40MB of RAM even with active VPN and SSH sessions, making it ideal for running on less powerful hardware.

Due to low system overhead it requires to run, I'd recommend getting the cheapest system you can with IPv4 routing (depending on how much bandwidth you need) since OpenBSD and WireGuard are not resource intensive at all. I personally use Vultr for hosting most of my VPS and have been for over a year now and never had any issues with them service wise, even while they were doing maintenance or upgrading servers. Vultr also has a great referral program where new users can earn $100 in credits for the first year. Referral link: https://www.vultr.com/?ref=9600105-8H

Prior to installing, I highly recommend reading the manual pages for OpenBSD to learn more about how the system functions and command usage if you aren't familiar with the operating system. Everything is very well documented on their website: https://man.openbsd.org

Server Setup & Configuration:

After installing OpenBSD on your cloud based server and hardening SSH connectivity, execute the following commands to ensure that the system and packages are up to date. Note: It is important to run the following commands in the sequence shown here:

root@openbsd# syspatch
root@openbsd# pkg_add -Uu
root@openbsd# reboot

syspatch is used to apply binary patches to the system ensuring that the base system's security updates and patches are applied.
pkg_add -Uu updates all installed packages to their latest versions.
reboot to ensure that all changes are applied and to reload the kernel.

Install the necessary software packages that will be used for key generation, routing configuration, and text editing:

root@openbsd# pkg_add wireguard-tools vim

Enable IPv4 and IPv6 forwarding if you plan to use IPv6:

root@openbsd# sysctl net.inet.ip.forwarding=1
root@openbsd# sysctl net.inet6.ip.forwarding=1

Configure IP forwarding to be automatically enabled on system boot:

root@openbsd# echo "net.inet.ip.forwarding=1" >> /etc/sysctl.conf
root@openbsd# echo "net.inet6.ip6.forwarding=1" >> /etc/sysctl.conf

Make a directory for WireGuard and navigate into the newly created directory:

root@openbsd# mkdir -p /etc/wireguard && cd /etc/wireguard

To securely connect a client and a server using WireGuard, it is essential to generate a cryptographic key pair. These keys facilitate client authentication and the encryption-decryption process for data transmission.

The private and public key pairs are primarily for authentication purposes. When a client tries to establish a connection with the server, it authenticates itself by presenting its public key, which the server will be configured to recognize as trusted. The server also authenticates itself to the client by providing its public key. This mutual authentication confirms the identities of both parties, ensuring that communications are between legitimate endpoints.

After the authentication phase, WireGuard establishes an encrypted communication channel between the client and server. However, rather than using the initial public and private keys directly for encrypting all the data, WireGuard uses these keys to generate temporary session-specific keys. These session keys are dynamically generated for each connection session, enabling the encryption and decryption of data. The use of session keys means that even if a session key were compromised, it would not affect the security of past or future sessions, nor compromise the private keys used for authentication.

Generate the private key using WireGuard's key generation command and derive a public key from the private key that was created:

root@openbsd# wg genkey > private.key
root@openbsd# wg pubkey < private.key > public.key

Create a configuration file for the WireGuard VPN interface:

root@openbsd# touch wg0.conf

Open wg0.conf using a text editor and add the following:

/etc/wireguard/wg0.conf
# Server configuration
[Interface]
PrivateKey = <SERVER-PRIVATE-KEY>
ListenPort = <SERVER-LISTEN-PORT>

# Client configuration
[Peer]
PublicKey = <CLIENT-PUBLIC-KEY>
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

Change file permissions for wg0.conf and private.key so that only the root user can access them since they both contain the private key:

root@openbsd# chmod 600 wg0.conf private.key

Use ifconfig to verify the primary interface name, in most cloud instances of OpenBSD it is vio0. If it is different keep note of the interface name for the proceeding steps.

Open the configuration file for OpenBSD's Packet Filter firewall:

root@openbsd# vim /etc/pf.conf

Add the following three rules to the firewall configuration file:

/etc/pf.conf
# Allow traffic on the WireGuard interface
pass in on wg0
# Allow incoming UDP traffic from specified listen port configured in wg0.conf
pass in inet proto udp from any to any port <SERVER-LISTEN-PORT>
# Translate outgoing traffic from wg0 to use the primary interface vio0 via NAT (change vio0 to primary interface if different)
pass out on egress inet from (wg0:network) nat-to (vio0:0)

Reload the PF firewall with the newly added rules:

root@openbsd# pfctl -f /etc/pf.conf

Open the vio0 network configuration file:

root@openbsd# vim /etc/hostname.vio0

Add the following lines to the /etc/hostname.vio0 file:

/etc/hostname.vio0
# Specify private IP address range, subnet and default gateway
inet 10.0.0.1 255.255.255.0 none
up # activates vio0 interface
# Sets config for wg0 interface to configs set in wg0.conf
!/usr/local/bin/wg setconf wg0 /etc/wireguard/wg0.conf

Client Configuration:

Now all we need to do now is to configure WireGuard on our client device, generate a key pair for client authentication, and update configuration files on the server with the our client information. The configuration steps will be perfomed on a client system running Debian but should be mostly the same for the vast majority of Linux distributions.

On the client device device install wireguard-tools:

client@debian:~$ sudo apt-get install wireguard-tools

Make a directory for WireGuard and navigate into the newly created directory:

client@debian:~$ mkdir /etc/wireguard && cd /etc/wireguard

Generate a private key using WireGuard's key generation command and derive a public key from the private key that was created:

client@debian:~$ sudo wg genkey | tee private.key | wg pubkey > public.key

Create a configuration file for the WireGuard VPN interface:

client@debian:~$ touch wg0.conf

Open wg0.conf with a text editor and add the following:

/etc/wireguard/wg0.conf
# Client configuration
[Interface]
PrivateKey = <CLIENT-PRIVATE-KEY>
Address 10.0.0.2/24 #change if using different private IP config

# Server configuration
[Peer]
PublicKey = <SERVER-PUBLIC-KEY>
Endpoint = <SERVER-PUBLIC-IP>:<PORT#>
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25 

Change file permissions for wg0.conf and private.key so that only the root user can access them since they both contain the private key:

client@debian:~$ sudo chmod 600 wg0.conf private.key

Final Steps:

Be sure to update the server's wg0.conf file with the public key of the client. Below is an example of what a completed configuration should look like for both the server and the client's wg0.conf files:

OpenBSD Server:

/etc/wireguard/wg0.conf
# Server configuration
[Interface]
PrivateKey = edWiTdis0BJDNomWkyKsTzkGHGWV8KNKoncnn8M9kDk=
ListenPort = 443
    
# Client configuration
[Peer]
PublicKey = UO24eicj2ZfkdO/u+iV1a32I43Z0FTVZu6AuEo6pbk0=
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

Debian Client:

/etc/wireguard/wg0.conf
# Client configuration
[Interface]
PrivateKey = WVtPbGvZ9jbB/yQWYXJIIgrz/g7lVISTvHU78r9V0Xg=
Address 10.0.0.2/24 #change if using different private IP config

# Server configuration
[Peer]
PublicKey = aC2gF4f/c89ya13bRmd3ATzE6ETdG+/ASlNoeez0vmI=
Endpoint = 192.0.2.0:443
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25 

After everything is configured we should be able start the VPN server with the following command:

root@openbsd# sh /etc/netstart wg0

To start a VPN connection on a client you can run:

client@debian:~$ sudo wg-quick up wg0

You can verify the VPN connection by running the following curl command which should return with the IP address of your OpenBSD VPN server:

client@debian:~$ curl ifconfig.me

To stop a VPN connection on a client you can run:

client@debian:~$ sudo wg-quick down wg0

To make things slightly more efficient I wrote a script that can be used to start and stop the VPN connection with ./wg.sh start and ./wg.sh stop. Here is a link to the source code on GitHub: wg.sh

Resources: