Hello, I’ll show how to set up a WireGuard interface that connects to a peer via his hostname and gets automatically started at boot by systemd.
networking.firewall = {
allowedUDPPorts = [ {exposedPort} ];
};
networking.wg-quick.interfaces = {
wg0 = {
autostart = true;
address = [ "192.168.3.2/24" ];
privateKeyFile = "/secrets/wireguard/private";
peers = [
# The VPS-peer which has a public IP
{
publicKey = "{pubKey}";
allowedIPs = [ "192.168.3.0/24" ];
endpoint = "{vpsName}:{exposedPort}";
persistentKeepalive = 25;
}
];
};
};
When booting up, WireGuard isn’t able to find the VPS peer because it can’t resolve {vpsName}. The systemd service that initializes the WireGuard interface gets started before DNS resolution is fully set up.
That should be enough, since nss-lookup.target is the signifer that DNS lookups are possible. You should not set wants on it, the systemd docs explicitly discourage that.
The ExecPreStart is unnecessary, as is the network-online.target since the upstream service already sets it, though at least the latter doesn’t hurt.
If that doesn’t work for you, your networking is misconfigured.
As an aside, I think `wg-quick` should almost never be used
Both systemd-networkd and networkmanager can set up wireguard connections and each is more appropriate for server/desktop use cases respectively.
The former has the benefit that you don’t need to do your networking in an auxillary systemd service, the latter that you can easily turn the connection on/off at runtime and your GUI applications properly integrate with it. wg-quick has no benefits over these.
Here’s how you do the above with networkmanager, since this sounds like a desktop use case (otherwise just hardcode the IP):
networking.networkmanager.ensureProfiles = {
environmentFiles = [ {envFileWithKey} ];
profiles.wg-{vpsName} = {
connection = {
autoconnect = true;
id = "wg-{vpsName}";
type = "wireguard";
interface-name = "wg0";
};
ipv4 = {
# Are you sure you want to bind a range to your host?
address = "192.168.3.2/24";
method = "manual";
};
wireguard = {
mtu = 1280;
private-key = "$WG_KEY"; # Your env file must set this
};
"wireguard-peer.{pubKey}" = {
endpoint = "{vpsName}:{exposedPort}";
allowed-ips = "192.168.3.0/24";
persistentKeepalive = 25;
};
};
};
In theory networkmanager claims to be clever enough to resolve DNS first if you set a non-IP peer, though admittedly I’ve not tested this.
Something must be wrong with my configuration since just using after = [ "nss-lookup.target" ] doesn’t work, and I get Name or service not known: {vpsName}:{exposedPort}' in the output of systemctl status wg-quick-wg0.service.
I also created a small dummy service that tries to ping google.com after nss-lookup.target and that one fails as well.
Do you have any units that will start the nss-lookup.target? You can check with:
systemctl list-dependencies nss-lookup.target
In my case, this will be started by nscd.service, which makes sense - it doesn’t depend on the network being up though, so lookups can happen before the network exists; I guess this is the default configuration. I also use unbound for DNS lookups, which also sets a dependency for nss-lookup.target, and therefore delays the target until after the network is up.
You could either consider using services.resolved.enable, which probably solves this issue by merit of having a cleaner setup story, or by adding a unit that does something like this (which is similar to what you have, it just integrates properly with the rest of the bootup story).
Indeed, nss-lookup.target has only one dependency on my system, which is nscd.service.
Unfortunately NetworkManager, which manages DNS, didn’t create a dependency for nss-lookup.target like unbound does. Do you think this is intentional because NetworkManager already has support for systemd-resolved?
I’ll probably go for the services.resolved.enable route.
More or less, though by default resolvconf is used. It in turn works a bit differently so it doesn’t really have a service that could block the nss-lookup.target. I guess this is just a case of the online status services being a little wonky with default configuration.
All that said, if you used a NetworkManager profile instead of wg-quick, this would all be managed inside NetworkManager, which generally has better logic for managing network profiles, especially on systems that need to do roaming.