about summary refs log tree commit diff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/acme.nix13
-rw-r--r--modules/chromium.nix3
-rw-r--r--modules/common/ark.nix13
-rw-r--r--modules/common/home-manager.nix13
-rw-r--r--modules/common/networking.nix132
-rw-r--r--modules/common/nix.nix8
-rw-r--r--modules/common/secrets.nix16
-rw-r--r--modules/common/stylix.nix13
-rw-r--r--modules/common/users.nix13
-rw-r--r--modules/emacs/default.nix5
-rw-r--r--modules/firefox/default.nix1
-rw-r--r--modules/hyprland.nix12
-rw-r--r--modules/ipfs.nix3
-rw-r--r--modules/password-store.nix3
-rw-r--r--modules/plausible.nix12
-rw-r--r--modules/profiles/dev/default.nix3
-rw-r--r--modules/syncthing.nix6
-rw-r--r--modules/unbound-ng.nix185
-rw-r--r--modules/unbound.nix20
-rw-r--r--modules/wireguard-ng.nix255
-rw-r--r--modules/wireguard.nix22
21 files changed, 623 insertions, 128 deletions
diff --git a/modules/acme.nix b/modules/acme.nix
index 6a75818..9a2f3f1 100644
--- a/modules/acme.nix
+++ b/modules/acme.nix
@@ -5,11 +5,14 @@ let
 in
 {
   imports = [
-    (mkAliasOptionModule [ "certs" ] [
-      "security"
-      "acme"
-      "certs"
-    ])
+    (mkAliasOptionModule
+      [ "certs" ]
+      [
+        "security"
+        "acme"
+        "certs"
+      ]
+    )
   ];
 
   options.nixfiles.modules.acme = {
diff --git a/modules/chromium.nix b/modules/chromium.nix
index c7842d5..bc34ecd 100644
--- a/modules/chromium.nix
+++ b/modules/chromium.nix
@@ -18,10 +18,11 @@ in
       programs.chromium = {
         enable = true;
 
-        package = pkgs.ungoogled-chromium;
+        # package = pkgs.ungoogled-chromium;
 
         extensions = [
           { id = "cjpalhdlnbpafiamejdnhcphjbkeiagm"; } # uBlock Origin
+          { id = "nkbihfbeogaeaoehlefnkodbefgpgknn"; } # MetaMask
         ];
       };
     };
diff --git a/modules/common/ark.nix b/modules/common/ark.nix
index ba3056b..007e209 100644
--- a/modules/common/ark.nix
+++ b/modules/common/ark.nix
@@ -10,11 +10,14 @@ in
 {
   imports = [
     inputs.impermanence.nixosModules.impermanence
-    (lib.mkAliasOptionModule [ "ark" ] [
-      "nixfiles"
-      "modules"
-      "ark"
-    ])
+    (lib.mkAliasOptionModule
+      [ "ark" ]
+      [
+        "nixfiles"
+        "modules"
+        "ark"
+      ]
+    )
   ];
 
   options.nixfiles.modules.ark =
diff --git a/modules/common/home-manager.nix b/modules/common/home-manager.nix
index f3e8143..118fc0e 100644
--- a/modules/common/home-manager.nix
+++ b/modules/common/home-manager.nix
@@ -7,11 +7,14 @@
 {
   imports = [
     inputs.home-manager.nixosModule
-    (lib.mkAliasOptionModule [ "hm" ] [
-      "home-manager"
-      "users"
-      lib.my.username
-    ])
+    (lib.mkAliasOptionModule
+      [ "hm" ]
+      [
+        "home-manager"
+        "users"
+        lib.my.username
+      ]
+    )
   ];
 
   hm = {
diff --git a/modules/common/networking.nix b/modules/common/networking.nix
index 468bd8b..2e9c218 100644
--- a/modules/common/networking.nix
+++ b/modules/common/networking.nix
@@ -7,9 +7,12 @@
 }:
 let
   cfg = config.nixfiles.modules.common.networking;
+
+  interface = "eth0"; # This assumes `usePredictableInterfaceNames` is false.
 in
 {
-  options.nixfiles.modules.common.networking.onlyDefault = lib.mkEnableOption "custom networking settings";
+  options.nixfiles.modules.common.networking.onlyDefault =
+    lib.mkEnableOption "custom networking settings";
 
   config = lib.mkIf (!cfg.onlyDefault) {
     ark.directories =
@@ -31,20 +34,6 @@ in
           "::1" = lib.mkForce [ ];
         };
 
-        # There's no way[1] to configure DNS server priority in
-        # systemd-resolved. The only solution for dealing with a broken VPN
-        # connection is to delete /etc/systemd/resolved.conf and restart the
-        # systemd-resolved service. Otherwise I'll just end up with a random
-        # server from the list most of the time because systemd-resolved
-        # "conveniently" will manage server priority for me...
-        #
-        # [1]: https://askubuntu.com/questions/1116732/how-do-i-list-dns-server-order-in-systemd-resolve
-        # [2]: https://github.com/systemd/systemd/issues/6076
-        nameservers = with lib.my.configurations.manwe.wireguard; [
-          ipv6.address
-          ipv4.address
-        ];
-
         useDHCP = false;
 
         nftables.enable = true;
@@ -62,45 +51,46 @@ in
           logRefusedUnicastsOnly = false;
           logReversePathDrops = false;
         };
+
+        usePredictableInterfaceNames = false;
       }
-      (
-        let
-          interface = "eth0"; # This assumes `usePredictableInterfaceNames` is false.
-        in
-        lib.mkIf (lib.hasAttr "ipv4" this && lib.hasAttr "ipv6" this) {
-          usePredictableInterfaceNames = false; # NOTE This can break something!
-          interfaces.${interface} = {
-            ipv4.addresses =
-              with this.ipv4;
-              lib.optional (lib.isString address && lib.isInt prefixLength) {
-                inherit address prefixLength;
-              };
-
-            ipv6.addresses =
-              with this.ipv6;
-              lib.optional (lib.isString address && lib.isInt prefixLength) {
-                inherit address prefixLength;
-              };
+      (lib.mkIf (lib.hasAttr "ipv4" this) {
+        interfaces.${interface}.ipv4.addresses =
+          with this.ipv4;
+          lib.optional (lib.isString address && lib.isInt prefixLength) {
+            inherit address prefixLength;
+          };
+        defaultGateway =
+          with this.ipv4;
+          lib.mkIf (lib.isString gatewayAddress) {
+            inherit interface;
+            address = gatewayAddress;
           };
-          defaultGateway =
-            with this.ipv4;
-            lib.mkIf (lib.isString gatewayAddress) {
-              inherit interface;
-              address = gatewayAddress;
-            };
-          defaultGateway6 =
-            with this.ipv6;
-            lib.mkIf (lib.isString gatewayAddress) {
-              inherit interface;
-              address = gatewayAddress;
-            };
-        }
-      )
+      })
+      (lib.mkIf (lib.hasAttr "ipv6" this) {
+        interfaces.${interface}.ipv6.addresses =
+          with this.ipv6;
+          lib.optional (lib.isString address && lib.isInt prefixLength) {
+            inherit address prefixLength;
+          };
+        defaultGateway6 =
+          with this.ipv6;
+          lib.mkIf (lib.isString gatewayAddress) {
+            inherit interface;
+            address = gatewayAddress;
+          };
+      })
+      (lib.mkIf this.isHeadless {
+        nameservers = with lib.my.configurations.manwe.wireguard; [
+          ipv6.address
+          ipv4.address
+        ];
+      })
       (lib.mkIf this.isHeadful {
         networkmanager = {
           enable = true;
-          plugins = lib.mkForce [ ];
           wifi.backend = "iwd";
+          dns = "none";
         };
 
         wireless = {
@@ -109,15 +99,49 @@ in
           userControlled.enable = true;
           allowAuxiliaryImperativeNetworks = true;
         };
+
+        resolvconf.extraConfig = ''
+          append_nameservers='127.0.0.1'
+        '';
       })
     ];
 
-    services.resolved = {
-      llmnr = "false";
-      dnsovertls = "opportunistic";
-      dnssec = "allow-downgrade";
-      fallbackDns = lib.dns.mkDoT lib.dns.const.quad9.ecs;
-    };
+    services = lib.mkMerge [
+      (lib.mkIf this.isHeadless {
+        resolved = {
+          enable = true;
+          llmnr = "false";
+          dnsovertls = "opportunistic";
+          dnssec = "allow-downgrade";
+          fallbackDns = lib.dns.mkDoT lib.dns.const.quad9.ecs;
+        };
+      })
+      (lib.mkIf this.isHeadful {
+        resolved.enable = false;
+
+        dnscrypt-proxy2 = {
+          enable = true;
+          settings = {
+            ipv4_servers = true;
+            ipv6_servers = false;
+            dnscrypt_servers = true;
+            doh_servers = true;
+            odoh_servers = false;
+            require_dnssec = true;
+            require_nolog = true;
+            require_nofilter = true;
+
+            disabled_server_names = [
+              "cloudflare"
+              "cloudflare-ipv6"
+            ];
+
+            cache = true;
+            cache_size = lib.pow 2 13;
+          };
+        };
+      })
+    ];
 
     environment = {
       shellAliases = lib.listToAttrs (
diff --git a/modules/common/nix.nix b/modules/common/nix.nix
index 09d57ed..2054185 100644
--- a/modules/common/nix.nix
+++ b/modules/common/nix.nix
@@ -72,6 +72,11 @@ in
 
           keep-going = true;
 
+          experimental-features = [
+            "fetch-tree"
+            "pipe-operators"
+          ];
+
           trusted-users = [ my.username ];
 
           substituters = [
@@ -83,6 +88,9 @@ in
           trusted-public-keys = [
             "cache.tvl.su:kjc6KOMupXc1vHVufJUoDUYeLzbwSr9abcAKdn/U1Jk="
           ];
+
+          # https://github.com/NixOS/nix/issues/6901
+          fallback = true;
         };
       };
 
diff --git a/modules/common/secrets.nix b/modules/common/secrets.nix
index 03a2eeb..77dee44 100644
--- a/modules/common/secrets.nix
+++ b/modules/common/secrets.nix
@@ -10,10 +10,13 @@ with lib;
 {
   imports = [
     inputs.agenix.nixosModules.default
-    (mkAliasOptionModule [ "secrets" ] [
-      "age"
-      "secrets"
-    ])
+    (mkAliasOptionModule
+      [ "secrets" ]
+      [
+        "age"
+        "secrets"
+      ]
+    )
   ];
 
   config = {
@@ -23,7 +26,10 @@ with lib;
       else
         map (attr: attr.path) (filter (attr: attr.type == my.ssh.type) config.services.openssh.hostKeys);
 
-    environment.systemPackages = with pkgs; [ agenix ];
+    environment.systemPackages = with pkgs; [
+      age
+      agenix
+    ];
 
     nixpkgs.overlays = [ inputs.agenix.overlays.default ];
   };
diff --git a/modules/common/stylix.nix b/modules/common/stylix.nix
index f1e0417..f17cb4c 100644
--- a/modules/common/stylix.nix
+++ b/modules/common/stylix.nix
@@ -10,11 +10,14 @@ with lib;
 {
   imports = [
     inputs.stylix.nixosModules.stylix
-    (mkAliasOptionModule [ "colors" ] [
-      "lib"
-      "stylix"
-      "colors"
-    ])
+    (mkAliasOptionModule
+      [ "colors" ]
+      [
+        "lib"
+        "stylix"
+        "colors"
+      ]
+    )
   ];
 
   options.nixfiles.modules.common.stylix.fonts.extraPackages = mkOption {
diff --git a/modules/common/users.nix b/modules/common/users.nix
index b8aca28..e0811b7 100644
--- a/modules/common/users.nix
+++ b/modules/common/users.nix
@@ -5,11 +5,14 @@ let
 in
 {
   imports = [
-    (mkAliasOptionModule [ "my" ] [
-      "users"
-      "users"
-      my.username
-    ])
+    (mkAliasOptionModule
+      [ "my" ]
+      [
+        "users"
+        "users"
+        my.username
+      ]
+    )
   ];
 
   ark.directories = [ home ];
diff --git a/modules/emacs/default.nix b/modules/emacs/default.nix
index 455f710..71bc24c 100644
--- a/modules/emacs/default.nix
+++ b/modules/emacs/default.nix
@@ -231,9 +231,8 @@ in
                               (mu4e-drafts-folder       . "/${name}/${folders.drafts}")
                               (mu4e-trash-folder        . "/${name}/${folders.trash}")
                               (mu4e-refile-folder       . "/${name}/Archive")
-                              ${
-                                optionalString (signature.showSignature != "none")
-                                  ''(mu4e-compose-signature   . "${replaceStrings [ "\n" ] [ "\\n" ] signature.text}")''
+                              ${optionalString (signature.showSignature != "none")
+                                ''(mu4e-compose-signature   . "${replaceStrings [ "\n" ] [ "\\n" ] signature.text}")''
                               }
                               (+mu4e-personal-addresses . (${personalAddresses})))
                             t)
diff --git a/modules/firefox/default.nix b/modules/firefox/default.nix
index 4b04c40..ee45434 100644
--- a/modules/firefox/default.nix
+++ b/modules/firefox/default.nix
@@ -536,6 +536,7 @@ in
               "media.autoplay.blocking_policy" = 2;
               "media.autoplay.default" = 5;
               "media.hardwaremediakeys.enabled" = false;
+              "media.videocontrols.picture-in-picture.video-toggle.enabled" = false;
               "reader.parse-on-load.enabled" = false;
               "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
             };
diff --git a/modules/hyprland.nix b/modules/hyprland.nix
index cab01b6..c7f574a 100644
--- a/modules/hyprland.nix
+++ b/modules/hyprland.nix
@@ -1,6 +1,5 @@
 {
   config,
-  inputs,
   lib,
   ...
 }:
@@ -128,16 +127,5 @@ in
     };
 
     programs.hyprland.enable = true;
-
-    nixpkgs.overlays = [ inputs.hyprland.overlays.default ];
-
-    nix.settings = {
-      substituters = [
-        "https://hyprland.cachix.org"
-      ];
-      trusted-public-keys = [
-        "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="
-      ];
-    };
   };
 }
diff --git a/modules/ipfs.nix b/modules/ipfs.nix
index 25f7fce..80a43b6 100644
--- a/modules/ipfs.nix
+++ b/modules/ipfs.nix
@@ -175,7 +175,8 @@ in
           "api.${cfg.domain}" = {
             locations = {
               "/".proxyPass = "http://kubo_api";
-              "~ ^/$".return = "301 http${optionalString config.nixfiles.modules.acme.enable "s"}://api.${cfg.domain}/webui";
+              "~ ^/$".return =
+                "301 http${optionalString config.nixfiles.modules.acme.enable "s"}://api.${cfg.domain}/webui";
             };
             extraConfig = libNginx.config.internalOnly;
           };
diff --git a/modules/password-store.nix b/modules/password-store.nix
index e5cd756..886afb6 100644
--- a/modules/password-store.nix
+++ b/modules/password-store.nix
@@ -9,7 +9,8 @@ let
   cfg = config.nixfiles.modules.password-store;
 in
 {
-  options.nixfiles.modules.password-store.enable = mkEnableOption "the standard UNIX password manager";
+  options.nixfiles.modules.password-store.enable =
+    mkEnableOption "the standard UNIX password manager";
 
   config = mkIf cfg.enable {
     hm.programs = {
diff --git a/modules/plausible.nix b/modules/plausible.nix
index c5b66c3..89729fd 100644
--- a/modules/plausible.nix
+++ b/modules/plausible.nix
@@ -80,12 +80,12 @@ in
       services.plausible = {
         enable = true;
 
-        adminUser = {
-          name = "admin";
-          email = "admin@${my.domain.shire}";
-          passwordFile = config.secrets.plausible-admin-password.path;
-          activate = false;
-        };
+        # adminUser = {
+        #   name = "admin";
+        #   email = "admin@${my.domain.shire}";
+        #   passwordFile = config.secrets.plausible-admin-password.path;
+        #   activate = false;
+        # };
 
         mail = {
           email = "admin+plausible@${my.domain.shire}";
diff --git a/modules/profiles/dev/default.nix b/modules/profiles/dev/default.nix
index 4d85168..af151a1 100644
--- a/modules/profiles/dev/default.nix
+++ b/modules/profiles/dev/default.nix
@@ -11,7 +11,8 @@ in
 {
   imports = attrValues (modulesIn ./.);
 
-  options.nixfiles.modules.profiles.dev.enable = mkEnableOption "Catch-all profile for stuff related to software development and etc.";
+  options.nixfiles.modules.profiles.dev.enable =
+    mkEnableOption "Catch-all profile for stuff related to software development and etc.";
 
   config = mkIf cfg.enable {
     nixfiles.modules = {
diff --git a/modules/syncthing.nix b/modules/syncthing.nix
index e61c080..d239aa4 100644
--- a/modules/syncthing.nix
+++ b/modules/syncthing.nix
@@ -79,7 +79,7 @@ in
 
           devices = mapAttrs (
             name: attr:
-            mkIf (attr.syncthing.id != null && hasAttr "wireguard" attr) {
+            mkIf (hasAttr "syncthing" attr && hasAttr "wireguard" attr) {
               inherit (attr.syncthing) id;
               compression = "always";
               introducer = false;
@@ -98,7 +98,7 @@ in
                 f:
                 attrNames (
                   filterAttrs (
-                    _: attr: (attr.hostname != this.hostname) && (attr.syncthing.id != null) && f attr
+                    _: attr: attr.hostname != this.hostname && hasAttr "syncthing" attr && f attr
                   ) my.configurations
                 );
               all = filterDevices (_: true);
@@ -111,7 +111,7 @@ in
               };
               trashcan = {
                 type = "trashcan";
-                params.cleanoutDays = "7";
+                params.cleanouctDays = "7";
               };
             in
             with config.hm.xdg.userDirs;
diff --git a/modules/unbound-ng.nix b/modules/unbound-ng.nix
new file mode 100644
index 0000000..3d3c6da
--- /dev/null
+++ b/modules/unbound-ng.nix
@@ -0,0 +1,185 @@
+{
+  config,
+  inputs,
+  lib,
+  pkgs,
+  this,
+  ...
+}:
+with lib;
+let
+  cfg = config.nixfiles.modules.unbound-ng;
+in
+{
+  options.nixfiles.modules.unbound-ng = {
+    enable = mkEnableOption "Unbound";
+
+    domain = mkOption {
+      description = "Domain name sans protocol scheme.";
+      type = with types; str;
+      default = config.networking.domain;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    ark.directories = [ config.services.unbound.stateDir ];
+
+    nixfiles.modules.redis.enable = true;
+
+    services = {
+      unbound = {
+        enable = true;
+
+        package = pkgs.unbound-with-systemd.override {
+          withRedis = true;
+          withTFO = true;
+        };
+
+        checkconf = true;
+        settings = {
+          server = {
+            module-config = ''"respip validator iterator"'';
+
+            interface = with this.wireguard-ng; [
+              "127.0.0.1"
+              "::1"
+              ipv4.address
+              ipv6.address
+            ];
+
+            local-zone = concatLists (
+              mapAttrsToList (h: _: [ "\"${h}.${cfg.domain}\" redirect" ]) my.configurations
+            );
+            local-data = concatLists (
+              mapAttrsToList (
+                hostname:
+                let
+                  domain = "${hostname}.${cfg.domain}";
+                in
+                attr:
+                (optionals (hasAttr "wireguard-ng" attr) (
+                  with attr.wireguard-ng;
+                  [
+                    "\"${domain} 604800 IN A ${ipv4.address}\""
+                    "\"${domain} 604800 IN AAAA ${ipv6.address}\""
+                    "\"${domain}. A ${ipv4.address}\""
+                    "\"${domain}. AAAA ${ipv6.address}\""
+                  ]
+                  ++ (optionals (hasAttr "domains" attr) (
+                    concatMap (domain: [
+                      "\"${domain}. A ${ipv4.address}\""
+                      "\"${domain}. AAAA ${ipv6.address}\""
+                    ]) attr.domains
+                  ))
+                ))
+              ) my.configurations
+            );
+            local-data-ptr = concatLists (
+              mapAttrsToList (
+                hostname:
+                let
+                  domain = "${hostname}.${cfg.domain}";
+                in
+                attr:
+                (optionals (hasAttr "wireguard-ng" attr) (
+                  with attr.wireguard-ng;
+                  [
+                    "\"${ipv4.address} ${domain}\""
+                    "\"${ipv6.address} ${domain}\""
+                  ]
+                  ++ (optionals (hasAttr "domains" attr) (
+                    concatMap (domain: [
+                      "\"${ipv4.address} ${domain}\""
+                      "\"${ipv6.address} ${domain}\""
+                    ]) attr.domains
+                  ))
+                ))
+              ) my.configurations
+            );
+
+            private-domain = map (domain: "${domain}.") [
+              cfg.domain
+              "local"
+            ];
+            private-address = with config.nixfiles.modules.wireguard-ng; [
+              ipv4.subnet
+              ipv6.subnet
+            ];
+
+            access-control = with config.nixfiles.modules.wireguard-ng; [
+              "0.0.0.0/0 refuse"
+              "::/0 refuse"
+              "127.0.0.0/8 allow"
+              "::1/128 allow"
+              "${ipv4.subnet} allow"
+              "${ipv6.subnet} allow"
+            ];
+
+            cache-min-ttl = 0;
+
+            serve-expired = true;
+            serve-expired-reply-ttl = 0;
+
+            prefetch = true;
+            prefetch-key = true;
+
+            hide-identity = true;
+            hide-version = true;
+
+            extended-statistics = true;
+
+            log-replies = false;
+            log-tag-queryreply = false;
+            log-local-actions = false;
+
+            verbosity = 0;
+          };
+
+          forward-zone = [
+            {
+              name = ".";
+              forward-tls-upstream = true;
+              forward-addr = dns.mkDoT dns.const.quad9.ecs;
+            }
+          ];
+
+          cachedb = with config.services.redis.servers.default; {
+            backend = "redis";
+            redis-server-host = bind;
+            redis-server-port = port;
+          };
+
+          rpz = {
+            name = "hagezi.pro";
+            zonefile = "hagezi.pro";
+            url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/pro.txt";
+          };
+        };
+
+        enableRootTrustAnchor = true;
+
+        localControlSocketPath = "/run/unbound/unbound.socket";
+      };
+
+      prometheus.exporters.unbound = {
+        enable = true;
+        listenAddress = mkDefault this.wireguard-ng.ipv4.address;
+        port = 9167;
+        inherit (config.services.unbound) group user;
+        unbound.host = "unix://${config.services.unbound.localControlSocketPath}";
+      };
+    };
+
+    boot.kernel.sysctl."net.ipv4.tcp_fastopen" = mkOverride 200 3;
+
+    topology = with cfg; {
+      nodes.${this.hostname}.services.unbound = {
+        name = "Unbound";
+        icon = "${inputs.homelab-svg-assets}/assets/unbound.svg";
+        details.listen.text = concatMapStringsSep "\n" (i: "${i}:53") (
+          filter (i: i != "127.0.0.1" && i != "::1") config.services.unbound.settings.server.interface
+        );
+      };
+    };
+  };
+}
diff --git a/modules/unbound.nix b/modules/unbound.nix
index e837f89..b8de321 100644
--- a/modules/unbound.nix
+++ b/modules/unbound.nix
@@ -65,10 +65,12 @@ in
                     "\"${domain}. A ${ipv4.address}\""
                     "\"${domain}. AAAA ${ipv6.address}\""
                   ]
-                  ++ concatMap (domain: [
-                    "\"${domain}. A ${ipv4.address}\""
-                    "\"${domain}. AAAA ${ipv6.address}\""
-                  ]) attr.domains
+                  ++ (optionals (hasAttr "domains" attr) (
+                    concatMap (domain: [
+                      "\"${domain}. A ${ipv4.address}\""
+                      "\"${domain}. AAAA ${ipv6.address}\""
+                    ]) attr.domains
+                  ))
                 ))
               ) my.configurations
             );
@@ -85,10 +87,12 @@ in
                     "\"${ipv4.address} ${domain}\""
                     "\"${ipv6.address} ${domain}\""
                   ]
-                  ++ concatMap (domain: [
-                    "\"${ipv4.address} ${domain}\""
-                    "\"${ipv6.address} ${domain}\""
-                  ]) attr.domains
+                  ++ (optionals (hasAttr "domains" attr) (
+                    concatMap (domain: [
+                      "\"${ipv4.address} ${domain}\""
+                      "\"${ipv6.address} ${domain}\""
+                    ]) attr.domains
+                  ))
                 ))
               ) my.configurations
             );
diff --git a/modules/wireguard-ng.nix b/modules/wireguard-ng.nix
new file mode 100644
index 0000000..5374a71
--- /dev/null
+++ b/modules/wireguard-ng.nix
@@ -0,0 +1,255 @@
+{
+  config,
+  inputs,
+  lib,
+  pkgs,
+  this,
+  ...
+}:
+with lib;
+let
+  cfg = config.nixfiles.modules.wireguard-ng;
+
+  DNSSetup = optionalString config.services.resolved.enable (
+    let
+      resolvectl = "${config.systemd.package}/bin/resolvectl";
+    in
+    ''
+      ${resolvectl} dns ${cfg.interface} ${cfg.server.ipv6.address} ${cfg.server.ipv4.address}
+      ${resolvectl} domain ${cfg.interface} local ${my.domain.shire}
+      ${resolvectl} dnssec ${cfg.interface} no
+      ${resolvectl} dnsovertls ${cfg.interface} no
+    ''
+  );
+in
+{
+  options.nixfiles.modules.wireguard-ng = {
+    client = {
+      enable = mkEnableOption "WireGuard client";
+
+      enableTrafficRouting = mkOption {
+        description = "Whether to enable traffic routing through the sever.";
+        type = with types; bool;
+        # default = !this.isHeadless;
+        default = false;
+      };
+    };
+
+    server = {
+      enable = mkEnableOption "WireGuard server";
+
+      ipv4.address = mkOption {
+        description = "IPv4 address to bind to.";
+        type = with types; str;
+        default = my.configurations.tulkas.wireguard-ng.ipv4.address;
+      };
+
+      ipv6.address = mkOption {
+        description = "IPv4 address to bind to.";
+        type = with types; str;
+        default = my.configurations.tulkas.wireguard-ng.ipv6.address;
+      };
+
+      address = mkOption {
+        description = "Endpoint address to use";
+        type = with types; str;
+        default = my.configurations.tulkas.ipv4.address;
+      };
+
+      port = mkOption {
+        description = "Endpoint port to use.";
+        type = with types; int;
+        default = 7070;
+      };
+
+      publicKey = mkOption {
+        description = "Server's public key.";
+        type = with types; str;
+        default = my.configurations.tulkas.wireguard.publicKey;
+      };
+
+      peers = mkOption {
+        description = "List of peers.";
+        type = with types; listOf attrs;
+        default =
+          mapAttrsToList
+            (
+              _: attr: with attr; {
+                inherit (wireguard-ng) publicKey;
+                allowedIPs = with wireguard-ng; [
+                  "${ipv6.address}/128"
+                  "${ipv4.address}/32"
+                ];
+              }
+            )
+            (
+              filterAttrs (
+                _: attr: attr.hostname != this.hostname && hasAttr "wireguard-ng" attr
+              ) my.configurations
+            );
+      };
+    };
+
+    interface = mkOption {
+      description = "Name of the interface to use WireGuard with.";
+      type = with types; str;
+      default = "wg70";
+    };
+
+    ipv4.subnet = mkOption {
+      description = "CIDR notation for the IPv4 subnet to use over WireGuard.";
+      type = with types; str;
+      default = "10.70.0.0/16";
+    };
+
+    ipv6.subnet = mkOption {
+      description = "CIDR notation for the IPv6 subnet to use over WireGuard.";
+      type = with types; str;
+      default = "fd70::/16";
+    };
+  };
+
+  config =
+    {
+      assertions = [
+        {
+          assertion = config.security.sudo.enable;
+          message = "Sudo is not enabled.";
+        }
+        {
+          assertion = any (x: x == "wheel") config.my.extraGroups;
+          message = ''User is not in the "wheel" group.'';
+        }
+      ];
+    }
+    // mkMerge [
+      (mkIf (cfg.client.enable || cfg.server.enable) {
+        secrets."wireguard-private-key-${this.hostname}".file =
+          "${inputs.self}/secrets/wireguard-private-key-${this.hostname}";
+
+        networking.firewall.trustedInterfaces = [ cfg.interface ];
+
+        topology = with cfg; {
+          nodes.${this.hostname}.interfaces.${interface} = {
+            network = interface;
+            icon = "interfaces.wireguard";
+          };
+        };
+      })
+      (mkIf cfg.client.enable {
+        networking.wg-quick.interfaces.${cfg.interface} = mkMerge [
+          (with this.wireguard-ng; {
+            privateKeyFile = config.secrets."wireguard-private-key-${this.hostname}".path;
+            address = [
+              "${ipv4.address}/16"
+              "${ipv6.address}/16"
+            ];
+          })
+          (with cfg.server; {
+            peers = [
+              {
+                inherit publicKey;
+                endpoint = "${address}:${toString port}";
+                allowedIPs =
+                  if cfg.client.enableTrafficRouting then
+                    [
+                      "::/0"
+                      "0.0.0.0/0"
+                    ]
+                  else
+                    [
+                      cfg.ipv6.subnet
+                      cfg.ipv4.subnet
+                    ];
+              }
+            ];
+            dns = [
+              ipv6.address
+              ipv4.address
+            ];
+            postUp = DNSSetup;
+          })
+        ];
+
+        environment.systemPackages = with pkgs; [
+          (writeShellApplication {
+            name = "wg-toggle-ng";
+            runtimeInputs = [
+              iproute2
+              jq
+            ];
+            text = ''
+              ip46() {
+                sudo ip -4 "$@"
+                sudo ip -6 "$@"
+              }
+
+              fwmark=$(sudo awg show ${cfg.interface} fwmark) || exit
+              if ip -j rule list lookup "$fwmark" | jq -e 'length > 0' >/dev/null; then
+                ip46 rule del lookup main suppress_prefixlength 0
+                ip46 rule del lookup "$fwmark"
+              else
+                ip46 rule add not fwmark "$fwmark" lookup "$fwmark"
+                ip46 rule add lookup main suppress_prefixlength 0
+              fi
+            '';
+          })
+        ];
+      })
+      (mkIf cfg.server.enable {
+        networking = {
+          wireguard = {
+            enable = true;
+            interfaces.${cfg.interface} = with cfg.server; {
+              privateKeyFile = config.secrets."wireguard-private-key-${this.hostname}".path;
+              ips = [
+                "${ipv6.address}/16"
+                "${ipv4.address}/16"
+              ];
+              listenPort = port;
+              inherit peers;
+              postSetup = DNSSetup;
+              allowedIPsAsRoutes = false;
+            };
+          };
+
+          nat = {
+            enable = true;
+            enableIPv6 = true;
+
+            externalInterface = mkDefault "eth0";
+
+            internalInterfaces = [ cfg.interface ];
+            internalIPs = [ cfg.ipv4.subnet ];
+            internalIPv6s = [ cfg.ipv6.subnet ];
+          };
+
+          firewall.allowedUDPPorts = [ cfg.server.port ];
+        };
+
+        services.prometheus.exporters.wireguard = {
+          enable = true;
+          listenAddress = mkDefault this.wireguard-ng.ipv4.address;
+          withRemoteIp = true;
+          port = 9586;
+        };
+
+        topology = with cfg; {
+          networks = {
+            ${interface} = {
+              name = interface;
+              cidrv4 = ipv4.subnet;
+              cidrv6 = ipv6.subnet;
+              icon = "interfaces.wireguard";
+            };
+          };
+
+          nodes.${this.hostname}.interfaces.${interface}.physicalConnections =
+            mapAttrsToList (name: _: config.lib.topology.mkConnection name interface)
+              (
+                filterAttrs (n: v: !v.isOther && n != this.hostname && hasAttr "wireguard-ng" v) my.configurations
+              );
+        };
+      })
+    ];
+}
diff --git a/modules/wireguard.nix b/modules/wireguard.nix
index 5138946..633ec5b 100644
--- a/modules/wireguard.nix
+++ b/modules/wireguard.nix
@@ -10,7 +10,7 @@ with lib;
 let
   cfg = config.nixfiles.modules.wireguard;
 
-  DNSSetup =
+  DNSSetup = optionalString config.services.resolved.enable (
     let
       resolvectl = "${config.systemd.package}/bin/resolvectl";
     in
@@ -19,14 +19,19 @@ let
       ${resolvectl} domain ${cfg.interface} local ${my.domain.shire}
       ${resolvectl} dnssec ${cfg.interface} no
       ${resolvectl} dnsovertls ${cfg.interface} no
-    '';
+    ''
+  );
 
   extraOptions = {
-    jc = 228;
-    jmin = 42;
-    jmax = 420;
-    s1 = 69;
-    s2 = 96;
+    jc = 23;
+    jmin = 58;
+    jmax = 1021;
+    s1 = 49;
+    s2 = 87;
+    h1 = 1264154357;
+    h2 = 462401493;
+    h3 = 737329836;
+    h4 = 1039929807;
   };
 in
 {
@@ -137,7 +142,8 @@ in
     }
     // mkMerge [
       (mkIf (cfg.client.enable || cfg.server.enable) {
-        secrets."wireguard-private-key-${this.hostname}".file = "${inputs.self}/secrets/wireguard-private-key-${this.hostname}";
+        secrets."wireguard-private-key-${this.hostname}".file =
+          "${inputs.self}/secrets/wireguard-private-key-${this.hostname}";
 
         networking.firewall.trustedInterfaces = [ cfg.interface ];
 

Consider giving Nix/NixOS a try! <3