Setup a WireGuard client using systemd-networkd
Tags: wireguard, vpn, systemd, linux
Published: 2022-09-17 14:30:54

---
title: Setup a WireGuard client using systemd-networkd
published: true
date: 2022-09-03 00:00:00 UTC
tags: wireguard, vpn, systemd, linux
canonical_url: https://kalnytskyi.com/posts/setup-wireguard-client-systemd-networkd/
---

_Please check out [«Setup a WireGuard server using systemd-networkd»](/ikalnytskyi/setup-a-wireguard-server-using-systemd-networkd-42nb) 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](https://man.archlinux.org/man/systemd-networkd.8.en) 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)](https://man.archlinux.org/man/systemd.netdev.5) unit that must be created in `/etc/systemd/network/` directory. The WireGuard network device must know about number of things:

- The private key of the peer.
- The endpoint of the 'server' peer and its public key.

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/wireguard-keys/wg0
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:

- The `FirewallMark` option takes a number and is used to mark outgoing WireGuard packets. Please remember that mark, it will be later used for network configuration.

- The `AllowedIPs` option is set to `0.0.0.0/0` because we're interested to route all the traffic via the tunnel, i.e. surfing the Internet via VPN. If your plans for the VPN is to connect multiple devices into a single network, you should go with the network address only, e.g. `10.0.0.0/24`.

- The `Endpoint` option takes a wireguard 'server' IP address or hostname, followed by a colon, and then a port the 'server' accepts connection on. The endpoint must be reachable from 'client' peers even when VPN is down.

Next thing to do is to use a [systemd.network(5)](https://man.archlinux.org/man/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:

- Since `/24` network mask is used, systemd-networkd will automatically add a route for the whole network to be routed via the WireGuard tunnel. Without that mask, it'd be up to a user to properly configure routing on the system.

- With `ActivationPolicy` set to `manual`, the VPN is not brought up on system boot, and requires manual activation via `$ networkctl up wg0`. One case use the `up` value to always activate VPN on system boot.

- Both `RoutingPolicyRule` and `Route` come together and are only required if you want to route all the traffic over the tunnel. The `Route` section essentially creates a default route that routes packets to the wireguard server. The `RoutingPolicyRule` section, on the other hand, says that this new default route should be applied only for the packets not coming from the wireguard network device (i.e. not being marked with a firewall mark).

- When VPN is used as a gateway for the Internet, it's quite common to set some non default DNS servers to resolve domain names. It could be your own VPN server, or some third-party provider such as Cloudflare. In order to set custom DNS servers when VPN connection is up, one can use `DNSDefaultRoute` and `DNS` options. The former tells the system to use the latter to resolve all domain names.

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.