Help setup Wireguard

Hi! I’m trying to setup Wireguard on a cheap OVH NixOs VPS.
I tried both the first setup and the wg-quick + dnsmasq setup proposed on WireGuard - NixOS Wiki for the VPS, and a wg-quick conf file for the desktop.
But when I bring up the interface on the client, I lose all internet connectivity.
By doing this:

# ip -4 route del 0.0.0.0/0 dev wg0 table 51820
# ip -4 route add 10.10.0.1/32 dev wg0

I get back internet connectivity (but not through wireguard tunnelling)
I also can ping and connect to the VPS (which Wireguard address is 10.10.0.1), querying its web server and its dns server.
But it’s not possible to connect to the internet through the WIreguard interface.
For example, ping -I wg0 1.1.1.1 doesn’t work.
I can’t understand what I did wrong. The VPS is a fresh install and contains almost no extra configuration. Here are the relevant parts of the config:

VPS:

{ lib, config, pkgs, ... }:

let
  wgPort = 123;
  genAddress = number: "10.10.0.${toString number}/32";
  externalInterface = "ens3";
in
{
  # enable NAT
  networking.nat = {
    enable = true;
    externalInterface = externalInterface;
    internalInterfaces = [ "wg0" ];
  };

  # Open WG port
  networking.firewall = {
    allowedTCPPorts = [ 53 wgPort ];
    allowedUDPPorts = [ 53 wgPort ];
  };

  # Enable routing
  boot.kernel.sysctl = {
    "net.ipv4.conf.all.forwarding" = lib.mkOverride 98 true;
    "net.ipv4.conf.default.forwarding" = lib.mkOverride 98 true;
  };

  services.dnsmasq = {
    enable = true;
    extraConfig = ''
      interface=wg0
    '';
  };

  networking.wg-quick.interfaces = {
    wg0 = {
      # Determines the IP address and subnet of the server's end of the tunnel interface.
      address = [ (genAddress 1) ];

      listenPort = wgPort;

      # This allows the wireguard server to route your traffic to the internet and hence be like a VPN
      postUp = ''
        ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT
        ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s ${genAddress 1} -o ${externalInterface} -j MASQUERADE
      '';

      # Undo the above
      preDown = ''
        ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT
        ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s ${genAddress 1} -o ${externalInterface} -j MASQUERADE
      '';

      privateKeyFile = "...";

      peers = [
        { # desktop
          publicKey = "...";
          allowedIPs = [ (genAddress 2) ];
        }
      ];
    };
  };
}

Desktop:

[Interface]
Address = 10.10.0.2/32
DNS = 10.10.0.1
PrivateKey = ...

[Peer]
PublicKey = ...
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
Endpoint = ...:123
1 Like

Especially, I don’t get why I can’t even ping the VPN before executing this

# ip -4 route del 0.0.0.0/0 dev wg0 table 51820
# ip -4 route add 10.10.0.1/32 dev wg0

Maybe there is a routing infinite loop or something ?

I recorded an asciinema to better show the issue: Can't get WireGuard to NAT packets. - asciinema.org

The packets that you want to snat/masquerade to WAN are sent by the client and thus have source address 10.10.0.2. But your iptables rule only allows masquerading for source address 10.10.0.1.

To fix this, change the rule to:

${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s ${genAddress 2} -o ${externalInterface} -j MASQUERADE

In general, it’s useful to allow masquerading for the whole wg subnet (-s 10.10.0.0/24 instead of -s ${genAddress 2}). This allows you to add more clients later.

Also set address = [ "10.10.0.1/24" ] instead of address = [ (genAddress 1) ] to fix routing to the client(s).

1 Like

Hi, thanks for your answer.
I removed the genAddress stuff because it was error-prone, and followed your fixes (I did some awful mistakes :sweat_smile:)
I have now this configuration on the server peer, and it’s working:

  # Enable routing
  boot.kernel.sysctl = {
    "net.ipv4.conf.all.forwarding" = lib.mkOverride 98 true;
    "net.ipv4.conf.default.forwarding" = lib.mkOverride 98 true;
  };

  services.dnsmasq = {
    enable = true;
    extraConfig = ''
      interface=${wireguardInterface}
    '';
  };

  networking.wg-quick.interfaces = {
    "${wireguardInterface}" = {
      # Determines the IP address and subnet of the server's end of the tunnel interface.
      address = [ "10.10.0.1/24" ];

      listenPort = wgPort;

      # This allows the wireguard server to route your traffic to the internet and hence be like a VPN
      postUp = ''
        ${pkgs.iptables}/bin/iptables -A FORWARD -i ${wireguardInterface} -j ACCEPT
        ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.10.0.0/24 -o ${externalInterface} -j MASQUERADE
      '';

      # Undo the above
      preDown = ''
        ${pkgs.iptables}/bin/iptables -D FORWARD -i ${wireguardInterface} -j ACCEPT
        ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.10.0.0/24 -o ${externalInterface} -j MASQUERADE
      '';

      privateKeyFile = "...";

      peers = [
        { # sona
          publicKey = "...";
          allowedIPs = [ "10.10.0.2/32" ];
        }
      ];
    };
  };
}

However, I still have some issues on the client-side:
When I bring up the interface on the client, I still lose all internet connectivity.
Here are the routes when running ip route after wg-quick up wg0, wlp3s0 being my wifi interface:

default via x.x.x.x dev wlp3s0 proto dhcp metric 600 
10.10.0.0/24 dev wg0 proto kernel scope link src 10.10.0.2 
x.x.x.0/20 dev wlp3s0 proto kernel scope link src x.x.x.y metric 600 

To get back internet connectivity, I must do this:

$ ip -4 route del 0.0.0.0/0 dev wg0 table 51820
$ ip -4 route add 10.10.0.1/32 dev wg0

And this for each IP I want to connect to through Wireguard:

$ ip -4 route add <ip> dev wg0

My desktop /etc/wireguard/wg0.conf looks like this:

[Interface]
Address = 10.10.0.2/24
DNS = 10.10.0.1
PrivateKey = ...

[Peer]
PublicKey = ...
AllowedIPs = 10.10.0.0/24, 0.0.0.0/0
PersistentKeepalive = 25
Endpoint = ...:123

I’d like all my connections to go through the Wireguard interface.

Unless you use network namespaces to keep things separate, if you want your default route to go through wg0, you’re going to need a route to at least your wireguard peer via the ‘real’ internet next hop. Otherwise the encapsulated packets have nowhere to go.

Hey @uep, thanks for your answer. I’m afraid I can’t translate your information into a concrete route.
If I correctly understand, as wg0 is the default interface route, all packets go through it, but then there is no “forwarding to the real network (and wifi/ethernet interface)”?
More concretely, which route (and associated command) would you add?


I tried importing the wg0.conf file into NetworkManager, but I get the exact same issue of loosing all internet connectivity

@uep means ip route add 1.2.3.4/32 via <gateway_ip>.

While this should work, there’s a slightly more clever solution used by wg-quick: it uses routing rules to avoid having to update this particular route in case your gateway changes. Refer to Improved Rule-based Routing in the Wireguard documentation for the full rationale.

It should already work this way though, but it doesn’t. The only odd thing about your client config is that you have defined overlapping AllowedIPs. Try changing it tot a single route.

That said, are you sure the issue is not on your server end? What if you just add 1.0.0.1 as AllowedIPs and try to ping that? If that doesn’t work, use tcpdump to see if the traffic arrives/exits at the server end (both on the wg and external interfaces).

In any case, if the above doesn’t help you’ll need to provide more info. Post this for client/server. Try not to censor IPs, only anonimize them if it’s a public IP you want to hide (your gateway might be relevant to the issue at hand, but you’ve hidden it…).

Hi @ius, thanks for answering!
I’m sure the issue is on the desktop side, because I’ve set up a WireGuard “client” peer on my Android device, and it’s working fine.

I’ve tried the client peer with values 10.10.0.0/24, 0.0.0.0/0 and 0.0.0.0/0 for AllowedIPs, both don’t work.

When I remove the ip route del 0.0.0.0/0 dev wg0 table 51820 route rule then manually add a specific ip route such as ip route add 1.0.0.1/32 dev wg0, corresponding packets successfully go through the VPN interface (and I can double-check it on the server peer using iftop -i wg0).

Command run with wg interface down: https://0x0.st/-hZU.txt
Command run with wg interface up: https://0x0.st/-hZG.txt

Maybe the issue is with the routing table number? I guess not, but I run out of ideas.
Also, as mentioned above, I use NetworkManager, but it shouldn’t be relevant to the issue here.

Anyway, thank you all for your time already, I really appreciate the help! Linux networking (routing tables etc) is not my specialty :slight_smile:

1 Like

Thanks.

The output looks mostly fine to me. Your wg0 interface lacks an IP address though? What’s up with that? According to the wg-quick config you posted before, it should be configured…

Can’t tell how that would relate to the modification sequence which makes it work though (I’d expect it to fail in either case, or perhaps originate tunnel traffic from the wlp3s0 address instead - which shouldn’t work either).

If the interface address isn’t the issue here, you might want to try running ip route get in the working/non-working case.

ip route get 1.0.0.1
ip route get 1.0.0.1 mark 0xca6c

… and see if the output differs.

If it doesn’t: use tcpdump to capture on wg0 and see if a ping packet actually leaves the interface…

If all else fails, consider linking this issue in #wireguard on Liberachat - some fairly helpful folks hangout over there…