I have multiple Wireguard VPNs for various environments which all use their own DNS server to resolve hostnames. Below is an excerpt of my Wireguard configurations:
networking.wg-quick.interfaces = {
vpn1 = {
autostart = false;
address = [ /* VPN 1 addresses */ ];
dns = [ /* DNS 1 IPs */ ];
privateKeyFile = config.sops.secrets.vpn1-pkey.path;
mtu = 1280;
peers = [{
publicKey = "...";
presharedKeyFile = config.sops.secrets.vpn1-psharedkey.path;
allowedIPs = [ "10.36.0.0/15" ];
endpoint = "w.x.y.z:1234";
persistentKeepalive = 25;
}];
};
vpn2 = {
autostart = false;
address = [ /* VPN 2 addresses */ ];
dns = [ /* DNS 2 IPs */ ];
privateKeyFile = config.sops.secrets.vpn2-pkey.path;
mtu = 1280;
peers = [{
publicKey = "...";
presharedKeyFile = config.sops.secrets.vpn2-psharedkey.path;
allowedIPs = [ "10.4.0.0/15" ];
endpoint = "w'.x'.y'.z':1234";
persistentKeepalive = 25;
}];
};
};
This setup works fine, however I’m not able to start both VPNs at the same time because the DNS resolution fails for the first started VPN while it works for the second started VPN.
I found out that with the default resolvconf package, Wireguard was replacing the whole content of /etc/resolv.conf with the DNS settings of the last started VPN. Hence the DNS resolution issue.
I read online that systemd-resolved was fixing this issue, so I set services.resolved.enable = true. However, after doing that, when I start the VPNs there isn’t any DNS set for the interfaces, as seen with resolvectl status vpn1 vpn2:
Link 13 (vpn1)
Current Scopes: none
Protocols: -DefaultRoute +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported
Link 12 (vpn2)
Current Scopes: DNS
Protocols: +DefaultRoute +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported
I found out that when using systemd-resolved, the DNS settings of Wireguard configuration where not taken into account and one should use PostUP to run resolvectl dns %i <DNS IPs> to set the DNS servers for the Wireguard interfaces. Therefore, I added this to my config:
networking.wg-quick.interfaces = {
vpn1 = rec {
# Omitting previous unchanged configuration
postUp = "${pkgs.systemd}/bin/resolvectl dns vpn1 ${lib.concatStringsSep " " dns}";
};
vpn2 = rec {
# Omitting previous unchanged configuration
postUp = "${pkgs.systemd}/bin/resolvectl dns vpn2 ${lib.concatStringsSep " " dns}";
};
};
I can see that the postUp script is being run on wg-quick systemd services start:
juin 20 11:52:06 g-xps wg-quick-vpn1-start[5080]: [#] /nix/store/s29qf5z3iy7s8gmsng7xjw8v2h1yb6x0-postUp.sh/bin/postUp.sh
And the content of the postUp script does include the resolvectl command:
#!/nix/store/h3bhzvz9ipglcybbcvkxvm4vg9lwvqg4-bash-5.2p26/bin/bash
wg set vpn1 private-key <(cat /run/secrets/vpn1-pkey)
wg set vpn1 peer [REDACTED] preshared-key <(cat /run/secrets/vpn1-psharedkey)
/nix/store/9cxd17xnmw0bi8n4nf722ysqj2bjlh8s-systemd-255.4/bin/resolvectl dns nstoolingsnc [REDACTED IP ADDRESSES]
However, when the systemd service is started, the DNS servers are not set as seen with resolvectl status vpn1:
Link 13 (vpn1)
Current Scopes: none
Protocols: -DefaultRoute +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported
But, if I manually run the postUp script after the service is started, it works:
❯ sudo /nix/store/0f712568ksyaafb1h640xzkxzg9yavr0-postUp.sh/bin/postUp.sh
❯ resolvectl status vpn1
Link 13 (vpn1)
Current Scopes: DNS
Protocols: +DefaultRoute +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: [REDACTED]
DNS Servers: [REDACTED]
Any idea why this is not working?