OpenBSD WireGuard VPN Server
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