WireGuard Logo

Virtual Private Network

WireGuard is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPSec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances.


As of this writing (Dec. 2017) the WireGuard code ..

  • is pre-release software.

  • has to be considered as experimental and not yet complete.

  • has not undergone proper degrees of security auditing.

  • is still subject to change.

  • may contain security vulnerabilities which would not be eligible for CVEs.

Usage Scenario

Several of our internal services have either no built-in support for encrypted communications (Redis) or its hard to get it right (e.g. MariaDB, Memcached).

Others may provide additional features or caches or APIs (e.g. PowerDNS REST API, Postfix lookup tables, status queries) which are meant to be used on the same machine or inside a local network.

With the WireGuard VPN we can let them talk to each other across the globe without disclosing any data to outsiders.

Server-1                     Server-2
--------                     --------
public IP <--- Internet ---> public IP
    |                            |
    |                            |
WireGuard                     WireGuard
    |                            |
    |                            |
private IP <----- VPN -----> private IP
    |                            |
    |                            |
 MariaDB                      MariaDB
 Redis                        Redis
 Postfix                      Postfix
 Rspamd                       Rspamd

In the following sections we will build a Virtual Private Network with the following hosts:

Domain Name

IPv4 Address

IPv6 Address
















After the VPN is setup, they will be reachable from inside the VPN as follows:

Domain Name

IPv4 Address

IPv6 Address









Please see Network Design for information.

WireGuard Port Number

We need a UDP port number where our VPN hosts will listen for incoming connections.

WireGuard does not recommend a specific port number, like most IP network services do.

The port numbers from 49,152 to 65,535 have been reserved by IANA for dynamic and/or private use. To select a random number from this range:

$ shuf -i 49152-65535 -n 1

Although IANA is responsible for official port numbers, many unofficial uses of both well- known and registered port numbers occur in practice.

To avoid any potential conflicts, I usually check if a port number is already known to be uses by any software or services. The Speed Guide Ports Database is a good resource for this:


Wikipedia also maintains a list.

Software Installation

On each host:

$ sudo add-apt-repository ppa:wireguard/wireguard
$ sudo apt update
$ sudo apt install wireguard-dkms wireguard-tools
$ sudo touch /etc/wireguard/.reload-module-on-update

Key Generation

On each host.

Create a private key:

$ cd /etc/wireguard
$ umask 077
$ wg genkey > privatekey

Create the public key:

$ wg pubkey < privatekey > publickey

Create public and private keys:

$ wg genkey | tee privatekey | wg pubkey > publickey


Create a fresh configuration file /etc/wireguard/wg0.conf on each host:

The file format is derived from the old windows INI files and fairly simple (at least for a VPN).


Each configuration has one section called [Interface] where the server-part is defined.

It contains the private key of the local WireGuard server, the UDP port it should listen for incoming connections and its own VPN IP addresses.

For the Dolores host this looks like the following:

# WireGuard Configuration for dolores.example.net
# Hetzner, San Francisco

PrivateKey = qNoBKylRuEUtBuTANIS6rSZoCqG8cFYzEWeS7fx63Vk=
ListenPort = 55867
Address =, fdc1:d89e:b128:6a04::7de4/64

For Maeve:

; WireGuard Configuration for maeve.example.net
; Rackspace, London

PrivateKey = cIsZsNNMJmHSjsi/VBmoJk3DHN+mOG6OY6otkKOqQm4=
ListenPort = 55867
Address =, fdc1:d89e:b128:6a04::2615/64


; WireGuard Configuration for bernard.example.net
; Rollnet, Phoenix

PrivateKey = gAjbms8705vj8Yg1p7EDKi6ZiRonQQTmzyFjaDey+Gw=
ListenPort = 55867
Address =, fdc1:d89e:b128:6a04::41c5/64


; WireGuard Configuration for charlotte.example.net
; Home, Frankfurt

PrivateKey = qNoBKylRuEUtBuTANIS6rSZoCqG8cFYzEWeS7fx63Vk=
ListenPort = 55867
Address =


The [Peer] sections define the other members of the VPN network. You can add as many as needed.

They contain their public key, which must match the peers private key in its [Interface] section.

The hostname (or IP address) and port set as Endpoint is optional:

  • If an Endpoint is defined, the local system is capable of connecting to the remote peer on its own.

  • If the peer don’t has an Endpoint defined, the local system will just wait for an incoming connection from that peer. This is useful for peers with dynamic IP addresses and for road-warriors who need to connect from anywhere.

Note that any incoming connection is first authenticated against one of the public keys. If the connection is not from a verified peer, the incoming packets are just silently ignored. Since connections from hosts who don’t own a matching private key are not answered at all, a WireGuard VPN does not only provide encrypted communication, it also remains hidden from outsiders. Except for its members, no one knows that it exists.

Once you have figured out the peer section of all your WireGuard hosts, you just copy and paste them to the configuration file of every other host participating in your VPN network.

So the [Peer] section are nearly the same on every system, with the exception that the servers should not have peer definitions that point to themselves. We want to avoid a peer trying to connect with himself.

For the Dolores host this looks like the following:

# dolores.example.net, Hetzner, San Francisco
PublicKey = xFXzNIDQ5NJkY0Pgg5hG1fZg0RAD51nnu5MMBbhlpCg=
Endpoint = dolores.example.net:55867
# Allow dolores.vpn.example.net
AllowedIPs =, fdc1:d89e:b128:6a04::7de4/128

For Maeve:

# maeve.example.net, Rackspace, London
PublicKey = Bj7G2pqXZRjrcBTwOWDrkjcy3PzhhJd3cX8QvBTaRDI=
Endpoint = maeve.example.net:55867
# Allow maeve.vpn.example.net
AllowedIPs =, fdc1:d89e:b128:6a04::961/128


# bernard.example.net, Rollernet, Phoenix
PublicKey = 5SAd89dXTesrxFZpNaRvwL/M11WjuevHJH/7Cv5LI3c=
Endpoint = bernard.example.net:55867
# Allow bernard.vpn.example.net
AllowedIPs =, fdc1:d89e:b128:6a04::3354/128

Charlotte and Teddy have their own subnets (home and office) behind them. If these peers are capable of routing packets, we can access these private networks trough the VPN.


# charlotte.example.net, Home, Frankfurt
PublicKey = xFXzNIDQ5NJkY0Pgg5hG1fZg0RAD51nnu5MMBbhlpCg=
Endpoint = charlotte.example.net:55867
# Allow charlotte.vpn.example.net
AllowedIPs =, fdc1:d89e:b128:6a04::29ab/128
# Allow home.example.net
AllowedIPs =, fdc1:d89e:b128:13a6::/64


# teddy.example.net, Office, Frankfurt
PublicKey =
Endpoint = teddy.example.net:55867
# Allow teddy.vpn.example.net
AllowedIPs =, fdc1:d89e:b128:6a04::/128
# Allow office.example.net
AllowedIPs =, fdc1:d89e:b128:2615::/64

Open Up the Firewall

If there is a Firewall, you need to open it up for UDP connections on our chosen WireGuard port. Do this on all hosts.

Allow Incoming WireGuard Connections:

$ sudo ufw allow 55867/udp

After connection, verification and encryption the VPN is set up, all communication to and from the VPN are then coming from the automatically created new virtual network interface wg0.

To enable unrestricted network access from the VPN:

$ sudo ufw allow in on wg0

Of course you are free to define you own more restrictive policy, depending on how much you trust your peers.

Starting the VPN

Systemd takes care of the rest, with the help of the wg-quick script:

sudo systemctl start wg-quick@wg0