Wireguard management

Foreword

This document will make use of 2 terminals:

It'll be split into those 3 categories:

For shell examples, every shell block will start with # <server>, where <server> is one of those 3 choices:

Note that, if I moved into a folder I created during the guide, it'll be noted by suffixing CA/VPN/CLIENT with "in ./"

Wireguard server setup

Installation

Note that some more recent kernels are now shipping Wireguard! You only need the Wireguard tools to manage the VPN itself.

From the debian wiki, we have those steps to run to add the wireguard repositories to our cache of available packages, then to install the wireguard dependencies (wireguard will install wireguard-dkms and wireguard-tools).

Debian wiki on Wireguard

# VPN
$ echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable-wireguard.list
$ printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable
$ apt update
$ apt install wireguard

And that's all we need. Since it's a kernel plugin, it's recommended to restart your server.

Configuration

We firstly create our wireguard config folder.

# VPN
$ mkdir -p /etc/wireguard/keys
$ cd /etc/wireguard && umask 077
$ cd keys && umask 077

We then generate the public/private key pair.

# VPN in /etc/wireguard/keys
$ wg genkey | tee privatekey | wg pubkey > publickey

This creates two files:

We'll now create our wireguard peer configuration, we'll call the interface wg0.

We'll use the IP address 10.0.10.1/24 for our VPN server, every client will have another IP in the same network range (e.g. 10.0.10.2/24).

We'll also use iptables to manage our network configuration.

Create and edit a file at /etc/wireguard/wg0.conf.

[Interface]
PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens3 -j MASQUERADE
# Address is your VPN endpoint's IP
Address = 10.0.10.1/24
# ListenPort is the port which you want to open on your server, it'll be used
# by the clients to connect to your server.
ListenPort = 59523
PrivateKey = <copy/paste the private key in keys/privatekey here>

We'll load the Wireguard daemon with our configuration file to quickly test that everything's ready.

# VPN
$ wg-quick up wg0

If no error's shown, you can check that the daemon started by running wg and looking at the output.

Now, stop the WG daemon.

# VPN
$ wg-quick down wg0

If everything's working, we can configure it to start at system startup.

# VPN
$ systemctl enable wg-quick@wg0

Let's start our server for now.

# VPN
$ systemctl start wg-quick@wg0

Client management

The following steps can be repeated for each client you wish to add.

Setup

Install the wireguard-dkms and wireguard-tools for your system.

Create the folders and generate the certificates as done for the server.

# Client
$ mkdir -p /etc/wireguard/keys
$ cd /etc/wireguard && umask 077
$ cd keys && umask 077
$ wg genkey | tee privatekey | wg pubkey > publickey

Configuration file

We'll have to choose an address for this peer. For this example, I'll use 10.0.10.2/24.

We also need to decide if we'll proxy everything through our VPN or not (see comments in the config block below).

[Interface]
Address = 10.0.10.2/24
PrivateKey = <copy/paste the private key in keys/privatekey here>
# If your wireguard server hosts a DNS, like pihole, reference it here.
DNS = 10.0.10.1

[Peer]
# This is your server. Put its public key here
PublicKey = OE5Ytufsw69r8xOa6faMaY2iQtd87CMC28mVRgseDEF=

# Only add this line if you want to proxy everything through your VPN.
AllowedIPs = 0.0.0.0/0
# Else, put your VPN's IP
AllowedIPs = 10.0.10.1/24

# Your VPN's IP:port
Endpoint = 51.30.40.40:59523
PersistentKeepalive = 25

Server-side acknowledgement of this client

EDIT: The following command will add the peer to the current instance and automatically update the wg0.conf file, it's the preferred method.

wg set wg0 peer <client public key> persistent-keepalive 25 allowed-ips <clientip> endpoint <serverip:port>
# as a Bash function
function wg-add {wg set wg0 peer $1 persistent-keepalive 25 allowed-ips $2 endpoint $3; }

wg-add <pubkey> <clientip> <endpoint>

We now need to change our server-side wg0.conf file to add a reference to this client inside the configuration.

Open the file at /etc/wireguard/wg0.conf on your vpn server, and add the following configuration block.

[Peer]
PublicKey = <copy/paste your client's public key here>
AllowedIPs = <put your client's IP here>

I recommend to prefix the [Peer] line with the hostname or a descriptor of the client you added, to easily organize peers.

Now, restart wireguard on the server, through systemctl restart wg-quick@wg0.

Client-side wireguard start

Like we did for the server, you should firstly test if the interface can be started, then enable it at startup.

We'll load the Wireguard daemon with our configuration file to quickly test that everything's ready.

# Client
$ wg-quick up wg0

If no error's shown, you can check that the daemon started by running wg and looking at the output.

Now, stop the WG daemon.

# Client
$ wg-quick down wg0

If everything's working, we can configure it to start at system startup.

# Client
$ systemctl enable wg-quick@wg0

Let's start our client for now.

# Client
$ systemctl start wg-quick@wg0

Client access revocation

To revoke the client from the server, you simply need to remove the [Peer] block related to your revoked client from the server's configuration, then restart your VPN server.

FAQ: Common problems I encountered

Client to Client: Ping is OK, but everything else is unreachable

That may be because your firewall is configured to drop everything else except ICMP.

With an iptables -L | less, you may notice a configuration sequence such as the following.

REJECT     all  --  anywhere     anywhere   reject-with icmp-host-prohibited
ACCEPT     all  --  anywhere             10.10.0.0/16
ACCEPT     all  --  10.10.0.0/16         anywhere

Which literally translates to:

Since rule priority is from first to last, the packet is dropped and it's end of story.

A hackfix you can do to manually enable C2C is to use iptables-save.

$ iptables-save > rules
$ nvim rules
$ iptables-restore < rules

When in the rules file, locate the two IPtables config lines which talk about your wireguard interface (here, 10.10.0.0/16 is a good search keyword), and put the REJECT rule below those two consecutive entries.