WireGuard: Difference between revisions
→Route all traffic over wg0, except endpoint: fix routetable name |
→Route for specific user: add port forwading |
||
(17 intermediate revisions by the same user not shown) | |||
Line 15: | Line 15: | ||
traffic on a per user basis. For example, you can route all torrenting traffic | traffic on a per user basis. For example, you can route all torrenting traffic | ||
through a wireguard tunnel, see below. | 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 = | = Use cases = | ||
Line 25: | Line 32: | ||
Internet via another peer. | Internet via another peer. | ||
== DNS for the proxy client == | == Secure 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 | |||
You can use | built in. | ||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
Line 46: | Line 53: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Secure DNS hinders usage of captive portals. See [[systemd-resolved]] for solutions. | |||
= AllowedIPs = | = AllowedIPs = | ||
Line 145: | Line 123: | ||
</syntaxHighlight> | </syntaxHighlight> | ||
= | = systemd.network = | ||
Credit: this section is adapted from ArchWiki. | |||
This section should fully support IPv4 and v6 dual stack. | |||
== Peer setup == | == Peer setup == | ||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
{ | { | ||
age.secrets.wg-key- | age.secrets.wg-key-vps = { | ||
file = "./secrets/wg-key- | 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.firewall.allowedUDPPorts = [ 51820 ]; | ||
networking. | networking.useNetworkd = true; | ||
systemd.network = { | |||
enable = true; | enable = true; | ||
# | networks."50-wg0" = { | ||
# | matchConfig.Name = "wg0"; | ||
address = [ | |||
# /32 and /128 specifies a single address | |||
# for use on this wg peer machine | |||
"fd31:bf08:57cb::7/128" | |||
"192.168.26.7/32" | |||
]; | |||
}; | |||
netdevs."50-wg0" = { | |||
netdevConfig = { | |||
Kind = "wireguard"; | |||
Name = "wg0"; | |||
}; | |||
wireguardConfig = { | |||
ListenPort = 51820; | |||
PrivateKeyFile = config.age.secrets.wg-key-vps.path; | |||
# | # To automatically create routes for everything in AllowedIPs, | ||
# add RouteTable=main | |||
RouteTable = "main"; | |||
# | |||
# FirewallMark marks all packets send and received by wg0 | |||
# with the number 42, which can be used to define policy rules on these packets. | |||
FirewallMark = 42; | |||
}; | }; | ||
wireguardPeers = [ | |||
{ | |||
# laptop wg conf | |||
PublicKey = "ronr+8v670J0CPb0xT5QLGMWDfE7+1g7HmC6YMdCIDk="; | |||
AllowedIPs = [ | |||
"fd31:bf08:57cb::9/128" | |||
"192.168.26.9/32" | |||
]; | |||
Endpoint = "192.168.1.26:51820"; | |||
# RouteTable can also be set in wireguardPeers | |||
# RouteTable in wireguardConfig will then be ignored. | |||
# RouteTable = 1000; | |||
} | |||
]; | |||
}; | }; | ||
}; | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 207: | Line 201: | ||
Same as peer setup, skip the endpoint option, with the following | Same as peer setup, skip the endpoint option, with the following | ||
addition | addition: | ||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
{ | { | ||
networking.nat = { | networking.nat = { | ||
enable = true; | enable = true; | ||
Line 219: | Line 212: | ||
}; | }; | ||
systemd.network = { | |||
enable = true; | |||
networks."50-wg0" = { | |||
networkConfig = { | |||
# do not use IPMasquerade, | |||
# unnecessary, causes problems with host ipv6 | |||
IPv4Forwarding = true; | |||
IPv6Forwarding = true; | |||
}; | |||
}; | |||
}; | }; | ||
} | } | ||
Line 241: | Line 228: | ||
== Proxy client setup == | == Proxy client setup == | ||
Same as peer 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; | |||
# (... continued) 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; | |||
} | |||
]; | |||
}; | |||
}; | |||
</syntaxhighlight> | |||
=== Exempting specific addresses === | |||
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. | |||
<syntaxhighlight lang="nix"> | |||
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"; | |||
} | |||
{ | |||
# 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 | |||
# | |||
# Therefore, only traffic matching specific rules with non-zero prefix | |||
# (such as those defining the subnet of your local home network) of the main table | |||
# are routed through the main table. | |||
Table = "main"; | |||
User = "transmission"; | |||
SuppressPrefixLength = 0; | |||
Priority = 30000; | |||
Family = "both"; | |||
} | |||
]; | |||
# Configure port forwarding for Transmission under NAT | |||
networking.nat.forwardPorts = | |||
[ | |||
{ | |||
destination = "10.0.0.1:80"; | |||
proto = "tcp"; | |||
sourcePort = 8080; | |||
} | |||
{ | |||
destination = "[fc00::2]:80"; | |||
proto = "tcp"; | |||
sourcePort = 8080; | |||
} | |||
]; | |||
</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 | |||
2600:1406::1 from :: dev wg0 table 1000 proto static src fd31:bf08:57cb::9 metric 1024 pref medium | |||
= wg-quick = | = wg-quick = | ||
Line 318: | Line 511: | ||
Optionally, configure proxy server as DNS server as described above. | 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. | |||
<syntaxhighlight lang="nix"> | |||
{ | |||
networking.firewall = { | |||
allowedTCPPorts = [ 53 ]; | |||
allowedUDPPorts = [ 53 ]; | |||
}; | |||
services = { | |||
dnsmasq = { | |||
enable = true; | |||
settings.interface = "wg0"; | |||
}; | |||
}; | |||
} | |||
</syntaxhighlight> | |||
For wg-quick peer, use the | |||
following option | |||
<syntaxhighlight lang="nix"> | |||
{ | |||
networking.wg-quick.interfaces.wg0.dns = | |||
[ {internal v4 & v6 ip addr of server} ]; | |||
} | |||
</syntaxhighlight> | |||
== Manually start and stop wg-quick == | == Manually start and stop wg-quick == | ||
Line 352: | Line 575: | ||
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. | ||
= | = networking.wireguard = | ||
Note: does not automatically configure routes, see comments. | |||
== Peer setup == | == Peer setup == | ||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
{ config, ... }: | |||
{ | { | ||
age.secrets.wg-key- | age.secrets.wg-key-peer0 = { | ||
file = " | file = "./secrets/wg-key-peer0.age"; | ||
}; | }; | ||
networking.firewall.allowedUDPPorts = [ 51820 ]; | networking.firewall.allowedUDPPorts = [ 51820 ]; | ||
networking. | networking.wireguard = { | ||
enable = true; | enable = true; | ||
interfaces = { | |||
# network interface name. | |||
# You can name the interface arbitrarily. | |||
wg0 = { | |||
# the IP address and subnet of this peer | |||
ips = [ "fd31:bf08:57cb::9/128" "192.168.26.9/32" ]; | |||
# WireGuard Port | |||
# Must be accessible by peers | |||
listenPort = 51820; | |||
# Path to the private key file. | |||
# | # | ||
# | # Note: can also be included inline via the privateKey option, | ||
# but this makes the private key world-readable; | |||
# 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; | |||
} | |||
]; | |||
}; | }; | ||
}; | }; | ||
} | } | ||
# 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> | </syntaxhighlight> | ||
Line 429: | Line 637: | ||
Same as peer setup, skip the endpoint option, with the following | Same as peer setup, skip the endpoint option, with the following | ||
addition: | addition, Remember to update the internal IP addresses in the script: | ||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
{ | { | ||
# enable NAT | |||
networking.nat = { | networking.nat = { | ||
enable = true; | enable = true; | ||
Line 440: | Line 649: | ||
}; | }; | ||
networking.wireguard.interfaces.wg0 = { | |||
# This allows the wireguard server to route your traffic to the internet and hence be like a VPN | |||
postSetup = '' | |||
${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT | |||
# | ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.0.0.1/24 -o eth0 -j MASQUERADE | ||
${pkgs.iptables}/bin/ip6tables -A FORWARD -i wg0 -j ACCEPT | |||
${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE | |||
''; | |||
# Undo the above | |||
postShutdown = '' | |||
${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT | |||
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.0.0.1/24 -o eth0 -j MASQUERADE | |||
${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 | |||
''; | |||
}; | }; | ||
} | } | ||
Line 456: | Line 671: | ||
== Proxy client setup == | == Proxy client setup == | ||
Same as peer 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 = | = NetworkManager Proxy client setup = | ||
Line 663: | Line 791: | ||
* [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]] | [[Category:VPN]] |