Back to blog

Self-Host Your Own VPN

WireGuard is a work of art. This post shows you best practices and how to set up a reliable VPN solution using OpenBSD and WireGuard.

Post

Introduction

With the ever increasing surveillance of our lives from ISPs, governments, and corporations, the privacy-conscious person may think, "How can I protect myself, my personal data, and my privacy?". That is a valid question, and we will explore ways to make it just a little harder for those prying eyes to get access to your precious PII. Remember, you may have nothing to hide, but you have everything to protect.

Threat Model

Who/what are you hiding from?

The first thing you want to do is a threat assessment. You may have to ask yourself, "Who am I protecting myself from?". Are you a journalist in an oppressive regime hiding from persecution? Are you an activist concerned about bad actors tracking your online activity? Or are you just a regular person like me seeking peace-of-mind knowing your privacy, and more importantly your data is secure? Hiding from state-actors is out of scope for this tutorial. I am just showing how easy it is to self-host your own VPN solution.

Installation

Prerequisites

To follow along you will need an OpenBSD VPS, a client device, and basic familiarity with the command line. Any VPS provider that supports OpenBSD will work. I use netcup.

Installing OpenBSD is out of scope for this tutorial, and will be covered in another post. This tutorial assumes you have already installed OpenBSD on your VPS.

First, we need to ensure forwarding is enabled on our VPN gateway. Enable IP forwarding with the following commands:

# sysctl net.inet.ip.forwarding=1
# sysctl net.inet6.ip6.forwarding=1

To make this persistent across reboots append to /etc/sysctl.conf.

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

Second, we need a text editor. We will use Nano for simplicity.

# pkg_add nano

Installing WireGuard

OpenBSD has WireGuard baked into the kernel since version 6.8.

I've used wireguard-tools in the past but I now consider it obsolete. We will do things the OpenBSD way. No external dependencies required.

Peer Configuration

"Server" Configuration

Now we will configure our OpenBSD VPS to act as the WireGuard gateway.

Generating Keys

To generate our private keys we will use openssl which comes preinstalled on OpenBSD.

openssl rand -base64 32 - This command will be used to generate our keys.

Private key

# openssl rand -base64 32 ↵
PRIVATE-KEY-SHOWN-HERE

Preshared key

# openssl rand -base64 32 ↵
PRESHARED-KEY-SHOWN-HERE
NEVER share your private or preshared keys! Keep them secret, keep them safe.

Now that we have our private keys generated, we can carry on with actually configuring our wg0 interface. OpenBSD uses it's hostname.if format for configuring the interface. If you've set up WireGuard on Linux before you're probably used to using .conf files that live in /etc/wireguard. I will show you how to convert those to hostname.if format.

# nano /etc/hostname.wg0
wgkey PRIVATE-KEY-HERE
wgport 51820
inet 192.168.10.1 255.255.255.0 NONE
up

Save and close the file.

Start interface so we can get the public key.
This should throw an error, this is normal.

# sh /etc/netstart wg0 ↵
# ifconfig wg0 | grep wgpubkey ↵
wgpubkey PUBLIC-KEY-SHOWN-HERE

"Client" Configuration

Time to configure our client device. I will use my Arch Linux laptop as the client. We will generate our keypair for our client using the tools included in wireguard-tools. This may differ depending on your distro. Refer to your distribution documentation as covering everything is out of scope for this tutorial. The ArchWiki is a good resource.

We will generate our private-public keypair with a one-liner.

/etc/wireguard# wg genkey | (umask 0077 && tee private.key) | wg pubkey > public.key

Now we have our private-public keypair stored in /etc/wireguard we can create our wg0.conf file.

# nano /etc/wireguard/wg0.conf
[Interface]
# Client Identity
Address = 192.168.10.2/32
PrivateKey = CLIENT-PRIVATE-KEY

[Peer]
# The Gateway
PublicKey = SERVER-PUBLIC-KEY
PresharedKey = PRESHARED-KEY
Endpoint = VPS-PUBLIC-IP:51820

# Route ALL traffic over VPN tunnel
AllowedIPs = 0.0.0.0/0

# Keep connection alive behind NAT
PersistentKeepalive = 25

Remember our /etc/hostname.wg0 from earlier? We now need to go back and add our client as a peer. We will do this now.

wgkey PRIVATE-KEY-HERE
wgport 51820
inet 192.168.10.1 255.255.255.0 NONE
wgpeer CLIENT-PUBLIC-KEY wgpsk PRESHARED-KEY wgaip 192.168.10.2/32
up

Save and close the file.

# restart the interface
sh /etc/netstart wg0 ↵

PF Rules

Now, back on our VPS we need to configure our pf firewall to allow our client devices to connect to the tunnel. We will also set up NAT so our VPN can forward our encrypted traffic out to the Internet. We will do this with a very simple ruleset.

Open and edit the firewall configuration file at /etc/pf.conf to add the following (after the skip lines).

# nano /etc/pf.conf

Paste the following to allow connections and NAT traffic from the wg0 interface.

pass in on wg0
pass in on egress proto udp from any to (egress) port 51820
pass out quick on egress from (wg0:network) nat-to (vio0:0)
vio0 is the public-facing interface on my VPS. It may be different for you so update the ruleset to match accordingly.

Save and close the file.

Reload the firewall to update it with our new ruleset.

# pfctl -f /etc/pf.conf

Bringing it all together

At this point you should have a fully functional WireGuard VPN. Let's bring the client up and test the connection.

# wg-quick up wg0

Verify the tunnel is up and traffic is flowing.

# wg show

You should see your peer listed with a recent handshake timestamp. If you don't, double check your keys, pf rules, and that port 51820 is reachable on your VPS. An IP leak test at ipleak.net will confirm your traffic is exiting through your VPS and not leaking to your ISP.

Wrapping Up

Self-hosting a VPN is one of the most practical things you can do for your privacy. You own the server, you own the keys, and nobody is selling your browsing data to advertisers. WireGuard makes it fast and simple, and OpenBSD makes it secure. That's a combination I can get behind.

If you run into issues, man ifconfig, man pf.conf, and man wg are your best friends. As always with OpenBSD, the answer is usually in the manual.

Sources

  1. wg (4) — OpenBSD manual pages
  2. hostname.if (5) — OpenBSD manual pages
  3. pf.conf (5) — OpenBSD manual pages
  4. WireGuard Quick Start — wireguard.com
  5. WireGuard VPN Server — ArchWiki