WireGuard: Difference between revisions

Added a hint, which package needs to be added for the ip46tables command.
Tie-ling (talk | contribs)
Additional routing setups: add mirror on internet archive
 
(33 intermediate revisions by 10 users not shown)
Line 1: Line 1:
[https://www.wireguard.com/ WireGuard] is a simple yet fast and modern VPN that utilizes state-of-the-art cryptography.


=Setting up WireGuard=
= Configuration Modules =
==Generate keypair==


Each peer needs to have a public-private keypair. The keys can be generated on any machine that already has WireGuard installed using the <code>wg</code> utility. If WireGuard isn't installed yet, it can be made available by adding <code>wireguard-tools</code> to <code>environment.systemPackages</code> or by running <code>nix-env -iA nixos.wireguard-tools</code> for NixOS based systems and <code>nix-env -iA nixpkgs.wireguard-tools</code> for non-NixOS systems.
WireGuard-related NixOS options exist for the following networking modules:


Creating a keypair is simple:
* NetworkManager
<syntaxHighlight lang="nix">
* wg-quick
umask 077
* networking.wireguard
mkdir ~/wireguard-keys
* systemd.network
wg genkey > ~/wireguard-keys/private
 
wg pubkey < ~/wireguard-keys/private > ~/wireguard-keys/public
Depending on how your computer is configured, you need to refer to the
relevant section for setting up WireGuard.
 
Different modules have different capabilities.  systemd.network support routing
traffic on a per user basis.  For example, you can route all torrenting traffic
through a wireguard tunnel, see below.
 
systemd.network is recommended due to its powerful configuration interface.
wg-quick is suitable for common usage patterns.  networking.wireguard seems to
have issues with routing.  NetworkManager does not supoort Proxy server setup, and
is cubersome to use.
 
Skip to Generate Keys section if you are in a hurry.
 
= Use cases =
 
The first use case is Virtual Private Network, which makes several peers
available on the same private subnet.  This is the basis for the proxy
configuration below.
 
The second use case is Internet proxy,  which allows you to access the
Internet via another peer.
 
== DNS for the proxy client ==
 
You can use a secure DNS client such as knot dns resolver,
which comes with a set of authenticated dns servers ips
built in.
 
<syntaxhighlight lang="nix">
{
  # knot dns resolver
  services.kresd.enable = true;
 
  # disable built-in dns
  services.resolved.enable = false;
 
  environment.etc."resolv.conf" = {
    mode = "0644";
    text = "nameserver ::1";
  };
}
</syntaxhighlight>
 
= AllowedIPs =
 
Each peer can handle traffic destined for a certain IP range.
This range is called AllowedIP.
 
Common forms of allowed IPs include
 
* 192.168.26.9/32, a single internal IPv4 address
* 192.168.26.0/24, a subnet
* fd31:bf08:57cb::9/128, a single internal IPv6 address
* fd31:bf08:57cb::/60, a subnet
* 0.0.0.0/0, entire IPv4 address space, for proxying
* ::/0, entire IPv6 address space, for proxying
 
Notice that, in specifying its subnet mask, some configuration
modules can automatically configure network routes.
 
Allowed IPs should be unique to each peer.  If there are peers whose
allowed IPs overlap, traffic will only reach one of them.
 
= UDP Port =
 
The default port is 51820.  Some literature recommends changing this
port to circumvent blocking of WireGuard traffic.
 
WireGuard will choose a random port, if this option is not set.
 
= Generate keys =
 
WireGuard works with public-private key pairs.
 
Computer (peer) is identified by its public key. 
Only connections from peers with known public keys are accepted.
For this reason, you can not reuse keys on multiple peers.
 
To generate a private key, and derive the public key from it, you
need the <code>wg</code> utility, available in
<code>wireguard-tools</code> package.
 
After installation, use the following commands to generate keys:
 
<syntaxHighlight>
$ umask 077
$ wg genkey > privatekey
$ wg pubkey < privatekey > publickey
</syntaxHighlight>
</syntaxHighlight>


You can create as many keypairs as you like for different connections or roles; it is also possible to reuse the same keypair for every connection.
You need to generate a new key for each peer.
 
Make sure the private key has the correct file permission as required
by the WireGuard service. Wrong file permission may
cause the service to fail.  Check system log to rule out
this scenario.


Alternatively, you can use <tt>networking.wireguard.interfaces.[name].generatePrivateKeyFile</tt> option.
You can use ryamtm/agenix to declaratively store and manage the
WireGuard key.


If you decide to use files for storing your private keys and also use networkd, you'll need to modify the private key file permissions.
For systemd.network:
<syntaxHighlight>
  age.secrets.wg-key-vps = {
    file = "${inputs.self.outPath}/secrets/wg-key-vps.age";
    # for permission, see man systemd.netdev
    mode = "640";
    owner = "systemd-network";
    group = "systemd-network";
  };
</syntaxHighlight>


==== Troubleshooting Private Key File Resources ====
= systemd.network =


* https://discourse.nixos.org/t/wg0-failed-to-read-private-key/31461/8
Credit: this section is adapted from ArchWiki.
This section should fully support IPv4 and v6 dual stack.
 
== Peer setup ==


===Server setup===
Enable WireGuard on the server via <tt>/etc/nixos/configuration.nix</tt>:
<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
{
{
   ...
   age.secrets.wg-key-vps = {
    file = "${inputs.self.outPath}/secrets/wg-key-vps.age";
    # for permission, see man systemd.netdev
    mode = "640";
    owner = "systemd-network";
    group = "systemd-network";
  };
 
  networking.firewall.allowedUDPPorts = [ 51820 ];
 
  networking.useNetworkd = true;
 
  systemd.network = {
    enable = true;
 
    networks."50-wg0" = {
      matchConfig.Name = "wg0";


  # enable NAT
      address = [
  networking.nat.enable = true;
        # /32 and /128 specifies a single address
  networking.nat.externalInterface = "eth0";
        # for use on this wg peer machine
  networking.nat.internalInterfaces = [ "wg0" ];
        "fd31:bf08:57cb::7/128"
  networking.firewall = {
        "192.168.26.7/32"
     allowedUDPPorts = [ 51820 ];
      ];
  };
     };


  networking.wireguard.enable = true;
    netdevs."50-wg0" = {
  networking.wireguard.interfaces = {
      netdevConfig = {
    # "wg0" is the network interface name. You can name the interface arbitrarily.
        Kind = "wireguard";
    wg0 = {
        Name = "wg0";
       # Determines the IP address and subnet of the server's end of the tunnel interface.
       };
      ips = [ "10.100.0.1/24" ];


       # The port that WireGuard listens to. Must be accessible by the client.
       wireguardConfig = {
      listenPort = 51820;
        ListenPort = 51820;


      # This allows the wireguard server to route your traffic to the internet and hence be like a VPN
        PrivateKeyFile = config.age.secrets.wg-key-vps.path;
      # For this to work you have to set the dnsserver IP of your router (or dnsserver of choice) in your clients
      postSetup = ''
        ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o eth0 -j MASQUERADE
      '';


      # This undoes the above command
        # To automatically create routes for everything in AllowedIPs,
      postShutdown = ''
        # add RouteTable=main
         ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o eth0 -j MASQUERADE
         RouteTable = "main";
      '';


      # Path to the private key file.
        # FirewallMark marks all packets send and received by wg0
       #
        # with the number 42, which can be used to define policy rules on these packets.  
       # Note: The private key can also be included inline via the privateKey option,
        FirewallMark = 42;
      # but this makes the private key world-readable; thus, using privateKeyFile is
       };
      # recommended.
       wireguardPeers = [
      privateKeyFile = "path to private key file";
        {
          # laptop wg conf
          PublicKey = "ronr+8v670J0CPb0xT5QLGMWDfE7+1g7HmC6YMdCIDk=";
          AllowedIPs = [
            "fd31:bf08:57cb::9/128"
            "192.168.26.9/32"
          ];
          Endpoint = "192.168.1.26:51820";


      peers = [
           # RouteTable can also be set in wireguardPeers
        # List of allowed peers.
           # RouteTable in wireguardConfig will then be ignored.
        { # Feel free to give a meaning full name
           # RouteTable = 1000;
           # Public key of the peer (not a file path).
          publicKey = "{client public key}";
           # List of IPs assigned to this peer within the tunnel subnet. Used to configure routing.
           allowedIPs = [ "10.100.0.2/32" ];
        }
        { # John Doe
          publicKey = "{john doe's public key}";
          allowedIPs = [ "10.100.0.3/32" ];
         }
         }
       ];
       ];
     };
     };
   };
   };
  ...
 
}
}
</syntaxhighlight>
</syntaxhighlight>


===Client setup===
== Proxy server setup ==
 
Same as peer setup, skip the endpoint option, with the following
addition:
 
<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
{
{
   ...
   networking.nat = {
   networking.firewall = {
    enable = true;
     allowedUDPPorts = [ 51820 ]; # Clients and peers can use the same port, see listenport
    enableIPv6 = true;
    externalInterface = "ens6";
    internalInterfaces = [ "wg0" ];
  };
 
  systemd.network = {
    enable = true;
    networks."50-wg0" = {
      networkConfig = {
        # do not use IPMasquerade,
        # unnecessary, causes problems with host ipv6
        IPv4Forwarding = true;
        IPv6Forwarding = true;
      };
    };
   };
}
</syntaxhighlight>
 
== Proxy client setup ==
 
Same as peer setup, with the following addition:
 
=== Disable rpfilter ===
 
<syntaxhighlight lang="nix">
# NixOS firewall will block wg traffic because of rpfilter
networking.firewall.checkReversePath = "loose";
</syntaxhighlight>
 
=== Route DNS over wg0 ===
 
This applies to systemd-resolved:
<syntaxhighlight lang="nix">
  systemd.network = {
     networks."50-wg0" = {
      # only works with systemd-resolved
      domains = [ "~." ];
      dns = [ "{proxy server internal ip}" ];
      networkConfig = {
        DNSDefaultRoute = true;
      };
    };
  };
</syntaxhighlight>
Note: Routing all DNS over WireGuard (i.e. Domains=~.) will prevent the DNS resolution of endpoints. Unless the peer domain is configured to be resolved on a specific network link.
 
To use a peer as a DNS server, specify its WireGuard tunnel's IP address(es) in the .network file using the DNS= option. For search domains use the Domains= option.
 
To use a peer as the only DNS server set DNSDefaultRoute=true and Domains=~. in the [Network] section of .network file's.
 
=== Route all traffic over wg0, except endpoint ===
<syntaxhighlight lang="nix">
  systemd.network = {
    netdevs."50-wg0" = {
      # FirewallMark simply marks all packets send and received by this wireguard
      # interface with the number 42, which can be used to define policy rules on these packets.
      wireguardConfig.FirewallMark = 42;
 
      wireguardPeers = [
        {
          AllowedIPs = [
            # proxy all traffic
            "::/0"
            "0.0.0.0/0"
          ];
          # can't use domain
          # Routing all DNS over WireGuard (i.e. Domains=~.) will prevent the DNS resolution of endpoints.
          Endpoint = "[2a01::1]:51820";
 
          # RouteTable line specifies that a new routing table with id 1000 is created
          # for the wireguard interface, and no rules are set on the main routing table.
          RouteTable = 1000;
        }
      ];
    };
    networks."50-wg0" = {
      routingPolicyRules = [
        # rule 1: redirect traffic
        {
          # apply rule to both v4 and v6
          Family = "both";
 
          # For all packets *not* marked with 42 (i.e. all non-wireguard/normal traffic),
          InvertRule = true;
          FirewallMark = 42;
 
          # we specify that the routing table 1000 must be used
          # (which is the wireguard routing table). This rule routes all traffic through wireguard.
          # inside routingPolicyRules section is called Table, not RouteTable
          Table = 1000;
 
          # this routing policy rule has a lower priority (10) than
          # endpoint exclusion rule (5).
          Priority = 10;
        }
 
 
        # rule 2: exclude endpoint ip
        {
          # Use a routing policy rule to exclude the endpoint IP address,
          # so that wireguard can still connect to it.
          # it has a higher priority (5) than (10).
 
          # We exempt our endpoint with a higher priority by routing it
          # through the main table (Table=main is default).
          To = "2a01::1/128";
          Priority = 5;
        }
      ];
    };
   };
   };
  # Enable WireGuard
</syntaxhighlight>
   networking.wireguard.enable = true;
 
   networking.wireguard.interfaces = {
=== Exempting specific addresses ===
     # "wg0" is the network interface name. You can name the interface arbitrarily.
 
    wg0 = {
In order to exempt specific addresses (such as private LAN addresses) from routing over the WireGuard tunnel, add them to another RoutingPolicyRule with higher priority.
       # Determines the IP address and subnet of the client's end of the tunnel interface.
 
       ips = [ "10.100.0.2/24" ];
<syntaxhighlight lang="nix">
       listenPort = 51820; # to match firewall allowedUDPPorts (without this wg uses random port numbers)
   systemd.network.networks."50-wg0".routingPolicyRules =  
   [
    {
      To = "192.168.0.0/24";
      Priority = 9;
     }
  ]
</syntaxhighlight>
 
=== Manually start and stop wg0 ===
 
The above steps will set up a <tt>wg0</tt> interface, managed by networkctl command.
 
You can start it by typing the following in your terminal:
 
<syntaxHighlight lang="sh">
sudo networkctl up wg0
</syntaxHighlight>
 
To stop the service:
 
<syntaxHighlight lang="sh">
sudo networkctl down wg0
</syntaxHighlight>
 
=== Route for specific user ===
 
It may be desirable to route WAN traffic over the tunnel only for a specific user, for example, the transmission user in order to use the tunnel for torrent traffic.
 
Replace catch-all rules above, with user-specific rules below.
 
<syntaxhighlight lang="nix">
  systemd.network.networks."50-wg0".routingPolicyRules =  
  [
    {
       # The lower priority rule (30001), matches all traffic generated
      # by the transmission user and routes it through table 1000 which is the wireguard table.  
       Table = 1000;
      User = "transmission";
       Priority = 30001;
      Family = "both";
    }


       # Path to the private key file.
    {
       # The higher priority rule (30000), matches all traffic
      # generated by the transmission user
      # and routes it through the main table (no wireguard)
      # BUT only using rules with a prefix length larger than 0.
      #
      # This means the default 0.0.0.0/0 and ::/0 rules still apply
       #
       #
       # Note: The private key can also be included inline via the privateKey option,
       # Therefore, only traffic matching specific rules with non-zero prefix
       # but this makes the private key world-readable; thus, using privateKeyFile is
       # (such as those defining the subnet of your local home network) of the main table
       # recommended.
       # are routed through the main table.  
      privateKeyFile = "path to private key file";


       peers = [
       Table = "main";
        # For a client configuration, one peer entry for the server will suffice.
      User = "transmission";
      SuppressPrefixLength = 0;
      Priority = 30000;
      Family = "both";
    }
  ]
</syntaxhighlight>
 
== Test and Troubleshooting ==
 
Test the proxy with
 
# ipv4
$ curl -4 zx2c4.com/ip
# ipv6
$ curl -6 zx2c4.com/ip
 
Check systemd-networkd log for any error and warning messages.
 
$ journalctl -u systemd-networkd.service
 
Invoke <code>wg</code> command from <code>wireguard-tools</code>.
 
Use <code>ip route</code> to inspect the route table
 
$ ip route show table 1000
default dev wg0 proto static scope link
 
$ ip route show table all
... many entries ...
 
$ ip rule list
10: not from all fwmark 0x2a lookup 1000 proto static
 
$ ip route get  136.144.57.121
136.144.57.121 dev wg0 table 1000 src 192.168.26.9 uid 1000


        {
$ ip route get 2600:1406::1
          # Public key of the server (not a file path).
2600:1406::1 from :: dev wg0 table 1000 proto static src fd31:bf08:57cb::9 metric 1024 pref medium
          publicKey = "{server public key}";


          # Forward all the traffic via VPN.
= wg-quick =
          allowedIPs = [ "0.0.0.0/0" ];
          # Or forward only particular subnets
          #allowedIPs = [ "10.100.0.1" "91.108.12.0/22" ];


          # Set this to the server IP and port.
== Peer setup ==
          endpoint = "{server ip}:51820"; # ToDo: route to endpoint not automatically configured https://wiki.archlinux.org/index.php/WireGuard#Loop_routing https://discourse.nixos.org/t/solved-minimal-firewall-setup-for-wireguard-client/7577


           # Send keepalives every 25 seconds. Important to keep NAT tables alive.
<syntaxhighlight lang="nix">
           persistentKeepalive = 25;
{
  networking.wg-quick.interfaces = {
    wg0 = {
      address = [
        "fd31:bf08:57cb::9/128"
        "192.168.26.9/32"
      ];
      # use dnscrypt, or proxy dns as described above
      dns = [ "127.0.0.1" ];
      privateKeyFile = config.age.secrets.wg-key-laptop.path;
      peers = [
        {
           # bt wg conf
          publicKey = "ejmbag/fcc9OLp8K62zfV0NCbp056DnA0qpNixLXwCo=";
          allowedIPs = [
            "fd31:bf08:57cb::8/128"
            "192.168.26.8/32"
          ];
           endpoint = "192.168.1.56:51820";
         }
         }
       ];
       ];
     };
     };
   };
   };
  ...
}
}
</syntaxhighlight>
</syntaxhighlight>


Multiple connections can be configured by configuring multiple interfaces under {{nixos:option|networking.wireguard.interfaces}}.
== Proxy server setup ==


==Setting up WireGuard server/client with wg-quick and dnsmasq==
Same as peer setup, skip the endpoint option, with the following
===Server setup===
addition:
DNS requires opening TCP/UDP port 53.
 
<syntaxHighlight lang="nix">
<syntaxhighlight lang="nix">
{
{
  ...
   # enable NAT
   # Enable NAT
   networking.nat = {
   networking.nat = {
     enable = true;
     enable = true;
     enableIPv6 = true;
     enableIPv6 = true;
     externalInterface = "eth0";
     externalInterface = "ens6";
     internalInterfaces = [ "wg0" ];
     internalInterfaces = [ "wg0" ];
   };
   };
  # Open ports in the firewall
  networking.firewall = {
    allowedTCPPorts = [ 53 ];
    allowedUDPPorts = [ 53 51820 ];
  };
  ...
}
</syntaxHighlight>


The wg-quick setup is similar to the previous setup.
<syntaxHighlight lang="nix">
{
  ...
   networking.wg-quick.interfaces = {
   networking.wg-quick.interfaces = {
    # "wg0" is the network interface name. You can name the interface arbitrarily.
     wg0 = {
     wg0 = {
      # Determines the IP/IPv6 address and subnet of the client's end of the tunnel interface
      address = [ "10.0.0.1/24" "fdc9:281f:04d7:9ee9::1/64" ];
      # The port that WireGuard listens to - recommended that this be changed from default
      listenPort = 51820;
      # Path to the server's private key
      privateKeyFile = "/root/wireguard-keys/privatekey";
       # This allows the wireguard server to route your traffic to the internet and hence be like a VPN
       # This allows the wireguard server to route your traffic to the internet and hence be like a VPN
       postUp = ''
       postUp = ''
Line 186: Line 484:
         ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE
         ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE
       '';
       '';
      peers = [
        { # peer0
          publicKey = "{client public key}";
          presharedKeyFile = "/root/wireguard-keys/preshared_from_peer0_key";
          allowedIPs = [ "10.0.0.2/32" "fdc9:281f:04d7:9ee9::2/128" ];
        }
        # More peers can be added here.
      ];
     };
     };
   };
   };
  ...
}
}
</syntaxHighlight>
</syntaxhighlight>
 
== Proxy client setup ==
 
Same as peer setup, specify proxy server ip or domain in the endpoint
option.  Use <code>[ "0.0.0.0/0" "::/0" ]</code> as allowed IPs.
 
Optionally, configure proxy server as DNS server as described above.
 
=== Proxy DNS with dnsmasq ===
 
You can also use the proxy server as DNS server with
dnsmasq.


To enable dnsmasq and only serve DNS requests to the WireGuard interface add the following:
<syntaxhighlight lang="nix">
<syntaxHighlight lang="nix">
{
{
   ...
   networking.firewall = {
    allowedTCPPorts = [ 53 ];
    allowedUDPPorts = [ 53 ];
  };
   services = {
   services = {
    ...
     dnsmasq = {
     dnsmasq = {
       enable = true;
       enable = true;
       extraConfig = ''
       settings.interface = "wg0";
        interface=wg0
      '';
     };
     };
    ...
   };
   };
  ...
}
}
</syntaxHighlight>
</syntaxhighlight>
 
For wg-quick peer, use the
following option


===Client setup===
<syntaxhighlight lang="nix">
The client will now point DNS to the server.
<syntaxHighlight lang="nix">
{
{
  ...
   networking.wg-quick.interfaces.wg0.dns =
   networking.wg-quick.interfaces = {
  [ {internal v4 & v6 ip addr of server} ];
    wg0 = {
      address = [ "10.0.0.2/24" "fdc9:281f:04d7:9ee9::2/64" ];
      dns = [ "10.0.0.1" "fdc9:281f:04d7:9ee9::1" ];
      privateKeyFile = "/root/wireguard-keys/privatekey";
     
      peers = [
        {
          publicKey = "{server public key}";
          presharedKeyFile = "/root/wireguard-keys/preshared_from_peer0_key";
          allowedIPs = [ "0.0.0.0/0" "::/0" ];
          endpoint = "{server ip}:51820";
          persistentKeepalive = 25;
        }
      ];
    };
  };
  ...
}
}
</syntaxhighlight>
== Manually start and stop wg-quick ==
The above steps will set up a <tt>wg-quick-wg0.service</tt> systemd unit.
You can start it by typing the following in your terminal:
<syntaxHighlight lang="sh">
sudo systemctl start wg-quick-wg0.service
</syntaxHighlight>
To stop the service:
<syntaxHighlight lang="sh">
sudo systemctl stop wg-quick-wg0.service
</syntaxHighlight>
</syntaxHighlight>


== Reuse existing wg-quick config file ==


===Client setup (non-declaratively)===
If you have WireGuard configuration files that you want to use as-is
If you have WireGuard configuration files that you want to use as-is (similarly how you would [https://wiki.debian.org/WireGuard#Step_2_-_Configuration configure WireGuard e.g. in Debian], without converting them to a declarative NixOS configuration, you can also configure <code>wg-quick</code> to use them. For example, if you have a configuration file <code>/etc/nixos/wireguard/wg0.conf</code>, add the following line to your <code>configuration.nix</code>:
(similarly how you would
[https://wiki.debian.org/WireGuard#Step_2_-_Configuration configure
WireGuard e.g. in Debian], without converting them to a declarative
NixOS configuration, you can also configure <code>wg-quick</code> to
use them. For example, if you have a configuration file
<code>/etc/nixos/wireguard/wg0.conf</code>, add the following line to
your <code>configuration.nix</code>:


<syntaxHighlight lang="nix">
<syntaxHighlight lang="nix">
Line 255: Line 559:
This will set up a <code>wg-quick-wg0.service</code> systemd unit.
This will set up a <code>wg-quick-wg0.service</code> systemd unit.


==Setting up WireGuard with systemd-networkd==
= networking.wireguard =
 
Note: does not automatically configure routes, see comments.


===Server setup===
== Peer setup ==


<syntaxHighlight lang="nix">
<syntaxhighlight lang="nix">
{ config, ... }:
{
{
   config,
   age.secrets.wg-key-peer0 = {
  pkgs,
    file = "./secrets/wg-key-peer0.age";
  lib,
  };
  ...
 
}: {
   networking.firewall.allowedUDPPorts = [ 51820 ];
   networking.firewall.allowedUDPPorts = [51820];
 
   networking.useNetworkd = true; 
   networking.wireguard = {
  systemd.network = {
     enable = true;
     enable = true;
     netdevs = {
     interfaces = {
       "50-wg0" = {
       # network interface name.
         netdevConfig = {
      # You can name the interface arbitrarily.
          Kind = "wireguard";
      wg0 = {
          Name = "wg0";
         # the IP address and subnet of this peer
          MTUBytes = "1300";
        ips = [ "fd31:bf08:57cb::9/128" "192.168.26.9/32" ];
         };
 
         wireguardConfig = {
        # WireGuard Port
          PrivateKeyFile = "/run/keys/wireguard-privkey";
        # Must be accessible by peers
          ListenPort = 51820;
        listenPort = 51820;
          RouteTable = "main"; # wg-quick creates routing entries automatically but we must use use this option in systemd.
 
        };
        # Path to the private key file.
         wireguardPeers = [
         #
           {
         # Note: can also be included inline via the privateKey option,
             PublicKey = "L4msD0mEG2ctKDtaMJW2y3cs1fT2LBRVV7iVlWZ2nZc=";
        # but this makes the private key world-readable;
             AllowedIPs = ["10.100.0.2"];
        # using privateKeyFile is recommended.
        privateKeyFile = config.age.secrets.wg-key-laptop.path;
 
         peers = [
           {  
             name = "home nas";
            publicKey = "ejmbag/fcc9OLp8K62zfV0NCbp056DnA0qpNixLXwCo=";
             allowedIPs = [
              "fd31:bf08:57cb::8/128"
              "192.168.26.8/32"
            ];
            endpoint = "192.168.1.56:51820";
            #  ToDo: route to endpoint not automatically configured
            # https://wiki.archlinux.org/index.php/WireGuard#Loop_routing
            # https://discourse.nixos.org/t/solved-minimal-firewall-setup-for-wireguard-client/7577
            # Send keepalives every 25 seconds. Important to keep NAT tables alive.
            # persistentKeepalive = 25;
           }
           }
         ];
         ];
       };
       };
     };
     };
    networks.wg0 = {
      matchConfig.Name = "wg0";
      address = ["10.100.0.1/24"];
      networkConfig = {
        IPMasquerade = "ipv4";
        IPForward = true;
      };
    };
  };
}
}
</syntaxHighlight>
# it’s not imperative but it does not know how to do it :
# sudo ip route add 11.111.11.111 via 192.168.1.11 dev wlo1
# the ip adresse 11: external and 192: local.
</syntaxhighlight>
 
== Proxy server setup ==


===Client setup===
Same as peer setup, skip the endpoint option, with the following
addition, Remember to update the internal IP addresses in the script:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
{
{
   config,
   # enable NAT
   pkgs,
   networking.nat = {
  lib,
  ...
}: {
  boot.kernelModules = [ "wireguard" ];
  systemd.network = {
     enable = true;
     enable = true;
     netdevs = {
     enableIPv6 = true;
      "10-wg0" = {
    externalInterface = "ens6";
        netdevConfig = {
    internalInterfaces = [ "wg0" ];
          Kind = "wireguard";
  };
          Name = "wg0";
 
          MTUBytes = "1300";
  networking.wireguard.interfaces.wg0 = {
        };
      # This allows the wireguard server to route your traffic to the internet and hence be like a VPN
        # See also man systemd.netdev (also contains info on the permissions of the key files)
      postSetup = ''
        wireguardConfig = {
        ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT
          # Don't use a file from the Nix store as these are world readable. Must be readable by the systemd-network user
         ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.0.0.1/24 -o eth0 -j MASQUERADE
          PrivateKeyFile = "/run/keys/wireguard-privkey";
        ${pkgs.iptables}/bin/ip6tables -A FORWARD -i wg0 -j ACCEPT
          ListenPort = 9918;
         ${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE
         };
       '';
        wireguardPeers = [         
 
          # configuration since nixos-unstable/nixos-24.11
       # Undo the above
          {
       postShutdown = ''
            PublicKey = "OhApdFoOYnKesRVpnYRqwk3pdM247j8PPVH5K7aIKX0=";
         ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT
            AllowedIPs = ["fc00::1/64" "10.100.0.1"];
         ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.0.0.1/24 -o eth0 -j MASQUERADE
            Endpoint = "{set this to the server ip}:51820";
        ${pkgs.iptables}/bin/ip6tables -D FORWARD -i wg0 -j ACCEPT
          }
        ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE
         ];
       '';
      };
    };
    networks.wg0 = {
      # See also man systemd.network
       matchConfig.Name = "wg0";
       # IP addresses the client interface will have
       address = [
         "fe80::3/64"
         "fc00::3/120"
        "10.100.0.2/24"
      ];
      DHCP = "no";
      dns = ["fc00::53"];
      ntp = ["fc00::123"];
      gateway = [
        "fc00::1"
        "10.100.0.1"
       ];
      networkConfig = {
        IPv6AcceptRA = false;
      };
    };
   };
   };
}
}
</syntaxhighlight>


</syntaxhighlight>
== Proxy client setup ==
 
Same as peer setup, specify proxy server ip or domain in the endpoint
option.  Use <code>[ "0.0.0.0/0" "::/0" ]</code> as allowed IPs.
 
 
= NetworkManager Proxy client setup =


==Setting up WireGuard with NetworkManager==
This is probably only useful on clients. Functionality is present in NetworkManager since version 1.20 but network-manager-applet can show and control wireguard connections since version 1.22 only (available since NixOS 21.05).
This is probably only useful on clients. Functionality is present in NetworkManager since version 1.20 but network-manager-applet can show and control wireguard connections since version 1.22 only (available since NixOS 21.05).


Line 415: Line 713:
{{Commands|nmcli connection import type wireguard file thefile.conf}}
{{Commands|nmcli connection import type wireguard file thefile.conf}}


The new VPN connection should be available, you still have to click on it to activate it.
The new VPN connection should be available, you still have to click on
it to activate it.
 


=Troubleshooting=
=Troubleshooting=
Line 448: Line 748:


</syntaxHighlight>
</syntaxHighlight>
== Server is reachable, but only some services are working==
It might be, that the [https://en.wikipedia.org/wiki/Maximum_transmission_unit MTU] of the network connecting the endpoints is smaller than the default (1500). By default the "option is set to" 1420, with an additional 80 due to wireguard overhead. Try adjusting it to something smaller:
<syntaxHighlight lang="nix">
networking.wireguard.interfaces.wg0.mtu = 1000;
#this is extremely small, bigger values can yield better performance.
#networking.wg-quick.interfaces.wg0.mtu = 1000; #if you use wq-quick
</syntaxHighlight>
== wg-quick issues with NetworkManager ==
Try <code>systemd-resolved</code>
This fixed the issue of wg connecting to the peer but not being able to access the internet or LAN.
<syntaxhighlight lang="nix">
networking.networkmanager.dns = "systemd-resolved";
services.resolved.enable = true;
</syntaxhighlight>


=See also=
=See also=
Line 456: Line 775:
* [https://www.youtube.com/watch?v=us7V2NvsQRA Talk by @fpletz at NixCon 2018 about networkd and his WireGuard setup]
* [https://www.youtube.com/watch?v=us7V2NvsQRA Talk by @fpletz at NixCon 2018 about networkd and his WireGuard setup]
* [https://web.archive.org/web/20210101230654/https://www.the-digital-life.com/wiki/wireguard-troubleshooting/ WireGuard Troubleshooting (on Web Archive)] shows how to enable debug logs
* [https://web.archive.org/web/20210101230654/https://www.the-digital-life.com/wiki/wireguard-troubleshooting/ WireGuard Troubleshooting (on Web Archive)] shows how to enable debug logs
= Additional routing setups =
For documentation on more routing and topology setups, such as
* Point to Point Configuration,
* Hub and Spoke Configuration,
* Point to Site Configuration,
* Site to Site Configuration,
see [https://docs.procustodibus.com/guide/wireguard/ Pro Custodibus Documentation], [https://web.archive.org/web/20250920231827/https://docs.procustodibus.com/guide/wireguard/ Mirror on Internet Archive].


[[Category:Networking]]
[[Category:Networking]]
[[Category:VPN]]