diff options
| author | Mel <mel@rnrd.eu> | 2026-05-01 18:40:37 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2026-05-01 18:40:37 +0200 |
| commit | a4ab740d07706d86503b84d36addcbbbf7a4944b (patch) | |
| tree | 24c52a29b9a3182149db37e332bee3af9b9f6014 /modules/foundation/vpn.nix | |
| parent | c9f2260dc0414d451d551f8ffdf1f573e7be41ff (diff) | |
| download | network-a4ab740d07706d86503b84d36addcbbbf7a4944b.tar.zst network-a4ab740d07706d86503b84d36addcbbbf7a4944b.zip | |
Re-add simple VPN and simplify module with shared users with tunnel
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'modules/foundation/vpn.nix')
| -rw-r--r-- | modules/foundation/vpn.nix | 90 |
1 files changed, 90 insertions, 0 deletions
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 + } + ''; + }; + }; +} |
