Translation(s): English


A fast and modern VPN.

About WireGuard

WireGuard is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It can be a useful replacement for IPSec or OpenVPN.

Official website: https://www.wireguard.com/

Installation

WireGuard is packaged in wireguard which pulls in wireguard-tools. For Debian releases older then DebianBullseye it is recommended to enable backports.

To install wireguard, install the metapackage wireguard:

# apt install wireguard

Wireguard was first introduced to debian in DebianBuster via backports. Since kernel version 5.5 wireguard is supported in the linux kernel.

Configuration - Debian Peers

Step 1 - Generating Keypairs

You need to generate key pairs for the server and for each and every client. To generate server key pairs:

# cd /etc/wireguard/
# ( umask 0077 && wg genkey | tee privatekey | wg pubkey > publickey )
# mkdir my_client1
# cd my_client1
# ( umask 0077 && wg genkey | tee privatekey | wg pubkey > publickey )
# cd my_client2
# ( umask 0077 && wg genkey | tee privatekey | wg pubkey > publickey )

Make sure that you protect the privatekey file, e.g. via appropriate file permissions.

Step 2 - Configuration

You will have to do trial and error tests if you need to enable port forwarding because for a basic VPN you probably can do without it. If you need port forwarding, set the following in /etc/sysctl.conf

net.ipv4.ip_forward = 1

to reload settings

# sysctl -p

Step 2 - Alternative A - systemd with wg-quick

In server create /etc/wireguard/wg0.conf. Open UDP port 51820 and change your interface for iptables (eth0).

[Interface]
Address = 192.168.11.1/24
SaveConfig = true
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820
PrivateKey = YOUR_SERVER_PRIVATE KEY

[Peer]
PublicKey = YOUR_CLIENT_PUBLIC_KEY
AllowedIPs = 192.168.11.2/32

[Peer]
PublicKey = OTHER_CLIENT_PUBLIC_KEY
AllowedIPs = ...

Test server:

# systemctl start wg-quick@wg0
# ip a show wg0

Now, in client create /etc/wireguard/wg0.conf.

[Interface]
PrivateKey = YOU_CLIENT_PRIVATE_KEY
## Client IP
Address = 192.168.11.2/24

## if you have DNS server running
# DNS = 192.168.11.1

[Peer]
PublicKey = YOUR_SERVER_PUBLIC_KEY

## to pass internet trafic 0.0.0.0 but for peer connection only use 192.168.11.0/24, or you can also specify comma separated IPs
AllowedIPs =  0.0.0.0/0

Endpoint = SERVER_PUBLIC_IP:51820
PersistentKeepalive = 20

Test client:

# systemctl start wg-quick@wg0
# ip a show wg0

You may enable systemd by default in server and client by

# systemctl enable wg-quick@wg0

For testing purposes, it may be sufficient to use wg-quick directly - see the wg-quick(8) man page (upstream version) and quickstart instructions.

Step 2 - Alternative B - /etc/network/interfaces

The following configuration examples focus on using /etc/network/interfaces as much as possible.

For a host with static network configuration (such as a server), using /etc/network/interfaces is often the preferred way.

Point-to-point tunnel

This example builds a simple point-to-point tunnel between two machines.

# /etc/network/interfaces
auto wg-p2p
iface wg-p2p inet static
        address 10.88.88.1
        netmask 255.255.255.0
        pre-up ip link add $IFACE type wireguard
        pre-up wg setconf $IFACE /etc/wireguard/$IFACE.conf
        post-down ip link del $IFACE
iface wg-p2p inet6 static
        address 2001:db8:1234:5678::1
        netmask 64

# /etc/wireguard/wg-p2p.conf
[Interface]
PrivateKey = <paste the private key of the local host here>
ListenPort = <enter a port number to use for WireGuard UDP data, 51820 seems common>

[Peer]
Endpoint = <remote IP>:<remote port>
PublicKey = <paste the public key of the remote host here>
AllowedIPs = 0.0.0.0/0, ::/0

You can then simply add routes through the tunnel, either statically, or dynamically using e.g. OSPF or BGP. For static routes:

# ip route add 2001:db8:4242::/48 dev wg-demo
# ip route add 192.168.42.0/24 dev wg-demo

For static routes where the endpoint is inside the network eg port forwarded to an vpn host, you will need to set the source address on the packets to the internal address, otherwise routing on the other side of the tunnel will try and route back over the public internet and not through the wg tunnel.

# ip route add 192.168.42.0/24 dev wg-demo src 192.168.42.10

VPN client with default route

This allows a "client" to connect to a server, and redirect its default route through the tunnel. This example uses wg-quick(8), make sure you understand what it does to your routing tables!

# /etc/network/interfaces
auto wg-client
iface wg-client inet static
        address 10.88.88.1
        netmask 255.255.255.0
        pre-up wg-quick up $IFACE
        post-down wg-quick down $IFACE

# /etc/wireguard/wg-client.conf
[Interface]
PrivateKey = <paste the private key of the local host here>
ListenPort = <enter a port number to use for WireGuard UDP data, 51820 seems common>

[Peer]
Endpoint = <server IP>:<server port>
PublicKey = <paste the public key of the remote host here>
AllowedIPs = 0.0.0.0/0, ::/0

Step 2 - Alternative C - systemd-networkd

systemd has native support for setting up WireGuard interfaces since version 237 (available in buster and stretch-backports).

First, create a systemd.netdev(5) file ending in .netdev and place it in /etc/systemd/network, for example as /etc/systemd/network/wg0.netdev. The .netdev file will contain security-sensitive data (the private key) and should have appropriate file permissions:

Use of ?PrivateKeyFile

Since systemd 242 you can use e.g. PrivateKeyFile=/etc/systemd/network/wg0.privatekey which only contains the privatekey. This way you will only have to set root:systemd-network and e.g. umask=0440 on this file.

# ( umask 0027 && touch /etc/systemd/network/wg0.netdev )
# chown root:systemd-network /etc/systemd/network/wg0.netdev

In the next config file, for server's AllowedIPs paste IPs of the wg0 interface, for each client adding +1 to the lowest subnet. Here we imagine IPs of the wg0 are 172.30.0.1 and 2a11:4f5:1c0f:a452:ac1e::1

Server configuration:

[NetDev]
Name=wg0
Kind=wireguard
Description=WireGuard server

[WireGuard]
PrivateKey=<paste the private key of the server>
ListenPort=<enter a port number to use for WireGuard UDP data, 51820 seems common for servers>

#Client1
[WireGuardPeer]
PublicKey=<paste the public key of the my_client1>
AllowedIPs=172.30.0.2/32,2a11:4f5:1c0f:a452:ac1e::2/128
PersistentKeepalive = 15

#Client2
[WireGuardPeer]
PublicKey=<paste the public key of the my_client2>
AllowedIPs=172.30.0.3/32,2a11:4f5:1c0f:a452:ac1e::3/128
PersistentKeepalive = 15

Second, create a matching systemd.network(5) file ending in .network and place it in /etc/systemd/network, for example as /etc/systemd/network/wg0.network:

[Match]
Name=wg0

[Network]
Address=172.30.0.1/24
## In this example IPv6 address of the server is 2a11:4f5:1c0f:a452::1 ##
Address=2a11:4f5:1c0f:a452:ac1e::1

Now tell systemd to enable and start SystemdNetworkd if not already done or just reload the configuration systemd-networkd(8) / networkctl:

# # if the service isn't enabled and running yet
# systemctl --now enable systemd-networkd
# # reload any configuration changes
# networkctl reload

Recreation of the wireguard interface

If you change something like the Port of the interface you need to recreate the interface. This can be done by e.g. networkctl delete wg0 ; networkctl reload.

Client configuration for the other Debian PC would look like that:

[NetDev]
Name=wg0
Kind=wireguard
Description=WireGuard client

[WireGuard]
PrivateKey=<paste the private key of the client>
ListenPort=<any port, it will be opened on the client>

#Server
[WireGuardPeer]
PublicKey=<paste the public key of the server>
AllowedIPs=0.0.0.0/0,::/0
PersistentKeepalive = 15

Mobile client configuration needs a different config, See Step 3, Alternative C

Step 2 - Alternative D - NetworkManager

NetworkManager has had support for WireGuard since version 1.16 (i.e. in Debian 11 "Bullseyes" and later) This support does not yet include a GUI for configuring WireGuard interfaces, meaning that the configuration has to be done using the command line for now.

See this blog post for more details.

Step 3 - Check the end result

You can check the status of your new interface by using e.g.:

# ip addr show dev wg0
# wg show wg0

And, if you've let systemd create the interface, by using:

# networkctl status wg0

Configuration - Mobile Clients

WireGuard has a user space implementation for mobile devices available via the WireGuard app - available for Android and iOS (a full list of supported operating systems is available here).

The client can be configured in several ways:

Alternative A - Create configuration manually

This is self-explanatory, you actually create the config on the mobile device then transfer the relevant keys to the server's config.

Alternative B - Create configuration from archive

Here you have to create a .zip archive of the client configuration file, transfer it to the device then import it into the app.

Alternative C - Import by reading a QR code (most secure method)

The mobile client as of version 0.0.20180724 supports QR code based input.

qrencode can be used to generate qr codes, even in a terminal/console using UTF8 characters.

The syntax is:

# qrencode -t ansiutf8 < client.conf

This will generate a QR code that is readable by the mobile client.

The advantage of this approach is that there is no need to transfer sensitive information via data channels that can potentially be compromised and there is no need for any additional software.

config file example: Mobile client config can be kept on the server in the same folder as it's keys /etc/wireguard/<client_folder>/client.conf:

##/etc/wireguard/my_client1/client.conf##
## Below we consider server being set up with IPs of interface wg0 and IP of the server from the Step 2, Alternative C##
[Interface]
Address = 172.30.0.2/32,2a11:4f5:1c0f:a452:ac1e::2/128
PrivateKey = <paste here private key of the client1>
ListenPort = <any port, it will be opened on the client>

[Peer]
Endpoint = [2a11:4f5:1c0f:a452::1]:51820 
PublicKey = <paste here public key of the server>
AllowedIPs = 0.0.0.0/0,::/0
PersistentKeepalive = 15

Configuration - Kernel hardening

If you have the sysctl kernel.modules_disabled = 1 setting enabled (sysctl -a | grep modules), you may need to add a file /etc/modules-load.d/wireguard.conf with the contents wireguard.

If you run lsmod | grep wireguard and there is nothing in the output and than when you run modprobe wireguard it says modprobe: ERROR: could not insert 'wireguard': Operation not permitted then you most probably need to add the file above and restart the system. Then check that it worked with lsmod | grep wireguard.

See also