main
 1{
 2  config,
 3  lib,
 4  pkgs,
 5  ...
 6}:
 7let
 8  inherit (lib)
 9    mkEnableOption
10    mkIf
11    mkOption
12    types
13    ;
14  cfg = config.services.wireguard.server;
15
16  # Detect if nftables is enabled
17  usingNftables = config.networking.nftables.enable;
18in
19{
20  options = {
21    services.wireguard.server = {
22      enable = mkEnableOption "Enable a wireguard server";
23      ips = mkOption {
24        type = with types; listOf str;
25        description = ''
26          The peer IPs
27        '';
28      };
29      peers = mkOption {
30        default = [ ];
31        description = "Peers linked to the interface.";
32        type = with types; listOf anything;
33      };
34      mtu = mkOption {
35        type = with types; nullOr int;
36        default = 1420;
37        description = ''
38          MTU size for the WireGuard interface.
39          Common values: 1420 (conservative), 1380 (for PPPoE).
40          If null, uses system default.
41        '';
42      };
43    };
44  };
45  config = mkIf cfg.enable {
46    environment.systemPackages = [ pkgs.wireguard-tools ];
47    boot.kernel.sysctl."net.ipv4.ip_forward" = lib.mkForce 1; # FIXME should probably be mkDefault
48
49    # Firewall configuration - supports both iptables and nftables
50    networking.firewall = {
51      allowedUDPPorts = [ 51820 ];
52      trustedInterfaces = [ "wg0" ];
53
54      # iptables rules (used when nftables is disabled)
55      extraCommands = mkIf (!usingNftables) ''
56        iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -j MASQUERADE
57        iptables -A FORWARD -i wg+ -j ACCEPT
58      '';
59    };
60
61    # nftables rules (used when nftables is enabled)
62    networking.nftables.tables = mkIf usingNftables {
63      wireguard-nat = {
64        family = "ip";
65        content = ''
66          chain postrouting {
67            type nat hook postrouting priority srcnat; policy accept;
68            ip saddr 10.100.0.0/24 masquerade
69          }
70
71          chain forward {
72            type filter hook forward priority filter; policy accept;
73            iifname "wg*" accept
74          }
75        '';
76      };
77    };
78
79    networking.wireguard.enable = true;
80    networking.wireguard.interfaces = {
81      "wg0" = {
82        inherit (cfg) ips peers;
83        listenPort = 51820;
84        privateKeyFile = "/etc/wireguard/private.key";
85      }
86      // lib.optionalAttrs (cfg.mtu != null) { inherit (cfg) mtu; };
87    };
88  };
89}