Wireguard is probably the easiest VPN to set up while on of the most secure since it requires only recent encryption methods. For clients, it is handy since it stay up even if the device's IP changes -- switching from wireless to wired as example. IPv4 and IPv6 are supported so you can get an IPV6 if your ISP doesn't offer one. Wireguard is supported natively since OpenBSD 6.8.

Wireguard official website

Many software for varous platforms are availables (android, MacOS...) si it's even more handy.

It might be the best choice if you want to self-host a VPN.

If you want to learn how Wireguard works, look at the whitepaper.

Setting up an exit point ("roadwarrior")

Below we describe the following structure:

Understand that route's changes are for OpenBSD's clients and won't be a question with other OS clients.

In this example, IPs inside the VPN are in subnet :

Here's how it will look like :

    |   server    | wg0: port 4545
    |             |---------------+
    +-------------+               |
           | Public IP            |
           |            |
           |                      |
           |                      |
    /############\                |WireGuard
    |  Internet  |                |VPN
    \############/                |
           |                      |
           |                      |
           |rdomain 1             |
    +-------------+               |
    |   client    |---------------+
    +-------------+ wg0:
                    rdomain 0 (default)

By default, traffic goes through unless you explicitly ask to use another route (ie : "route -T1 exec ping openbsd.org")

VPN is set up by creating wgN interfaces, where "N" is a number from 0 to 9 as example. Such interface is created by filling a file "/etc/hostname.wgN".

Server will listen on port 4545 UDP. Any other port can be used, just check it isn't already reserved in "/etc/services".

Create keys

Use the following to create a key :

openssl rand -base64 32

It returns as example : "uA1ggvRv66QslZ0ygorWvcLVTxzFauffqMigXTrmLVY="

Once an interface receive a private key, you can retrieve the associated public key with ifconfig :

# ifconfig wgN

On the server

Create a key :

# openssl rand -base64 32

Create wg0 interface with the previous private key :

# ifconfig wg0 create wgkey r8uSGD6vyycE5n5/atU9/NX9JQPo4SJryNGpjbQG+rA= wgport 4545

Now get the matching public key :

# ifconfig wg0
wg0: flags=8082<BROADCAST,NOARP,MULTICAST> mtu 1420
        index 5 priority 0 llprio 3
        wgport 4545
        wgpubkey x9VXlh4AMa2YRjTMRVE39pQRsFHRJHUYrATL6vkqFmU=
        groups: wg

The line starting with "wgpubkey" indicates the interface's public key. You'll need it for clients so they can authentify the server, so write it down.

Of course, take note of server's private key : we'll write it later in a file to automate interface creation.

On a client

We do pretty much the same : create a private key and set up a wg interface without specifying a port:

# openssl rand -base64 32
# ifconfig wg0 create wgkey q/7uIx6wBIRUIdxOi5D6OWEQRVUt2AXhMj7j29W/s3s=
# ifconfig wg0 |grep wgpubkey
    wgpubkey V3pCAhxnRl0QEL8luB9D4EvTVxGT7QGDDCZ3O26kY3A=

Once again, write down keys.

Redirecting traffic through server

Here, we want the server to be a king of relay between the client and the rest of the world.

You have to redirect IP forwarding on server :

# sysctl net.inet.ip.forwarding=1

Add the following line in "/etc/sysctl.conf" so changes are applied at reboot:


For IPv6 :


Then, add a nat rule in "/etc/pf.conf" :

# open 4545 UDP
pass in proto udp from any to any port 4545 keep state
# What's from VPN (wg0) is NATted to public servers iface
# serveur
match out on egress from (wg0:network) to any nat-to (egress)
pass on egress from (wg0:network) to any
pass in on wg0

Reload pf 😉

Dig the tunnel

Now we've got all the material to authenticate clients and server, we can dig up the VPN. To do so, we'll indicate public keys on each devices and which IP are allowrd to use the tunnel.

To make things easier, we'll edit "/etc/hostname.wg0" files now. When rebooting, our configuration will remain.

Pay attention to keys, they are the same we got above. 😉

On the server :

"/etc/hostname.wg0" :

wgkey r8uSGD6vyycE5n5/atU9/NX9JQPo4SJryNGpjbQG+rA=
wgport 4545
wgpeer V3pCAhxnRl0QEL8luB9D4EvTVxGT7QGDDCZ3O26kY3A= wgaip

You can add as many "wgpeer" line as you want. However, each client must have its own IP :

wgpeer V3pCAhxnRl0QEL8luB9D4EvTVxGT7QGDDCZ3O26kY3A= wgaip
wgpeer m7K/gfmMPYRJx1IOP01zYrNbEuMnnZ29xN4OBgRoRXo= wgaip
wgpeer qnuq5MgezCDHXsYYGmrcegPCNcJvz9EOIG3XyHp1DBk= wgaip

On client :

Here you must specify where the client can find the server ("wgendpoint") and set default routes so traffic goes through the tunnel.

wgkey q/7uIx6wBIRUIdxOi5D6OWEQRVUt2AXhMj7j29W/s3s=
wgpeer x9VXlh4AMa2YRjTMRVE39pQRsFHRJHUYrATL6vkqFmU= wgendpoint athome.tld 4545 wgaip
wgrtable 1
!route add -net default

Dig the tunnel on client and server with :

# sh /etc/netstart wg0

Edit client's interface used to reach the internet so it uses routing table n°1. As example in "/etc/hostname.em0":

rdomain 1

You can now check client's IP : it's the same as the server's.

Configure clients using other OSes

Wiregard supported OS

F-droid (android)

Below is the minimal requirements to set up a client :

Interface :

Peer :


This page is heavily inspired from :

Thank you very much to Solène Rapenne who had the brilliant idea to use "rdomain".