From a4ab740d07706d86503b84d36addcbbbf7a4944b Mon Sep 17 00:00:00 2001 From: Mel Date: Fri, 1 May 2026 18:40:37 +0200 Subject: Re-add simple VPN and simplify module with shared users with tunnel Signed-off-by: Mel --- modules/foundation/vpn.nix | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 modules/foundation/vpn.nix (limited to 'modules/foundation/vpn.nix') diff --git a/modules/foundation/vpn.nix b/modules/foundation/vpn.nix new file mode 100644 index 0000000..1a7524d --- /dev/null +++ b/modules/foundation/vpn.nix @@ -0,0 +1,90 @@ +{ + config, + lib, + ... +}: + +let + inherit (lib) + mkEnableOption + mkOption + types + mkIf + attrValues + replaceString + ; + + cfg = config.foundation.vpn; + + inherit (import ../../assets/vpn.nix) users; + + interface = "vpn0"; + port = 51820; + + # while the tunnel uses the lower subnets for the paths, + # the vpn always uses subnet number 10. + subnetIndex = 10; + + addressFromTemplate = + template: prefix: "${replaceString "X" (toString subnetIndex) template}/${toString prefix}"; +in +{ + options.foundation.vpn = { + enable = mkEnableOption "WireGuard VPN server"; + + externalInterface = mkOption { + type = types.str; + description = "External network interface"; + }; + }; + + config = mkIf cfg.enable { + age.secrets.wg-private-key = { + file = ../../secrets/wg-private-key.age; + owner = "systemd-network"; + }; + + networking.firewall.allowedUDPPorts = [ port ]; + + systemd.network = { + netdevs."30-${interface}" = { + netdevConfig = { + Kind = "wireguard"; + Name = interface; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.wg-private-key.path; + ListenPort = port; + }; + wireguardPeers = map (user: { + PublicKey = user.key; + AllowedIPs = [ (addressFromTemplate user.ip 32) ]; + }) (attrValues users); + }; + + networks."30-${interface}" = { + name = interface; + address = [ (addressFromTemplate "10.123.X.1" 24) ]; + linkConfig = { + RequiredForOnline = "no"; + }; + }; + }; + + networking.nftables.tables.vpn-nat = { + family = "ip"; + content = '' + chain postrouting { + type nat hook postrouting priority srcnat; policy accept; + iifname "${interface}" oifname "${cfg.externalInterface}" masquerade + } + + chain forward { + type filter hook forward priority 0; policy accept; + iifname "${interface}" oifname "${cfg.externalInterface}" accept + iifname "${cfg.externalInterface}" oifname "${interface}" ct state established,related accept + } + ''; + }; + }; +} -- cgit 1.4.1