Wireguard

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 10.0.0.0/24 subnet :

Here's how it will look like :

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

By default, traffic goes through 10.0.0.2 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
r8uSGD6vyycE5n5/atU9/NX9JQPo4SJryNGpjbQG+rA=

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
    q/7uIx6wBIRUIdxOi5D6OWEQRVUt2AXhMj7j29W/s3s=
# 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:

net.inet.ip.forwarding=1

For IPv6 :

net.inet6.ip6.forwarding=1

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" :

inet 10.0.0.1/24
wgkey r8uSGD6vyycE5n5/atU9/NX9JQPo4SJryNGpjbQG+rA=
wgport 4545
wgpeer V3pCAhxnRl0QEL8luB9D4EvTVxGT7QGDDCZ3O26kY3A= wgaip 10.0.0.2/32
up

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

wgpeer V3pCAhxnRl0QEL8luB9D4EvTVxGT7QGDDCZ3O26kY3A= wgaip 10.0.0.2/32
wgpeer m7K/gfmMPYRJx1IOP01zYrNbEuMnnZ29xN4OBgRoRXo= wgaip 10.0.0.3/32
wgpeer qnuq5MgezCDHXsYYGmrcegPCNcJvz9EOIG3XyHp1DBk= wgaip 10.0.0.4/32

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 0.0.0.0/0
inet 10.0.0.2/24
wgrtable 1
!route add -net default 10.0.0.1
up

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":

dhcp
rdomain 1
up

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 :

Ressources

This page is heavily inspired from :

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