WireGuard (via systemd-networkd)
WireGuard is a new VPN protocol and software under development (although they are working for a stable release), using modern cryptography (ChaCha20, Ed25519…). It is simple to use and configure similarly to OpenSSH, you just need to share public keys between peers, compared to OpenVPN where you need to manage a private certificate authority (which has different advantages). Please note though that WireGuard is not made for having anonymous (not logged) clients unlike how OpenVPN can be used for, since it uses static IP addresses instead of DHCP (servers need to track the connections of clients). The main implementation lives in Linux kernel (in a kernel module) but other software implementations exist.
Please note that source code hasn’t yet been audited although formal verification has been done for some parts of WireGuard. The code base is way smaller than other related projects so it should be easier to audit and maintain.
This tutorial presents an installation on a Linux-based operating system with systemd (and systemd-networkd). Other setups are also possible but I found this one simple to use, although platform-dependant. Note that I am not interested by routing Internet traffic through the private network created, so this won’t be covered. I personnally keep using OpenVPN for that matter.
Here are instructions to install WireGuard on Debian and Arch Linux. You can find other operating system instructions on the official website.
At the time of writing, WireGuard is shipped in Debian testing (bullseye) and unstable repositories. The
wireguard meta package includes the kernel module and WireGuard tools. All dependencies are in stable repository, so this won’t cause issues. You can check the Package search website if it has changed.
Using instructions similar from Debian Wiki, let’s add the testing repository, but with a lower priority than default repositories to avoid conflicts. This is of course not required if you are already running Debian bullseye (11) or a more recent version (like unstable/sid).
1 2 echo "deb http://deb.debian.org/debian/ testing main" > /etc/apt/sources.list.d/testing.list printf 'Package: *\nPin: release a=testing\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-testing
Then install the
wireguard package. Note that this will install Linux kernel headers to build the WireGuard kernel module (dkms), unless a built kernel module is out now.
1 apt update && apt install wireguard
On Arch Linux
Using instructions from ArchWiki, install the
wireguard-tools package for the tools and the appropriate package depending to your kernel:
wireguard-dkmswhen using any other kernel (WireGuard kernel module will be built, so this requires Linux kernel headers, e.g.
linux-mainline-headersif you are using
linux-mainlinekernel AUR package)
1 pacman -Syu wireguard-tools wireguard-arch
You may have to reboot to load the right kernel version and WireGuard module.
You need to enable the
systemd-networkd service, if not done already. The advantage is that it will manage both WireGuard setup and networking at the same time, easing the configuration. Please note that I haven’t tried using it alongside another networking daemon (like
networking on Debian or
dhcpcd on Arch Linux), so you may have to migrate your whole networking configuration and disable the other daemon.
On both server and client
You need to create a pair of keys on both server and client. Each client will need to get server’s public key and the server will need to get each client’s public key. Also a pre-shared key will be created, known to each peer.
1 2 3 4 5 6 7 8 9 10 11 # go to systemd-networkd configuration directory cd /etc/systemd/network # create files with right permissions (640) to prevent other system users to read secrets umask 0027 touch wg0.netdev wg0.network wg-preshared.key wg-private.key wg-public.key umask 0022 chown root:systemd-network * # create a pair of keys wg genkey | tee wg-private.key | wg pubkey > wg-public.key
wg0.netdev will be used for WireGuard configuration,
wg0.network for networking configuration.
On systemd versions earlier than 242,
wg0.netdev will contain secrets, on later versions it’s possible to reference other created files. At the time of writing, Debian uses systemd 241, which doesn’t support that feature.
On the server, you need to create the pre-shared key (or on any other peer).
1 wg genpsk > wg-preshared.key
It needs to be copied to other peers.
Then here are sample server configuration files. I chose to use a subnet
10.213.213.0/24, you can also use IPv6 or even dual-stack.
Make sure to change
<variable> to the appropriate key value. Less-than and greater-than signs (
<>) must not be kept.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 cat <<EOF > wg0.netdev [NetDev] Name = wg0 Kind = wireguard Description = wg server 10.213.213.0/24 [WireGuard] # If running systemd >= 242 #PrivateKeyFile = /etc/systemd/network/wg-private.key # If running systemd < 242 PrivateKey = <content of local wg-private.key> ListenPort = 51820 # For any number of client: [WireGuardPeer] PublicKey = <content of client's wg-public.key> AllowedIPs = 10.213.213.2/32 # If running systemd >= 242 #PresharedKeyFile = /etc/systemd/network/wg-preshared.key # If running systemd < 242 PresharedKey = <content of wg-preshared.key> EOF
AllowedIPs represents here the static IP address of the client. You need to choose one per client in the subnet.
You can change
ListenPort to your needs (e.g.
53 to pass through firewalls, since it uses UDP).
1 2 3 4 5 6 7 8 9 10 11 cat <<EOF > wg0.network [Match] Name = wg0 [Network] Address = 10.213.213.1/32 [Route] Gateway = 10.213.213.1 Destination = 10.213.213.0/24 EOF
Then restart systemd-networkd:
1 systemctl restart systemd-networkd
Like on the server, here are sample configuration files. Make sure you change the private IP address on each client, according to server configuration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 cat <<EOF > wg0.netdev [NetDev] Name = wg0 Kind = wireguard Description = wg client 10.213.213.2 [WireGuard] # If running systemd >= 242 #PrivateKeyFile = /etc/systemd/network/wg-private.key # If running systemd < 242 PrivateKey = <content of local wg-private.key> [WireGuardPeer] PublicKey = <server's public key> AllowedIPs = 10.213.213.0/24 Endpoint = <server's public IP address>:51820 # If running systemd >= 242 #PresharedKeyFile = /etc/systemd/network/wg-preshared.key # If running systemd < 242 PresharedKey = <content of wg-preshared.key> PersistentKeepalive = 25 EOF cat <<EOF > wg0.network [Match] Name = wg0 [Network] Address = 10.213.213.2/32 [Route] Gateway = 10.213.213.1 Destination = 10.213.213.0/24 GatewayOnlink = true EOF
ListenPort is not entered, a random port will be chosen by systemd, this is not important for clients that connect to the server specified with
Then restart systemd-networkd.
Check the connection
You can check that systemd-networkd enabled the WireGuard network interface (wg0) with the
1 2 3 4 5 $ networkctl IDX LINK TYPE OPERATIONAL SETUP 1 lo loopback carrier unmanaged 2 eno1 ether routable configured 3 wg0 wireguard routable configured
You should now be able to ping server and client addresses from each other.
If there is any issue, check the logs with
journalctl -eu systemd-networkd. If you have
Unknown lvalue errors, it means you used unknown configuration directives, e.g. mistyped or from a more recent systemd version.
You can also get more information using the
1 2 3 4 5 6 7 8 9 10 11 12 $ wg interface: wg0 public key: <redacted> private key: (hidden) listening port: 51820 peer: redacted= preshared key: (hidden) endpoint: <client's public IP address>:44195 allowed ips: 10.213.213.2/32 latest handshake: 24 seconds ago transfer: 968.57 KiB received, 50.94 MiB sent
1 2 3 4 5 6 7 8 9 10 11 12 13 $ wg interface: wg0 public key: <redacted> private key: (hidden) listening port: 44195 peer: redacted= preshared key: (hidden) endpoint: <server's public IP address>:51820 allowed ips: 10.213.213.0/24 latest handshake: 49 seconds ago transfer: 50.94 MiB received, 971.40 KiB sent persistent keepalive: every 25 seconds
man 5 systemd.netdev(online versions: Debian, Arch, latest)
- Quick Start on official website
Copyright © 2019, Elouan Martinet (Exagone313) — This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.