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:
- 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/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:
-
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 to0.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) 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 tomanual
, the VPN is not brought up on system boot, and requires manual activation via$ networkctl up wg0
. One can use theup
value to always activate VPN on system boot. -
Both
RoutingPolicyRule
andRoute
come together and are only required if you want to route all the traffic over the tunnel. TheRoute
section essentially creates a default route that routes packets to the wireguard server. TheRoutingPolicyRule
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
andDNS
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.