Setup a WireGuard client using systemd-networkd

Please check out «Setup a WireGuard server using systemd-networkd» to learn more about WireGuard in general and network topology outlined in this post.

On Feb 24, 2022, Russia began a full scale invasion of Ukraine. The terror they brought to my country is devastating, and so publication of this post has been postponed till better times. Only now I finally found some strength inside to finish and publish this writing.

WireGuard is a great VPN choice for your home, and maybe even for your company. It's simple, fast, built into Linux kernel 5.6 and above, and can be configured via systemd-networkd in no time. The systemd suite supports WireGuard starting with v237 and is most likely installed on your Linux machine.

Let us try to setup a wireguard 'client' for the following VPN network:

Option Value
Network 10.0.0.0/24
Server 10.0.0.1
Client 10.0.0.20

First thing to do is to set up a virtual network device for a WireGuard tunnel. This can be achieved by means of a systemd.netdev(5) unit that must be created in /etc/systemd/network/ directory. The WireGuard network device must know about number of things:

Unlike 'server', a 'client' peer doesn't require port configuration because it's the 'client' that initiates connection not the other way round. This is how some /etc/systemd/network/wg0.netdev could look like:

[NetDev]
Name=wg0
Kind=wireguard
Description=wg0 - wireguard tunnel

[WireGuard]
PrivateKeyFile=/etc/systemd/network/wg0.key
FirewallMark=0x8888

[WireGuardPeer]
PublicKey=TPouHhVqvgAMfa9mNwZOh59kifUAsdn9Vtgsj2IsKVU=
AllowedIPs=0.0.0.0/0
Endpoint=vpn.example.com:51820

The content of /etc/systemd/network/wg0.key can be generated by invoking $ wg genkey command and must be readable by the systemd-network user.

There are couple of things to note:

Next thing to do is to use a systemd.network(5) unit to setup a network. The purpose of the network is to assign a proper IP address on the network device, set proper routes and so on.

This how some /etc/systemd/network/wg0.network could look like:

[Match]
Name=wg0

[Network]
Address=10.0.0.20/24
DNSDefaultRoute=true
DNS=1.1.1.1

[Link]
ActivationPolicy=manual

[RoutingPolicyRule]
FirewallMark=0x8888
InvertRule=true
Table=1000
Priority=10

[Route]
Gateway=10.0.0.1
GatewayOnLink=true
Table=1000

There are a bunch of important stuff going on:

When both the network device and the network are configured, the only remained step is to run $ networkctl reload to pipe in and apply latest configuration followed by $networkctl up wg0 to bring the VPN up.