You’re exactly right @mth, the fundamental issue was running wg.service
inside the newly created wg
namespace. The service needs to run in the default namespace. Thank you very much for your help!
I’ll include a summary here for those who may find this post later.
Overall I had to make two changes:
- Remove the NetworkNamespacePath line from
wg.service
’sserviceConfig
- Update the
wg setconf
command to run viaip netns exec
, since it runs afterwg0
is moved to thewg
namespace.
My working config is thus:
{ config, pkgs, ... }:
systemd.services."netns@" = {
description = "%I network namespace";
before = [ "network.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${pkgs.iproute}/bin/ip netns add %I";
ExecStop = "${pkgs.iproute}/bin/ip netns del %I";
};
};
systemd.services.wg = {
description = "wg network interface";
bindsTo = [ "netns@wg.service" ];
requires = [ "network-online.target" ];
after = [ "netns@wg.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = with pkgs; writers.writeBash "wg-up" ''
set -e
${iproute}/bin/ip link add wg0 type wireguard
${iproute}/bin/ip link set wg0 netns wg
${iproute}/bin/ip -n wg address add <ipv4 VPN addr/cidr> dev wg0
${iproute}/bin/ip -n wg -6 address add <ipv6 VPN addr/cidr> dev wg0
${iproute}/bin/ip netns exec wg \
${wireguard}/bin/wg setconf wg0 /root/myVPNprovider.conf
${iproute}/bin/ip -n wg link set wg0 up
${iproute}/bin/ip -n wg route add default dev wg0
${iproute}/bin/ip -n wg -6 route add default dev wg0
'';
ExecStop = with pkgs; writers.writeBash "wg-down" ''
${iproute}/bin/ip -n wg route del default dev wg0
${iproute}/bin/ip -n wg -6 route del default dev wg0
${iproute}/bin/ip -n wg link del wg0
'';
};
};
With this updated config, services can now be defined that will be exclusively routed through the wg0
interface. These new services can utilize the NetworkNamespacePath
option to run inside the wg
namespace. The basic skeleton is:
systemd.services.myWireguardOnlyService = {
description = "Service that will only have access to the wg0 interface"
bindsTo = [ "netns@wg.service" ];
requires = [ "network-online.target" ];
after = [ "wg.service" ];
serviceConfig = {
...
NetworkNamespacePath = "/var/run/netns/wg";
...
};
}
I’m sure this could be refactored and cleaned up a bit, but it will serve my needs nicely for now.