Setting up a WireGuard client with NetworkManager (using nmcli
)
For reasons beyond the scope of this entry, I've been building a VPN server that will support WireGuard (along with OpenVPN and L2TP). A server needs a client, so I spent part of today setting up my work laptop as a WireGuard client in a 'VPN' configuration, under NetworkManager because that's what my laptop uses. I was hoping to do this through the Cinnamon GUIs for NetworkManager, but unfortunately while NetworkManager itself has supported WireGuard for some time, this support hasn't propagated into GUIs such as the GNOME Control Center (cf) or the NetworkManager applet that Cinnamon uses.
I'm already quite familiar with WireGuard in general, so I found
that the easiest way to start was to set up a basic WireGuard
configuration file for the connection in /etc/wireguard/wg0.conf
,
including both the main configuration (with the laptop's key and
my local port) and a [Peer]
section for the server. Since I'm
using WireGuard here in a VPN configuration, instead of to reach
just some internal IPs, I set AllowedIPs
to 0.0.0.0/0. After writing wg0.conf
, I then imported it into
NetworkManager:
nmcli connection import type wireguard file /etc/wireguard/wg0.conf
(For what can go in the configuration file, start with wg(8)
and wg-quick(8)
. I suspect
that NetworkManager doesn't support some of the more advanced keys.
I stuck to the basics. The import process definitely ignores the
various script settings supported by wg-quick(8)
. Currently,
see nm_vpn_wireguard_import()
in nm-vpn-helpers.c.)
Imported connections are apparently set to auto-connect, which isn't what I wanted, plus there were some other things to adjust (following the guide of Thomas Haller's WireGuard in NetworkManager):
nmcli con modify wg0 \ autoconnect no \ ipv4.method manual \ ipv4.address 172.29.50.10/24 \ ipv4.dns <...>
At this point you might be tempted to set ipv4.gateway
, and indeed
that's what I did the first time around. It turns out that this is
a mistake, because these days NetworkManager will do the right thing
based on the 'accept everything' AllowedIPs
I set, right down to
setting up policy based routing with a fwmark so that encrypted
traffic to the WireGuard VPN server doesn't try to go over WireGuard.
If you set ipv4.gateway
as well, you wind up with two default
routes and then your encrypted WireGuard traffic may try to go over
your WireGuard connection again, which doesn't work.
(See the description of 'ip4-auto-default-route
in the WireGuard
configuration properties.
The full index of available NetworkManager settings in various
sections is currently here; the
ones most useful to me are probably connection.*
and ipv4.*
.)
Getting DNS to work correctly requires a little extra step, or at
least did for me. While the wg0
connection is active, I want all
of my DNS queries to go to our internal resolving DNS server and
also to have a search path of our university subdomain. This
apparently requires explicitly including '~
' in the NetworkManager
DNS search path:
nmcli con modify wg0 \ ipv4.dns-search "cs.toronto.edu,~"
This comes from Fedora bug #1895518, which also
has some useful resolvectl
options.
You (I) can see a lot of settings for the WireGuard setup with
'nmcli connection show wg0
', including active ones, but this seems
to omit NetworkManager's view of the WireGuard peers. To see that,
I needed to look directly at the configuration file that NetworkManager
wrote, in /etc/NetworkManager/system-connections/wg0.nmconnection
.
I'm someday going to need to edit this directly to modify the
WireGuard VPN server's endpoint from my test machine to the production
machine.
(The NetworkManager RFE for configuring WireGuard peers in nmcli
is issue #358.)
With no GUI support for WireGuard connections, I have to bring this
WireGuard VPN up and down with 'nmcli con up wg0
' and 'nmcli con
down wg0
'. Once I have the new VPN server in production, I'll be
writing little scripts to do this for me. Hopefully this will be
improved some day, so that the NetworkManager applet allows you to
activate and deactivate WireGuard connections and shows you that
one is active.
If I wanted a limited VPN that only sent traffic to our internal
networks over my WireGuard link, I would configure the server's
AllowedIPs
to the list of networks and then I believe that
NetworkManager would automatically set up routes for them. However,
I don't know how to make this work (in NetworkManager) if the
WireGuard VPN server itself was on one of the subnets I wanted to
reach over WireGuard. For my laptop, routing all traffic over
WireGuard to work is no worse than using our OpenVPN or L2TP VPN
servers, which also do the same thing by default.
(On my home desktop, I use hand built fwmark-based policy rules to deal with my WireGuard endpoint being on a subnet I want to normally reach over WireGuard. NetworkManager will build the equivalents for me when I'm routing 0.0.0.0/0 over the WireGuard link, but I believe not in other situations.)
(For information, I primarily relied on Thomas Haller's WireGuard in NetworkManager, supplemented with a Fedora Magazine article and this article.)
|
|