about summary refs log tree commit diff
path: root/nixpkgs/nixos
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2023-10-30 13:37:39 +0100
committerAlyssa Ross <hi@alyssa.is>2023-10-30 13:37:39 +0100
commit7e0c8fe656bbc2fcbdfc3e03a367d2c6ff389769 (patch)
tree38e753812c0ceba947d65ec0555a5a66c1a5aa4e /nixpkgs/nixos
parent46cf147fc42b72f68ecd52b3b03a8bfd6077f42b (diff)
parent63678e9f3d3afecfeafa0acead6239cdb447574c (diff)
downloadnixlib-7e0c8fe656bbc2fcbdfc3e03a367d2c6ff389769.tar
nixlib-7e0c8fe656bbc2fcbdfc3e03a367d2c6ff389769.tar.gz
nixlib-7e0c8fe656bbc2fcbdfc3e03a367d2c6ff389769.tar.bz2
nixlib-7e0c8fe656bbc2fcbdfc3e03a367d2c6ff389769.tar.lz
nixlib-7e0c8fe656bbc2fcbdfc3e03a367d2c6ff389769.tar.xz
nixlib-7e0c8fe656bbc2fcbdfc3e03a367d2c6ff389769.tar.zst
nixlib-7e0c8fe656bbc2fcbdfc3e03a367d2c6ff389769.zip
Merge commit '63678e9f3d3afecfeafa0acead6239cdb447574c' into HEAD
Conflicts:
	nixpkgs/pkgs/build-support/rust/build-rust-package/default.nix
Diffstat (limited to 'nixpkgs/nixos')
-rw-r--r--nixpkgs/nixos/doc/manual/release-notes/rl-2311.section.md12
-rw-r--r--nixpkgs/nixos/lib/make-squashfs.nix13
-rw-r--r--nixpkgs/nixos/lib/qemu-common.nix1
-rw-r--r--nixpkgs/nixos/modules/hardware/video/nvidia.nix6
-rw-r--r--nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl16
-rw-r--r--nixpkgs/nixos/modules/misc/nixpkgs.nix8
-rw-r--r--nixpkgs/nixos/modules/module-list.nix6
-rw-r--r--nixpkgs/nixos/modules/programs/browserpass.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/firefox.nix103
-rw-r--r--nixpkgs/nixos/modules/programs/wayland/cardboard.nix24
-rw-r--r--nixpkgs/nixos/modules/security/acme/default.nix59
-rw-r--r--nixpkgs/nixos/modules/services/backup/bacula.nix40
-rw-r--r--nixpkgs/nixos/modules/services/databases/ferretdb.nix2
-rw-r--r--nixpkgs/nixos/modules/services/desktops/gnome/gnome-browser-connector.nix2
-rw-r--r--nixpkgs/nixos/modules/services/home-automation/esphome.nix2
-rw-r--r--nixpkgs/nixos/modules/services/home-automation/home-assistant.nix2
-rw-r--r--nixpkgs/nixos/modules/services/matrix/synapse.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/amazon-ssm-agent.nix (renamed from nixpkgs/nixos/modules/services/misc/ssm-agent.nix)19
-rw-r--r--nixpkgs/nixos/modules/services/misc/forgejo.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/munin.nix37
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix4
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix19
-rw-r--r--nixpkgs/nixos/modules/services/networking/fastnetmon-advanced.nix222
-rw-r--r--nixpkgs/nixos/modules/services/networking/kea.nix21
-rw-r--r--nixpkgs/nixos/modules/services/networking/rosenpass.nix233
-rw-r--r--nixpkgs/nixos/modules/services/networking/syncthing.nix28
-rw-r--r--nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/akkoma.nix17
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/lanraragi.nix100
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix5
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/systemd/tmpfiles.nix104
-rw-r--r--nixpkgs/nixos/modules/virtualisation/lxc-container.nix18
-rw-r--r--nixpkgs/nixos/modules/virtualisation/qemu-vm.nix71
-rw-r--r--nixpkgs/nixos/release-combined.nix2
-rw-r--r--nixpkgs/nixos/release.nix15
-rw-r--r--nixpkgs/nixos/tests/all-tests.nix6
-rw-r--r--nixpkgs/nixos/tests/cockpit.nix3
-rw-r--r--nixpkgs/nixos/tests/fastnetmon-advanced.nix65
-rw-r--r--nixpkgs/nixos/tests/firefox.nix30
-rw-r--r--nixpkgs/nixos/tests/forgejo.nix23
-rw-r--r--nixpkgs/nixos/tests/installer.nix32
-rw-r--r--nixpkgs/nixos/tests/lanraragi.nix40
-rw-r--r--nixpkgs/nixos/tests/lxd/container.nix13
-rw-r--r--nixpkgs/nixos/tests/misc.nix4
-rw-r--r--nixpkgs/nixos/tests/nixos-rebuild-install-bootloader.nix73
-rw-r--r--nixpkgs/nixos/tests/openssh.nix14
-rw-r--r--nixpkgs/nixos/tests/prometheus-exporters.nix6
-rw-r--r--nixpkgs/nixos/tests/rosenpass.nix217
-rw-r--r--nixpkgs/nixos/tests/stratis/encryption.nix4
-rw-r--r--nixpkgs/nixos/tests/systemd-credentials-tpm2.nix59
-rw-r--r--nixpkgs/nixos/tests/systemd-cryptenroll.nix61
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-luks-tpm2.nix27
54 files changed, 1553 insertions, 347 deletions
diff --git a/nixpkgs/nixos/doc/manual/release-notes/rl-2311.section.md b/nixpkgs/nixos/doc/manual/release-notes/rl-2311.section.md
index 9e2afe5fd201..bd0d74a8885b 100644
--- a/nixpkgs/nixos/doc/manual/release-notes/rl-2311.section.md
+++ b/nixpkgs/nixos/doc/manual/release-notes/rl-2311.section.md
@@ -107,6 +107,8 @@
 
 - [NNCP](http://www.nncpgo.org/). Added nncp-daemon and nncp-caller services. Configuration is set with [programs.nncp.settings](#opt-programs.nncp.settings) and the daemons are enabled at [services.nncp](#opt-services.nncp.caller.enable).
 
+- [FastNetMon Advanced](https://fastnetmon.com/product-overview/), a commercial high performance DDoS detector / sensor. Available as [services.fastnetmon-advanced](#opt-services.fastnetmon-advanced.enable).
+
 - [tuxedo-rs](https://github.com/AaronErhardt/tuxedo-rs), Rust utilities for interacting with hardware from TUXEDO Computers.
 
 - [audiobookshelf](https://github.com/advplyr/audiobookshelf/), a self-hosted audiobook and podcast server. Available as [services.audiobookshelf](#opt-services.audiobookshelf.enable).
@@ -121,6 +123,8 @@
 
 - [Soft Serve](https://github.com/charmbracelet/soft-serve), a tasty, self-hostable Git server for the command line. Available as [services.soft-serve](#opt-services.soft-serve.enable).
 
+- [Rosenpass](https://rosenpass.eu/), a service for post-quantum-secure VPNs with WireGuard. Available as [services.rosenpass](#opt-services.rosenpass.enable).
+
 ## Backward Incompatibilities {#sec-release-23.11-incompatibilities}
 
 - `network-online.target` has been fixed to no longer time out for systems with `networking.useDHCP = true` and `networking.useNetworkd = true`.
@@ -313,6 +317,8 @@
 
 - `rome` was removed because it is no longer maintained and is succeeded by `biome`.
 
+- The `prometheus-knot-exporter` was migrated to a version maintained by CZ.NIC. Various metric names have changed, so checking existing rules is recommended.
+
 - The `services.mtr-exporter.target` has been removed in favor of `services.mtr-exporter.jobs` which allows specifying multiple targets.
 
 - Setting `nixpkgs.config` options while providing an external `pkgs` instance will now raise an error instead of silently ignoring the options. NixOS modules no longer set `nixpkgs.config` to accomodate this. This specifically affects `services.locate`, `services.xserver.displayManager.lightdm.greeters.tiny` and `programs.firefox` NixOS modules. No manual intervention should be required in most cases, however, configurations relying on those modules affecting packages outside the system environment should switch to explicit overlays.
@@ -325,6 +331,10 @@
 
 - `ps3netsrv` has been replaced with the webman-mod fork, the executable has been renamed from `ps3netsrv++` to `ps3netsrv` and cli parameters have changed.
 
+- `ssm-agent` package and module were renamed to `amazon-ssm-agent` to be consistent with the upstream package name.
+
+- `services.kea.{ctrl-agent,dhcp-ddns,dhcp,dhcp6}` now use separate runtime directories instead of `/run/kea` to work around the runtime directory being cleared on service start.
+
 ## Other Notable Changes {#sec-release-23.11-notable-changes}
 
 - The Cinnamon module now enables XDG desktop integration by default. If you are experiencing collisions related to xdg-desktop-portal-gtk you can safely remove `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];` from your NixOS configuration.
@@ -359,6 +369,8 @@
 
 - `services.outline` can now be configured to use local filesystem storage instead of S3 storage using [services.outline.storage.storageType](#opt-services.outline.storage.storageType).
 
+- `paperwork` was updated to version 2.2. Documents scanned with this version will not be visible to previous versions if you downgrade. See the [upstream announcement](https://forum.openpaper.work/t/paperwork-2-2-testing-phase/316#important-switch-from-jpeg-to-png-for-new-pages-2) for details and workarounds.
+
 - `buildGoModule` `go-modules` attrs have been renamed to `goModules`.
 
 - The `fonts.fonts` and `fonts.enableDefaultFonts` options have been renamed to `fonts.packages` and `fonts.enableDefaultPackages` respectively.
diff --git a/nixpkgs/nixos/lib/make-squashfs.nix b/nixpkgs/nixos/lib/make-squashfs.nix
index b7c7078b73b1..4b6b56739948 100644
--- a/nixpkgs/nixos/lib/make-squashfs.nix
+++ b/nixpkgs/nixos/lib/make-squashfs.nix
@@ -1,15 +1,22 @@
 { lib, stdenv, squashfsTools, closureInfo
 
+,  fileName ? "squashfs"
 , # The root directory of the squashfs filesystem is filled with the
   # closures of the Nix store paths listed here.
   storeContents ? []
+  # Pseudo files to be added to squashfs image
+, pseudoFiles ? []
+, noStrip ? false
 , # Compression parameters.
   # For zstd compression you can use "zstd -Xcompression-level 6".
   comp ? "xz -Xdict-size 100%"
 }:
 
+let
+  pseudoFilesArgs = lib.concatMapStrings (f: ''-p "${f}" '') pseudoFiles;
+in
 stdenv.mkDerivation {
-  name = "squashfs.img";
+  name = "${fileName}.img";
   __structuredAttrs = true;
 
   nativeBuildInputs = [ squashfsTools ];
@@ -31,8 +38,8 @@ stdenv.mkDerivation {
     '' + ''
 
       # Generate the squashfs image.
-      mksquashfs nix-path-registration $(cat $closureInfo/store-paths) $out \
-        -no-hardlinks -keep-as-directory -all-root -b 1048576 -comp ${comp} \
+      mksquashfs nix-path-registration $(cat $closureInfo/store-paths) $out ${pseudoFilesArgs} \
+        -no-hardlinks ${lib.optionalString noStrip "-no-strip"} -keep-as-directory -all-root -b 1048576 -comp ${comp} \
         -processors $NIX_BUILD_CORES
     '';
 }
diff --git a/nixpkgs/nixos/lib/qemu-common.nix b/nixpkgs/nixos/lib/qemu-common.nix
index 4fff2e0a6f15..b946f62d93dc 100644
--- a/nixpkgs/nixos/lib/qemu-common.nix
+++ b/nixpkgs/nixos/lib/qemu-common.nix
@@ -40,6 +40,7 @@ rec {
       otherHostGuestMatrix = {
         aarch64-darwin = {
           aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -machine virt,gic-version=2,accel=hvf:tcg -cpu max";
+          inherit (otherHostGuestMatrix.x86_64-darwin) x86_64-linux;
         };
         x86_64-darwin = {
           x86_64-linux = "${qemuPkg}/bin/qemu-system-x86_64 -machine type=q35,accel=hvf:tcg -cpu max";
diff --git a/nixpkgs/nixos/modules/hardware/video/nvidia.nix b/nixpkgs/nixos/modules/hardware/video/nvidia.nix
index 4320edf60da5..c36775dd24bb 100644
--- a/nixpkgs/nixos/modules/hardware/video/nvidia.nix
+++ b/nixpkgs/nixos/modules/hardware/video/nvidia.nix
@@ -269,9 +269,9 @@ in {
         services.udev.extraRules =
         ''
           # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded.
-          KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidiactl c $$(grep nvidia-frontend /proc/devices | cut -d \  -f 1) 255'"
-          KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'for i in $$(cat /proc/driver/nvidia/gpus/*/information | grep Minor | cut -d \  -f 4); do mknod -m 666 /dev/nvidia$${i} c $$(grep nvidia-frontend /proc/devices | cut -d \  -f 1) $${i}; done'"
-          KERNEL=="nvidia_modeset", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-modeset c $$(grep nvidia-frontend /proc/devices | cut -d \  -f 1) 254'"
+          KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidiactl c 195 255'"
+          KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'for i in $$(cat /proc/driver/nvidia/gpus/*/information | grep Minor | cut -d \  -f 4); do mknod -m 666 /dev/nvidia$${i} c 195 $${i}; done'"
+          KERNEL=="nvidia_modeset", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-modeset c 195 254'"
           KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm c $$(grep nvidia-uvm /proc/devices | cut -d \  -f 1) 0'"
           KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm-tools c $$(grep nvidia-uvm /proc/devices | cut -d \  -f 1) 1'"
         '';
diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl b/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl
index 7d0c5898e23d..85180bf2d1b4 100644
--- a/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -102,22 +102,6 @@ sub cpuManufacturer {
     return $cpuinfo =~ /^vendor_id\s*:.* $id$/m;
 }
 
-
-# Determine CPU governor to use
-if (-e "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") {
-    my $governors = read_file("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors");
-    # ondemand governor is not available on sandy bridge or later Intel CPUs
-    my @desired_governors = ("ondemand", "powersave");
-    my $e;
-
-    foreach $e (@desired_governors) {
-        if (index($governors, $e) != -1) {
-            last if (push @attrs, "powerManagement.cpuFreqGovernor = lib.mkDefault \"$e\";");
-        }
-    }
-}
-
-
 # Virtualization support?
 push @kernelModules, "kvm-intel" if hasCPUFeature "vmx";
 push @kernelModules, "kvm-amd" if hasCPUFeature "svm";
diff --git a/nixpkgs/nixos/modules/misc/nixpkgs.nix b/nixpkgs/nixos/modules/misc/nixpkgs.nix
index bfcae9c7a935..da321a923449 100644
--- a/nixpkgs/nixos/modules/misc/nixpkgs.nix
+++ b/nixpkgs/nixos/modules/misc/nixpkgs.nix
@@ -187,7 +187,7 @@ in
 
     hostPlatform = mkOption {
       type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform
-      example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
+      example = { system = "aarch64-linux"; };
       # Make sure that the final value has all fields for sake of other modules
       # referring to this. TODO make `lib.systems` itself use the module system.
       apply = lib.systems.elaborate;
@@ -205,7 +205,7 @@ in
     buildPlatform = mkOption {
       type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform
       default = cfg.hostPlatform;
-      example = { system = "x86_64-linux"; config = "x86_64-unknown-linux-gnu"; };
+      example = { system = "x86_64-linux"; };
       # Make sure that the final value has all fields for sake of other modules
       # referring to this.
       apply = lib.systems.elaborate;
@@ -228,7 +228,7 @@ in
     localSystem = mkOption {
       type = types.attrs; # TODO utilize lib.systems.parsedPlatform
       default = { inherit (cfg) system; };
-      example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
+      example = { system = "aarch64-linux"; };
       # Make sure that the final value has all fields for sake of other modules
       # referring to this. TODO make `lib.systems` itself use the module system.
       apply = lib.systems.elaborate;
@@ -262,7 +262,7 @@ in
     crossSystem = mkOption {
       type = types.nullOr types.attrs; # TODO utilize lib.systems.parsedPlatform
       default = null;
-      example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
+      example = { system = "aarch64-linux"; };
       description = lib.mdDoc ''
         Systems with a recently generated `hardware-configuration.nix`
         may instead specify *only* {option}`nixpkgs.buildPlatform`,
diff --git a/nixpkgs/nixos/modules/module-list.nix b/nixpkgs/nixos/modules/module-list.nix
index 16541be4e120..c5c3c0d4719a 100644
--- a/nixpkgs/nixos/modules/module-list.nix
+++ b/nixpkgs/nixos/modules/module-list.nix
@@ -268,6 +268,7 @@
   ./programs/usbtop.nix
   ./programs/vim.nix
   ./programs/wavemon.nix
+  ./programs/wayland/cardboard.nix
   ./programs/wayland/river.nix
   ./programs/wayland/sway.nix
   ./programs/wayland/waybar.nix
@@ -626,6 +627,7 @@
   ./services/matrix/matrix-sliding-sync.nix
   ./services/matrix/synapse.nix
   ./services/misc/airsonic.nix
+  ./services/misc/amazon-ssm-agent.nix
   ./services/misc/ananicy.nix
   ./services/misc/ankisyncd.nix
   ./services/misc/apache-kafka.nix
@@ -742,7 +744,6 @@
   ./services/misc/spice-autorandr.nix
   ./services/misc/spice-vdagentd.nix
   ./services/misc/spice-webdavd.nix
-  ./services/misc/ssm-agent.nix
   ./services/misc/sssd.nix
   ./services/misc/subsonic.nix
   ./services/misc/sundtek.nix
@@ -908,6 +909,7 @@
   ./services/networking/eternal-terminal.nix
   ./services/networking/expressvpn.nix
   ./services/networking/fakeroute.nix
+  ./services/networking/fastnetmon-advanced.nix
   ./services/networking/ferm.nix
   ./services/networking/firefox-syncserver.nix
   ./services/networking/fireqos.nix
@@ -1048,6 +1050,7 @@
   ./services/networking/redsocks.nix
   ./services/networking/resilio.nix
   ./services/networking/robustirc-bridge.nix
+  ./services/networking/rosenpass.nix
   ./services/networking/routedns.nix
   ./services/networking/rpcbind.nix
   ./services/networking/rxe.nix
@@ -1269,6 +1272,7 @@
   ./services/web-apps/kavita.nix
   ./services/web-apps/keycloak.nix
   ./services/web-apps/komga.nix
+  ./services/web-apps/lanraragi.nix
   ./services/web-apps/lemmy.nix
   ./services/web-apps/limesurvey.nix
   ./services/web-apps/mainsail.nix
diff --git a/nixpkgs/nixos/modules/programs/browserpass.nix b/nixpkgs/nixos/modules/programs/browserpass.nix
index abd99056ff3b..a9670a37e618 100644
--- a/nixpkgs/nixos/modules/programs/browserpass.nix
+++ b/nixpkgs/nixos/modules/programs/browserpass.nix
@@ -27,6 +27,6 @@ with lib;
       "opt/brave/native-messaging-hosts/${appId}".source = source "hosts/chromium";
       "opt/brave/policies/managed/${appId}".source = source "policies/chromium";
     };
-    programs.firefox.wrapperConfig.enableBrowserpass = true;
+    programs.firefox.nativeMessagingHosts.packages = [ pkgs.browserpass ];
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/firefox.nix b/nixpkgs/nixos/modules/programs/firefox.nix
index 813e0e0105f6..85f47530cf5a 100644
--- a/nixpkgs/nixos/modules/programs/firefox.nix
+++ b/nixpkgs/nixos/modules/programs/firefox.nix
@@ -5,8 +5,6 @@ with lib;
 let
   cfg = config.programs.firefox;
 
-  nmh = cfg.nativeMessagingHosts;
-
   policyFormat = pkgs.formats.json { };
 
   organisationInfo = ''
@@ -17,6 +15,50 @@ let
     given control of your browser, unless of course they also control your
     NixOS configuration.
   '';
+
+  # deprecated per-native-messaging-host options
+  nmhOptions = {
+    browserpass = {
+      name = "Browserpass";
+      package = pkgs.browserpass;
+    };
+    bukubrow = {
+      name = "Bukubrow";
+      package = pkgs.bukubrow;
+    };
+    euwebid = {
+      name = "Web eID";
+      package = pkgs.web-eid-app;
+    };
+    ff2mpv = {
+      name = "ff2mpv";
+      package = pkgs.ff2mpv;
+    };
+    fxCast = {
+      name = "fx_cast";
+      package = pkgs.fx-cast-bridge;
+    };
+    gsconnect = {
+      name = "GSConnect";
+      package = pkgs.gnomeExtensions.gsconnect;
+    };
+    jabref = {
+      name = "JabRef";
+      package = pkgs.jabref;
+    };
+    passff = {
+      name = "PassFF";
+      package = pkgs.passff-host;
+    };
+    tridactyl = {
+      name = "Tridactyl";
+      package = pkgs.tridactyl-native;
+    };
+    ugetIntegrator = {
+      name = "Uget Integrator";
+      package = pkgs.uget-integrator;
+    };
+  };
 in
 {
   options.programs.firefox = {
@@ -204,46 +246,31 @@ in
       '';
     };
 
-    nativeMessagingHosts = mapAttrs (_: v: mkEnableOption (mdDoc v)) {
-      browserpass = "Browserpass support";
-      bukubrow = "Bukubrow support";
-      euwebid = "Web eID support";
-      ff2mpv = "ff2mpv support";
-      fxCast = "fx_cast support";
-      gsconnect = "GSConnect support";
-      jabref = "JabRef support";
-      passff = "PassFF support";
-      tridactyl = "Tridactyl support";
-      ugetIntegrator = "Uget Integrator support";
-    };
+    nativeMessagingHosts = ({
+      packages = mkOption {
+        type = types.listOf types.package;
+        default = [];
+        description = mdDoc ''
+          Additional packages containing native messaging hosts that should be made available to Firefox extensions.
+        '';
+      };
+    }) // (mapAttrs (k: v: mkEnableOption (mdDoc "${v.name} support")) nmhOptions);
   };
 
-  config = mkIf cfg.enable {
+  config = let
+    forEachEnabledNmh = fn: flatten (mapAttrsToList (k: v: lib.optional cfg.nativeMessagingHosts.${k} (fn k v)) nmhOptions);
+  in mkIf cfg.enable {
+    warnings = forEachEnabledNmh (k: v:
+      "The `programs.firefox.nativeMessagingHosts.${k}` option is deprecated, " +
+      "please add `${v.package.pname}` to `programs.firefox.nativeMessagingHosts.packages` instead."
+    );
+    programs.firefox.nativeMessagingHosts.packages = forEachEnabledNmh (_: v: v.package);
+
     environment.systemPackages = [
       (cfg.package.override (old: {
-        extraPrefs = cfg.autoConfig;
-        extraNativeMessagingHosts =
-          old.extraNativeMessagingHosts or []
-          ++ optional nmh.ff2mpv pkgs.ff2mpv
-          ++ optional nmh.euwebid pkgs.web-eid-app
-          ++ optional nmh.gsconnect pkgs.gnomeExtensions.gsconnect
-          ++ optional nmh.jabref pkgs.jabref
-          ++ optional nmh.passff pkgs.passff-host;
-        cfg = let
-          # copy-pasted from the wrapper; TODO: figure out fix
-          applicationName = cfg.package.binaryName or (lib.getName cfg.package);
-
-          oldCfg = old.cfg or {};
-          nixpkgsConfig = pkgs.config.${applicationName} or {};
-          optionConfig = cfg.wrapperConfig;
-          nmhConfig = {
-            enableBrowserpass = nmh.browserpass;
-            enableBukubrow = nmh.bukubrow;
-            enableTridactylNative = nmh.tridactyl;
-            enableUgetIntegrator = nmh.ugetIntegrator;
-            enableFXCastBridge = nmh.fxCast;
-          };
-        in oldCfg // nixpkgsConfig // optionConfig // nmhConfig;
+        extraPrefsFiles = old.extraPrefsFiles or [] ++ [(pkgs.writeText "firefox-autoconfig.js" cfg.autoConfig)];
+        nativeMessagingHosts = old.nativeMessagingHosts or [] ++ cfg.nativeMessagingHosts.packages;
+        cfg = (old.cfg or {}) // cfg.wrapperConfig;
       }))
     ];
 
diff --git a/nixpkgs/nixos/modules/programs/wayland/cardboard.nix b/nixpkgs/nixos/modules/programs/wayland/cardboard.nix
new file mode 100644
index 000000000000..262c698c74ba
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/wayland/cardboard.nix
@@ -0,0 +1,24 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.programs.cardboard;
+in
+{
+  meta.maintainers = with lib.maintainers; [ AndersonTorres ];
+
+  options.programs.cardboard = {
+    enable = lib.mkEnableOption (lib.mdDoc "cardboard");
+
+    package = lib.mkPackageOptionMD pkgs "cardboard" { };
+  };
+
+  config = lib.mkIf cfg.enable (lib.mkMerge [
+    {
+      environment.systemPackages = [ cfg.package ];
+
+      # To make a cardboard session available for certain DMs like SDDM
+      services.xserver.displayManager.sessionPackages = [ cfg.package ];
+    }
+    (import ./wayland-session.nix { inherit lib pkgs; })
+  ]);
+}
diff --git a/nixpkgs/nixos/modules/security/acme/default.nix b/nixpkgs/nixos/modules/security/acme/default.nix
index f8e17bc71ee1..932bf3e79115 100644
--- a/nixpkgs/nixos/modules/security/acme/default.nix
+++ b/nixpkgs/nixos/modules/security/acme/default.nix
@@ -184,6 +184,7 @@ let
   certToConfig = cert: data: let
     acmeServer = data.server;
     useDns = data.dnsProvider != null;
+    useDnsOrS3 = useDns || data.s3Bucket != null;
     destPath = "/var/lib/acme/${cert}";
     selfsignedDeps = optionals (cfg.preliminarySelfsigned) [ "acme-selfsigned-${cert}.service" ];
 
@@ -219,7 +220,8 @@ let
       [ "--dns" data.dnsProvider ]
       ++ optionals (!data.dnsPropagationCheck) [ "--dns.disable-cp" ]
       ++ optionals (data.dnsResolver != null) [ "--dns.resolvers" data.dnsResolver ]
-    ) else if data.listenHTTP != null then [ "--http" "--http.port" data.listenHTTP ]
+    ) else if data.s3Bucket != null then [ "--http" "--http.s3-bucket" data.s3Bucket ]
+    else if data.listenHTTP != null then [ "--http" "--http.port" data.listenHTTP ]
     else [ "--http" "--http.webroot" data.webroot ];
 
     commonOpts = [
@@ -362,13 +364,12 @@ let
           "/var/lib/acme/.lego/${cert}/${certDir}:/tmp/certificates"
         ];
 
-        # Only try loading the environmentFile if the dns challenge is enabled
-        EnvironmentFile = mkIf useDns data.environmentFile;
+        EnvironmentFile = mkIf useDnsOrS3 data.environmentFile;
 
-        Environment = mkIf useDns
+        Environment = mkIf useDnsOrS3
           (mapAttrsToList (k: v: ''"${k}=%d/${k}"'') data.credentialFiles);
 
-        LoadCredential = mkIf useDns
+        LoadCredential = mkIf useDnsOrS3
           (mapAttrsToList (k: v: "${k}:${v}") data.credentialFiles);
 
         # Run as root (Prefixed with +)
@@ -755,6 +756,15 @@ let
         '';
       };
 
+      s3Bucket = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "acme";
+        description = lib.mdDoc ''
+          S3 bucket name to use for HTTP-01 based challenges. Challenges will be written to the S3 bucket.
+        '';
+      };
+
       inheritDefaults = mkOption {
         default = true;
         example = true;
@@ -928,35 +938,20 @@ in {
             and remove the wildcard from the path.
           '';
         }
-        {
-          assertion = data.dnsProvider == null || data.webroot == null;
-          message = ''
-            Options `security.acme.certs.${cert}.dnsProvider` and
-            `security.acme.certs.${cert}.webroot` are mutually exclusive.
-          '';
-        }
-        {
-          assertion = data.webroot == null || data.listenHTTP == null;
-          message = ''
-            Options `security.acme.certs.${cert}.webroot` and
-            `security.acme.certs.${cert}.listenHTTP` are mutually exclusive.
-          '';
-        }
-        {
-          assertion = data.listenHTTP == null || data.dnsProvider == null;
+        (let exclusiveAttrs = {
+          inherit (data) dnsProvider webroot listenHTTP s3Bucket;
+        }; in {
+          assertion = lib.length (lib.filter (x: x != null) (builtins.attrValues exclusiveAttrs)) == 1;
           message = ''
-            Options `security.acme.certs.${cert}.listenHTTP` and
-            `security.acme.certs.${cert}.dnsProvider` are mutually exclusive.
+            Exactly one of the options
+            `security.acme.certs.${cert}.dnsProvider`,
+            `security.acme.certs.${cert}.webroot`,
+            `security.acme.certs.${cert}.listenHTTP` and
+            `security.acme.certs.${cert}.s3Bucket`
+            is required.
+            Current values: ${(lib.generators.toPretty {} exclusiveAttrs)}.
           '';
-        }
-        {
-          assertion = data.dnsProvider != null || data.webroot != null || data.listenHTTP != null;
-          message = ''
-            One of `security.acme.certs.${cert}.dnsProvider`,
-            `security.acme.certs.${cert}.webroot`, or
-            `security.acme.certs.${cert}.listenHTTP` must be provided.
-          '';
-        }
+        })
         {
           assertion = all (hasSuffix "_FILE") (attrNames data.credentialFiles);
           message = ''
diff --git a/nixpkgs/nixos/modules/services/backup/bacula.nix b/nixpkgs/nixos/modules/services/backup/bacula.nix
index 0acbf1b3eabb..5a75a46e5259 100644
--- a/nixpkgs/nixos/modules/services/backup/bacula.nix
+++ b/nixpkgs/nixos/modules/services/backup/bacula.nix
@@ -15,16 +15,16 @@ let
       Client {
         Name = "${fd_cfg.name}";
         FDPort = ${toString fd_cfg.port};
-        WorkingDirectory = "${libDir}";
-        Pid Directory = "/run";
+        WorkingDirectory = ${libDir};
+        Pid Directory = /run;
         ${fd_cfg.extraClientConfig}
       }
 
       ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
       Director {
         Name = "${name}";
-        Password = "${value.password}";
-        Monitor = "${value.monitor}";
+        Password = ${value.password};
+        Monitor = ${value.monitor};
       }
       '') fd_cfg.director)}
 
@@ -41,8 +41,8 @@ let
       Storage {
         Name = "${sd_cfg.name}";
         SDPort = ${toString sd_cfg.port};
-        WorkingDirectory = "${libDir}";
-        Pid Directory = "/run";
+        WorkingDirectory = ${libDir};
+        Pid Directory = /run;
         ${sd_cfg.extraStorageConfig}
       }
 
@@ -50,8 +50,8 @@ let
       Autochanger {
         Name = "${name}";
         Device = ${concatStringsSep ", " (map (a: "\"${a}\"") value.devices)};
-        Changer Device =  "${value.changerDevice}";
-        Changer Command = "${value.changerCommand}";
+        Changer Device =  ${value.changerDevice};
+        Changer Command = ${value.changerCommand};
         ${value.extraAutochangerConfig}
       }
       '') sd_cfg.autochanger)}
@@ -59,8 +59,8 @@ let
       ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
       Device {
         Name = "${name}";
-        Archive Device = "${value.archiveDevice}";
-        Media Type = "${value.mediaType}";
+        Archive Device = ${value.archiveDevice};
+        Media Type = ${value.mediaType};
         ${value.extraDeviceConfig}
       }
       '') sd_cfg.device)}
@@ -68,8 +68,8 @@ let
       ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
       Director {
         Name = "${name}";
-        Password = "${value.password}";
-        Monitor = "${value.monitor}";
+        Password = ${value.password};
+        Monitor = ${value.monitor};
       }
       '') sd_cfg.director)}
 
@@ -85,18 +85,18 @@ let
     ''
     Director {
       Name = "${dir_cfg.name}";
-      Password = "${dir_cfg.password}";
+      Password = ${dir_cfg.password};
       DirPort = ${toString dir_cfg.port};
-      Working Directory = "${libDir}";
-      Pid Directory = "/run/";
-      QueryFile = "${pkgs.bacula}/etc/query.sql";
+      Working Directory = ${libDir};
+      Pid Directory = /run/;
+      QueryFile = ${pkgs.bacula}/etc/query.sql;
       ${dir_cfg.extraDirectorConfig}
     }
 
     Catalog {
-      Name = "PostgreSQL";
-      dbname = "bacula";
-      user = "bacula";
+      Name = PostgreSQL;
+      dbname = bacula;
+      user = bacula;
     }
 
     Messages {
@@ -533,7 +533,7 @@ in {
       };
     };
 
-    services.postgresql.enable = dir_cfg.enable == true;
+    services.postgresql.enable = lib.mkIf dir_cfg.enable true;
 
     systemd.services.bacula-dir = mkIf dir_cfg.enable {
       after = [ "network.target" "postgresql.service" ];
diff --git a/nixpkgs/nixos/modules/services/databases/ferretdb.nix b/nixpkgs/nixos/modules/services/databases/ferretdb.nix
index 45f822d64691..ab55e22bf214 100644
--- a/nixpkgs/nixos/modules/services/databases/ferretdb.nix
+++ b/nixpkgs/nixos/modules/services/databases/ferretdb.nix
@@ -30,7 +30,7 @@ in
         };
         description = ''
           Additional configuration for FerretDB, see
-          <https://docs.ferretdb.io/flags/>
+          <https://docs.ferretdb.io/configuration/flags/>
           for supported values.
         '';
       };
diff --git a/nixpkgs/nixos/modules/services/desktops/gnome/gnome-browser-connector.nix b/nixpkgs/nixos/modules/services/desktops/gnome/gnome-browser-connector.nix
index d18e303891e4..4f680eabbe15 100644
--- a/nixpkgs/nixos/modules/services/desktops/gnome/gnome-browser-connector.nix
+++ b/nixpkgs/nixos/modules/services/desktops/gnome/gnome-browser-connector.nix
@@ -42,6 +42,6 @@ in
 
     services.dbus.packages = [ pkgs.gnome-browser-connector ];
 
-    programs.firefox.wrapperConfig.enableGnomeExtensions = true;
+    programs.firefox.nativeMessagingHosts.packages = [ pkgs.gnome-browser-connector ];
   };
 }
diff --git a/nixpkgs/nixos/modules/services/home-automation/esphome.nix b/nixpkgs/nixos/modules/services/home-automation/esphome.nix
index d7dbb6f0b90e..080c8876382f 100644
--- a/nixpkgs/nixos/modules/services/home-automation/esphome.nix
+++ b/nixpkgs/nixos/modules/services/home-automation/esphome.nix
@@ -112,7 +112,7 @@ in
         ProtectKernelModules = true;
         ProtectKernelTunables = true;
         ProtectProc = "invisible";
-        ProcSubset = "pid";
+        ProcSubset = "all"; # Using "pid" breaks bwrap
         ProtectSystem = "strict";
         #RemoveIPC = true; # Implied by DynamicUser
         RestrictAddressFamilies = [
diff --git a/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix b/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix
index 99bac86a8e9a..0e6fa65667af 100644
--- a/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix
+++ b/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix
@@ -12,7 +12,7 @@ let
   # We post-process the result to add support for YAML functions, like secrets or includes, see e.g.
   # https://www.home-assistant.io/docs/configuration/secrets/
   filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! elem v [ null ])) cfg.config or {};
-  configFile = pkgs.runCommand "configuration.yaml" { preferLocalBuild = true; } ''
+  configFile = pkgs.runCommandLocal "configuration.yaml" { } ''
     cp ${format.generate "configuration.yaml" filteredConfig} $out
     sed -i -e "s/'\!\([a-z_]\+\) \(.*\)'/\!\1 \2/;s/^\!\!/\!/;" $out
   '';
diff --git a/nixpkgs/nixos/modules/services/matrix/synapse.nix b/nixpkgs/nixos/modules/services/matrix/synapse.nix
index b38b35361cf0..12e27ef26ff3 100644
--- a/nixpkgs/nixos/modules/services/matrix/synapse.nix
+++ b/nixpkgs/nixos/modules/services/matrix/synapse.nix
@@ -60,7 +60,6 @@ let
     ++ lib.optional (cfg.settings ? oidc_providers) "oidc"
     ++ lib.optional (cfg.settings ? jwt_config) "jwt"
     ++ lib.optional (cfg.settings ? saml2_config) "saml2"
-    ++ lib.optional (cfg.settings ? opentracing) "opentracing"
     ++ lib.optional (cfg.settings ? redis) "redis"
     ++ lib.optional (cfg.settings ? sentry) "sentry"
     ++ lib.optional (cfg.settings ? user_directory) "user-search"
@@ -334,7 +333,6 @@ in {
           [
             "cache-memory" # Provide statistics about caching memory consumption
             "jwt"          # JSON Web Token authentication
-            "opentracing"  # End-to-end tracing support using Jaeger
             "oidc"         # OpenID Connect authentication
             "postgres"     # PostgreSQL database backend
             "redis"        # Redis support for the replication stream between worker processes
diff --git a/nixpkgs/nixos/modules/services/misc/ssm-agent.nix b/nixpkgs/nixos/modules/services/misc/amazon-ssm-agent.nix
index d1f371c2bd61..0be79e759c31 100644
--- a/nixpkgs/nixos/modules/services/misc/ssm-agent.nix
+++ b/nixpkgs/nixos/modules/services/misc/amazon-ssm-agent.nix
@@ -2,7 +2,7 @@
 
 with lib;
 let
-  cfg = config.services.ssm-agent;
+  cfg = config.services.amazon-ssm-agent;
 
   # The SSM agent doesn't pay attention to our /etc/os-release yet, and the lsb-release tool
   # in nixpkgs doesn't seem to work properly on NixOS, so let's just fake the two fields SSM
@@ -16,19 +16,24 @@ let
     esac
   '';
 in {
-  options.services.ssm-agent = {
-    enable = mkEnableOption (lib.mdDoc "AWS SSM agent");
+  imports = [
+    (mkRenamedOptionModule [ "services" "ssm-agent" "enable" ] [ "services" "amazon-ssm-agent" "enable" ])
+    (mkRenamedOptionModule [ "services" "ssm-agent" "package" ] [ "services" "amazon-ssm-agent" "package" ])
+  ];
+
+  options.services.amazon-ssm-agent = {
+    enable = mkEnableOption (lib.mdDoc "Amazon SSM agent");
 
     package = mkOption {
       type = types.path;
-      description = lib.mdDoc "The SSM agent package to use";
-      default = pkgs.ssm-agent.override { overrideEtc = false; };
-      defaultText = literalExpression "pkgs.ssm-agent.override { overrideEtc = false; }";
+      description = lib.mdDoc "The Amazon SSM agent package to use";
+      default = pkgs.amazon-ssm-agent.override { overrideEtc = false; };
+      defaultText = literalExpression "pkgs.amazon-ssm-agent.override { overrideEtc = false; }";
     };
   };
 
   config = mkIf cfg.enable {
-    systemd.services.ssm-agent = {
+    systemd.services.amazon-ssm-agent = {
       inherit (cfg.package.meta) description;
       after    = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
diff --git a/nixpkgs/nixos/modules/services/misc/forgejo.nix b/nixpkgs/nixos/modules/services/misc/forgejo.nix
index b2920981efbd..90b5f16f4189 100644
--- a/nixpkgs/nixos/modules/services/misc/forgejo.nix
+++ b/nixpkgs/nixos/modules/services/misc/forgejo.nix
@@ -632,6 +632,8 @@ in
       };
     };
 
+    services.openssh.settings.AcceptEnv = mkIf (!cfg.settings.START_SSH_SERVER or false) "GIT_PROTOCOL";
+
     users.users = mkIf (cfg.user == "forgejo") {
       forgejo = {
         home = cfg.stateDir;
diff --git a/nixpkgs/nixos/modules/services/monitoring/munin.nix b/nixpkgs/nixos/modules/services/monitoring/munin.nix
index f37f2689927e..90a51181ac30 100644
--- a/nixpkgs/nixos/modules/services/monitoring/munin.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/munin.nix
@@ -83,42 +83,47 @@ let
   # Copy one Munin plugin into the Nix store with a specific name.
   # This is suitable for use with plugins going directly into /etc/munin/plugins,
   # i.e. munin.extraPlugins.
-  internOnePlugin = name: path:
+  internOnePlugin = { name, path }:
     "cp -a '${path}' '${name}'";
 
   # Copy an entire tree of Munin plugins into a single directory in the Nix
-  # store, with no renaming.
-  # This is suitable for use with munin-node-configure --suggest, i.e.
-  # munin.extraAutoPlugins.
-  internManyPlugins = name: path:
+  # store, with no renaming. The output is suitable for use with
+  # munin-node-configure --suggest, i.e. munin.extraAutoPlugins.
+  # Note that this flattens the input; this is intentional, as
+  # munin-node-configure won't recurse into subdirectories.
+  internManyPlugins = path:
     "find '${path}' -type f -perm /a+x -exec cp -a -t . '{}' '+'";
 
   # Use the appropriate intern-fn to copy the plugins into the store and patch
   # them afterwards in an attempt to get them to run on NixOS.
+  # This is a bit hairy because we can't just fix shebangs; lots of munin plugins
+  # hardcode paths like /sbin/mount rather than trusting $PATH, so we have to
+  # look for and update those throughout the script. At the same time, if the
+  # plugin comes from a package that is already nixified, we don't want to
+  # rewrite paths like /nix/store/foo/sbin/mount.
+  # For now we make the simplifying assumption that no file will contain lines
+  # which mix store paths and FHS paths, and thus run our substitution only on
+  # lines which do not contain store paths.
   internAndFixPlugins = name: intern-fn: paths:
     pkgs.runCommand name {} ''
       mkdir -p "$out"
       cd "$out"
-      ${lib.concatStringsSep "\n"
-          (lib.attrsets.mapAttrsToList intern-fn paths)}
+      ${lib.concatStringsSep "\n" (map intern-fn paths)}
       chmod -R u+w .
-      find . -type f -exec sed -E -i '
-        s,(/usr)?/s?bin/,/run/current-system/sw/bin/,g
-      ' '{}' '+'
+      ${pkgs.findutils}/bin/find . -type f -exec ${pkgs.gnused}/bin/sed -E -i "
+        \%''${NIX_STORE}/%! s,(/usr)?/s?bin/,/run/current-system/sw/bin/,g
+      " '{}' '+'
     '';
 
   # TODO: write a derivation for munin-contrib, so that for contrib plugins
   # you can just refer to them by name rather than needing to include a copy
   # of munin-contrib in your nixos configuration.
   extraPluginDir = internAndFixPlugins "munin-extra-plugins.d"
-    internOnePlugin nodeCfg.extraPlugins;
+    internOnePlugin
+    (lib.attrsets.mapAttrsToList (k: v: { name = k; path = v; }) nodeCfg.extraPlugins);
 
   extraAutoPluginDir = internAndFixPlugins "munin-extra-auto-plugins.d"
-    internManyPlugins
-    (builtins.listToAttrs
-      (map
-        (path: { name = baseNameOf path; value = path; })
-        nodeCfg.extraAutoPlugins));
+    internManyPlugins nodeCfg.extraAutoPlugins;
 
   customStaticDir = pkgs.runCommand "munin-custom-static-data" {} ''
     cp -a "${pkgs.munin}/etc/opt/munin/static" "$out"
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix
index ed33c72f644f..8b1cd47d0a40 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix
@@ -15,8 +15,8 @@ in {
       type = types.listOf types.str;
       example = literalExpression ''
         [
-          "/run/kea/kea-dhcp4.socket"
-          "/run/kea/kea-dhcp6.socket"
+          "/run/kea-dhcp4/kea-dhcp4.socket"
+          "/run/kea-dhcp6/kea-dhcp6.socket"
         ]
       '';
       description = lib.mdDoc ''
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix
index a73425b37da7..775848750803 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix
@@ -8,9 +8,9 @@ in {
   port = 9433;
   extraOpts = {
     knotLibraryPath = mkOption {
-      type = types.str;
-      default = "${pkgs.knot-dns.out}/lib/libknot.so";
-      defaultText = literalExpression ''"''${pkgs.knot-dns.out}/lib/libknot.so"'';
+      type = types.nullOr types.str;
+      default = null;
+      example = literalExpression ''"''${pkgs.knot-dns.out}/lib/libknot.so"'';
       description = lib.mdDoc ''
         Path to the library of `knot-dns`.
       '';
@@ -25,7 +25,7 @@ in {
     };
 
     knotSocketTimeout = mkOption {
-      type = types.int;
+      type = types.ints.positive;
       default = 2000;
       description = lib.mdDoc ''
         Timeout in seconds.
@@ -33,17 +33,22 @@ in {
     };
   };
   serviceOpts = {
+    path = with pkgs; [
+      procps
+    ];
     serviceConfig = {
       ExecStart = ''
-        ${pkgs.prometheus-knot-exporter}/bin/knot_exporter \
+        ${pkgs.prometheus-knot-exporter}/bin/knot-exporter \
           --web-listen-addr ${cfg.listenAddress} \
           --web-listen-port ${toString cfg.port} \
-          --knot-library-path ${cfg.knotLibraryPath} \
           --knot-socket-path ${cfg.knotSocketPath} \
           --knot-socket-timeout ${toString cfg.knotSocketTimeout} \
+          ${lib.optionalString (cfg.knotLibraryPath != null) "--knot-library-path ${cfg.knotLibraryPath}"} \
           ${concatStringsSep " \\\n  " cfg.extraFlags}
       '';
-      SupplementaryGroups = [ "knot" ];
+      SupplementaryGroups = [
+        "knot"
+      ];
       RestrictAddressFamilies = [
         # Need AF_UNIX to collect data
         "AF_UNIX"
diff --git a/nixpkgs/nixos/modules/services/networking/fastnetmon-advanced.nix b/nixpkgs/nixos/modules/services/networking/fastnetmon-advanced.nix
new file mode 100644
index 000000000000..26e8ad8b76d9
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/fastnetmon-advanced.nix
@@ -0,0 +1,222 @@
+{ config, lib, pkgs, ... }:
+
+let
+  # Background information: FastNetMon requires a MongoDB to start. This is because
+  # it uses MongoDB to store its configuration. That is, in a normal setup there is
+  # one collection with one document.
+  # To provide declarative configuration in our NixOS module, this database is
+  # completely emptied and replaced on each boot by the fastnetmon-setup service
+  # using the configuration backup functionality.
+
+  cfg = config.services.fastnetmon-advanced;
+  settingsFormat = pkgs.formats.yaml { };
+
+  # obtain the default configs by starting up ferretdb and fcli in a derivation
+  default_configs = pkgs.runCommand "default-configs" {
+    nativeBuildInputs = [
+      pkgs.ferretdb
+      pkgs.fastnetmon-advanced # for fcli
+      pkgs.proot
+    ];
+  } ''
+    mkdir ferretdb fastnetmon $out
+    FERRETDB_TELEMETRY="disable" FERRETDB_HANDLER="sqlite" FERRETDB_STATE_DIR="$PWD/ferretdb" FERRETDB_SQLITE_URL="file:$PWD/ferretdb/" ferretdb &
+
+    cat << EOF > fastnetmon/fastnetmon.conf
+    ${builtins.toJSON {
+      mongodb_username = "";
+    }}
+    EOF
+    proot -b fastnetmon:/etc/fastnetmon -0 fcli create_configuration
+    proot -b fastnetmon:/etc/fastnetmon -0 fcli set bgp default
+    proot -b fastnetmon:/etc/fastnetmon -0 fcli export_configuration backup.tar
+    tar -C $out --no-same-owner -xvf backup.tar
+  '';
+
+  # merge the user configs into the default configs
+  config_tar = pkgs.runCommand "fastnetmon-config.tar" {
+    nativeBuildInputs = with pkgs; [ jq ];
+  } ''
+    jq -s add ${default_configs}/main.json ${pkgs.writeText "main-add.json" (builtins.toJSON cfg.settings)} > main.json
+    mkdir hostgroup
+    ${lib.concatImapStringsSep "\n" (pos: hostgroup: ''
+      jq -s add ${default_configs}/hostgroup/0.json ${pkgs.writeText "hostgroup-${toString (pos - 1)}-add.json" (builtins.toJSON hostgroup)} > hostgroup/${toString (pos - 1)}.json
+    '') hostgroups}
+    mkdir bgp
+    ${lib.concatImapStringsSep "\n" (pos: bgp: ''
+      jq -s add ${default_configs}/bgp/0.json ${pkgs.writeText "bgp-${toString (pos - 1)}-add.json" (builtins.toJSON bgp)} > bgp/${toString (pos - 1)}.json
+    '') bgpPeers}
+    tar -cf $out main.json ${lib.concatImapStringsSep " " (pos: _: "hostgroup/${toString (pos - 1)}.json") hostgroups} ${lib.concatImapStringsSep " " (pos: _: "bgp/${toString (pos - 1)}.json") bgpPeers}
+  '';
+
+  hostgroups = lib.mapAttrsToList (name: hostgroup: { inherit name; } // hostgroup) cfg.hostgroups;
+  bgpPeers = lib.mapAttrsToList (name: bgpPeer: { inherit name; } // bgpPeer) cfg.bgpPeers;
+
+in {
+  options.services.fastnetmon-advanced = with lib; {
+    enable = mkEnableOption "the fastnetmon-advanced DDoS Protection daemon";
+
+    settings = mkOption {
+      description = ''
+        Extra configuration options to declaratively load into FastNetMon Advanced.
+
+        See the [FastNetMon Advanced Configuration options reference](https://fastnetmon.com/docs-fnm-advanced/fastnetmon-advanced-configuration-options/) for more details.
+      '';
+      type = settingsFormat.type;
+      default = {};
+      example = literalExpression ''
+        {
+          networks_list = [ "192.0.2.0/24" ];
+          gobgp = true;
+          gobgp_flow_spec_announces = true;
+        }
+      '';
+    };
+    hostgroups = mkOption {
+      description = "Hostgroups to declaratively load into FastNetMon Advanced";
+      type = types.attrsOf settingsFormat.type;
+      default = {};
+    };
+    bgpPeers = mkOption {
+      description = "BGP Peers to declaratively load into FastNetMon Advanced";
+      type = types.attrsOf settingsFormat.type;
+      default = {};
+    };
+
+    enableAdvancedTrafficPersistence = mkOption {
+      description = "Store historical flow data in clickhouse";
+      type = types.bool;
+      default = false;
+    };
+
+    traffic_db.settings = mkOption {
+      type = settingsFormat.type;
+      description = "Additional settings for /etc/fastnetmon/traffic_db.conf";
+    };
+  };
+
+  config = lib.mkMerge [ (lib.mkIf cfg.enable {
+    environment.systemPackages = with pkgs; [
+      fastnetmon-advanced # for fcli
+    ];
+
+    environment.etc."fastnetmon/license.lic".source = "/var/lib/fastnetmon/license.lic";
+    environment.etc."fastnetmon/gobgpd.conf".source = "/run/fastnetmon/gobgpd.conf";
+    environment.etc."fastnetmon/fastnetmon.conf".source = pkgs.writeText "fastnetmon.conf" (builtins.toJSON {
+      mongodb_username = "";
+    });
+
+    services.ferretdb.enable = true;
+
+    systemd.services.fastnetmon-setup = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "ferretdb.service" ];
+      path = with pkgs; [ fastnetmon-advanced config.systemd.package ];
+      script = ''
+        fcli create_configuration
+        fcli delete hostgroup global
+        fcli import_configuration ${config_tar}
+        systemctl --no-block try-restart fastnetmon
+      '';
+      serviceConfig.Type = "oneshot";
+    };
+
+    systemd.services.fastnetmon = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "ferretdb.service" "fastnetmon-setup.service" "polkit.service" ];
+      path = with pkgs; [ iproute2 ];
+      unitConfig = {
+        # Disable logic which shuts service when we do too many restarts
+        # We do restarts from sudo fcli commit and it's expected that we may have many restarts
+        # Details: https://github.com/systemd/systemd/issues/2416
+        StartLimitInterval = 0;
+      };
+      serviceConfig = {
+        ExecStart = "${pkgs.fastnetmon-advanced}/bin/fastnetmon --log_to_console";
+
+        LimitNOFILE = 65535;
+        # Restart service when it fails due to any reasons, we need to keep processing traffic no matter what happened
+        Restart= "on-failure";
+        RestartSec= "5s";
+
+        DynamicUser = true;
+        CacheDirectory = "fastnetmon";
+        RuntimeDirectory = "fastnetmon"; # for gobgpd config
+        StateDirectory = "fastnetmon"; # for license file
+      };
+    };
+
+    security.polkit.enable = true;
+    security.polkit.extraConfig = ''
+      polkit.addRule(function(action, subject) {
+        if (action.id == "org.freedesktop.systemd1.manage-units" &&
+          subject.isInGroup("fastnetmon")) {
+          if (action.lookup("unit") == "gobgp.service") {
+            var verb = action.lookup("verb");
+            if (verb == "start" || verb == "stop" || verb == "restart") {
+              return polkit.Result.YES;
+            }
+          }
+        }
+      });
+    '';
+
+    # We don't use the existing gobgp NixOS module and package, because the gobgp
+    # version might not be compatible with fastnetmon. Also, the service name
+    # _must_ be 'gobgp' and not 'gobgpd', so that fastnetmon can reload the config.
+    systemd.services.gobgp = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      description = "GoBGP Routing Daemon";
+      unitConfig = {
+        ConditionPathExists = "/run/fastnetmon/gobgpd.conf";
+      };
+      serviceConfig = {
+        Type = "notify";
+        ExecStartPre = "${pkgs.fastnetmon-advanced}/bin/fnm-gobgpd -f /run/fastnetmon/gobgpd.conf -d";
+        SupplementaryGroups = [ "fastnetmon" ];
+        ExecStart = "${pkgs.fastnetmon-advanced}/bin/fnm-gobgpd -f /run/fastnetmon/gobgpd.conf --sdnotify";
+        ExecReload = "${pkgs.fastnetmon-advanced}/bin/fnm-gobgpd -r";
+        DynamicUser = true;
+        AmbientCapabilities = "cap_net_bind_service";
+      };
+    };
+  })
+
+  (lib.mkIf (cfg.enable && cfg.enableAdvancedTrafficPersistence) {
+    ## Advanced Traffic persistence
+    ## https://fastnetmon.com/docs-fnm-advanced/fastnetmon-advanced-traffic-persistency/
+
+    services.clickhouse.enable = true;
+
+    services.fastnetmon-advanced.settings.traffic_db = true;
+
+    services.fastnetmon-advanced.traffic_db.settings = {
+      clickhouse_batch_size = lib.mkDefault 1000;
+      clickhouse_batch_delay = lib.mkDefault 1;
+      traffic_db_host = lib.mkDefault "127.0.0.1";
+      traffic_db_port = lib.mkDefault 8100;
+      clickhouse_host = lib.mkDefault "127.0.0.1";
+      clickhouse_port = lib.mkDefault 9000;
+      clickhouse_user = lib.mkDefault "default";
+      clickhouse_password = lib.mkDefault "";
+    };
+    environment.etc."fastnetmon/traffic_db.conf".text = builtins.toJSON cfg.traffic_db.settings;
+
+    systemd.services.traffic_db = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      serviceConfig = {
+        ExecStart = "${pkgs.fastnetmon-advanced}/bin/traffic_db";
+        # Restart service when it fails due to any reasons, we need to keep processing traffic no matter what happened
+        Restart= "on-failure";
+        RestartSec= "5s";
+
+        DynamicUser = true;
+      };
+    };
+
+  }) ];
+
+  meta.maintainers = lib.teams.wdz.members;
+}
diff --git a/nixpkgs/nixos/modules/services/networking/kea.nix b/nixpkgs/nixos/modules/services/networking/kea.nix
index 945f4113bd47..2f922a026a3a 100644
--- a/nixpkgs/nixos/modules/services/networking/kea.nix
+++ b/nixpkgs/nixos/modules/services/networking/kea.nix
@@ -254,7 +254,6 @@ in
       DynamicUser = true;
       User = "kea";
       ConfigurationDirectory = "kea";
-      RuntimeDirectory = "kea";
       StateDirectory = "kea";
       UMask = "0077";
     };
@@ -289,8 +288,8 @@ in
       ];
 
       environment = {
-        KEA_PIDFILE_DIR = "/run/kea";
-        KEA_LOCKFILE_DIR = "/run/kea";
+        KEA_PIDFILE_DIR = "/run/kea-ctrl-agent";
+        KEA_LOCKFILE_DIR = "/run/kea-ctrl-agent";
       };
 
       restartTriggers = [
@@ -301,6 +300,7 @@ in
         ExecStart = "${package}/bin/kea-ctrl-agent -c /etc/kea/ctrl-agent.conf ${lib.escapeShellArgs cfg.ctrl-agent.extraArgs}";
         KillMode = "process";
         Restart = "on-failure";
+        RuntimeDirectory = "kea-ctrl-agent";
       } // commonServiceConfig;
     };
   })
@@ -329,8 +329,8 @@ in
       ];
 
       environment = {
-        KEA_PIDFILE_DIR = "/run/kea";
-        KEA_LOCKFILE_DIR = "/run/kea";
+        KEA_PIDFILE_DIR = "/run/kea-dhcp4";
+        KEA_LOCKFILE_DIR = "/run/kea-dhcp4";
       };
 
       restartTriggers = [
@@ -348,6 +348,7 @@ in
           "CAP_NET_BIND_SERVICE"
           "CAP_NET_RAW"
         ];
+        RuntimeDirectory = "kea-dhcp4";
       } // commonServiceConfig;
     };
   })
@@ -376,8 +377,8 @@ in
       ];
 
       environment = {
-        KEA_PIDFILE_DIR = "/run/kea";
-        KEA_LOCKFILE_DIR = "/run/kea";
+        KEA_PIDFILE_DIR = "/run/kea-dhcp6";
+        KEA_LOCKFILE_DIR = "/run/kea-dhcp6";
       };
 
       restartTriggers = [
@@ -393,6 +394,7 @@ in
         CapabilityBoundingSet = [
           "CAP_NET_BIND_SERVICE"
         ];
+        RuntimeDirectory = "kea-dhcp6";
       } // commonServiceConfig;
     };
   })
@@ -421,8 +423,8 @@ in
       ];
 
       environment = {
-        KEA_PIDFILE_DIR = "/run/kea";
-        KEA_LOCKFILE_DIR = "/run/kea";
+        KEA_PIDFILE_DIR = "/run/kea-dhcp-ddns";
+        KEA_LOCKFILE_DIR = "/run/kea-dhcp-ddns";
       };
 
       restartTriggers = [
@@ -437,6 +439,7 @@ in
         CapabilityBoundingSet = [
           "CAP_NET_BIND_SERVICE"
         ];
+        RuntimeDirectory = "kea-dhcp-ddns";
       } // commonServiceConfig;
     };
   })
diff --git a/nixpkgs/nixos/modules/services/networking/rosenpass.nix b/nixpkgs/nixos/modules/services/networking/rosenpass.nix
new file mode 100644
index 000000000000..d2a264b83d67
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/rosenpass.nix
@@ -0,0 +1,233 @@
+{ config
+, lib
+, options
+, pkgs
+, ...
+}:
+let
+  inherit (lib)
+    attrValues
+    concatLines
+    concatMap
+    filter
+    filterAttrsRecursive
+    flatten
+    getExe
+    mdDoc
+    mkIf
+    optional
+    ;
+
+  cfg = config.services.rosenpass;
+  opt = options.services.rosenpass;
+  settingsFormat = pkgs.formats.toml { };
+in
+{
+  options.services.rosenpass =
+    let
+      inherit (lib)
+        literalExpression
+        mdDoc
+        mkOption
+        ;
+      inherit (lib.types)
+        enum
+        listOf
+        nullOr
+        path
+        str
+        submodule
+        ;
+    in
+    {
+      enable = lib.mkEnableOption (mdDoc "Rosenpass");
+
+      package = lib.mkPackageOption pkgs "rosenpass" { };
+
+      defaultDevice = mkOption {
+        type = nullOr str;
+        description = mdDoc "Name of the network interface to use for all peers by default.";
+        example = "wg0";
+      };
+
+      settings = mkOption {
+        type = submodule {
+          freeformType = settingsFormat.type;
+
+          options = {
+            public_key = mkOption {
+              type = path;
+              description = mdDoc "Path to a file containing the public key of the local Rosenpass peer. Generate this by running {command}`rosenpass gen-keys`.";
+            };
+
+            secret_key = mkOption {
+              type = path;
+              description = mdDoc "Path to a file containing the secret key of the local Rosenpass peer. Generate this by running {command}`rosenpass gen-keys`.";
+            };
+
+            listen = mkOption {
+              type = listOf str;
+              description = mdDoc "List of local endpoints to listen for connections.";
+              default = [ ];
+              example = literalExpression "[ \"0.0.0.0:10000\" ]";
+            };
+
+            verbosity = mkOption {
+              type = enum [ "Verbose" "Quiet" ];
+              default = "Quiet";
+              description = mdDoc "Verbosity of output produced by the service.";
+            };
+
+            peers =
+              let
+                peer = submodule {
+                  freeformType = settingsFormat.type;
+
+                  options = {
+                    public_key = mkOption {
+                      type = path;
+                      description = mdDoc "Path to a file containing the public key of the remote Rosenpass peer.";
+                    };
+
+                    endpoint = mkOption {
+                      type = nullOr str;
+                      default = null;
+                      description = mdDoc "Endpoint of the remote Rosenpass peer.";
+                    };
+
+                    device = mkOption {
+                      type = str;
+                      default = cfg.defaultDevice;
+                      defaultText = literalExpression "config.${opt.defaultDevice}";
+                      description = mdDoc "Name of the local WireGuard interface to use for this peer.";
+                    };
+
+                    peer = mkOption {
+                      type = str;
+                      description = mdDoc "WireGuard public key corresponding to the remote Rosenpass peer.";
+                    };
+                  };
+                };
+              in
+              mkOption {
+                type = listOf peer;
+                description = mdDoc "List of peers to exchange keys with.";
+                default = [ ];
+              };
+          };
+        };
+        default = { };
+        description = mdDoc "Configuration for Rosenpass, see <https://rosenpass.eu/> for further information.";
+      };
+    };
+
+  config = mkIf cfg.enable {
+    warnings =
+      let
+        # NOTE: In the descriptions below, we tried to refer to e.g.
+        # options.systemd.network.netdevs."<name>".wireguardPeers.*.PublicKey
+        # directly, but don't know how to traverse "<name>" and * in this path.
+        extractions = [
+          {
+            relevant = config.systemd.network.enable;
+            root = config.systemd.network.netdevs;
+            peer = (x: x.wireguardPeers);
+            key = (x: if x.wireguardPeerConfig ? PublicKey then x.wireguardPeerConfig.PublicKey else null);
+            description = mdDoc "${options.systemd.network.netdevs}.\"<name>\".wireguardPeers.*.wireguardPeerConfig.PublicKey";
+          }
+          {
+            relevant = config.networking.wireguard.enable;
+            root = config.networking.wireguard.interfaces;
+            peer = (x: x.peers);
+            key = (x: x.publicKey);
+            description = mdDoc "${options.networking.wireguard.interfaces}.\"<name>\".peers.*.publicKey";
+          }
+          rec {
+            relevant = root != { };
+            root = config.networking.wg-quick.interfaces;
+            peer = (x: x.peers);
+            key = (x: x.publicKey);
+            description = mdDoc "${options.networking.wg-quick.interfaces}.\"<name>\".peers.*.publicKey";
+          }
+        ];
+        relevantExtractions = filter (x: x.relevant) extractions;
+        extract = { root, peer, key, ... }:
+          filter (x: x != null) (flatten (concatMap (x: (map key (peer x))) (attrValues root)));
+        configuredKeys = flatten (map extract relevantExtractions);
+        itemize = xs: concatLines (map (x: " - ${x}") xs);
+        descriptions = map (x: "`${x.description}`");
+        missingKeys = filter (key: !builtins.elem key configuredKeys) (map (x: x.peer) cfg.settings.peers);
+        unusual = ''
+          While this may work as expected, e.g. you want to manually configure WireGuard,
+          such a scenario is unusual. Please double-check your configuration.
+        '';
+      in
+      (optional (relevantExtractions != [ ] && missingKeys != [ ]) ''
+        You have configured Rosenpass peers with the WireGuard public keys:
+        ${itemize missingKeys}
+        But there is no corresponding active Wireguard peer configuration in any of:
+        ${itemize (descriptions relevantExtractions)}
+        ${unusual}
+      '')
+      ++
+      optional (relevantExtractions == [ ]) ''
+        You have configured Rosenpass, but you have not configured Wireguard via any of:
+        ${itemize (descriptions extractions)}
+        ${unusual}
+      '';
+
+    environment.systemPackages = [ cfg.package pkgs.wireguard-tools ];
+
+    systemd.services.rosenpass =
+      let
+        filterNonNull = filterAttrsRecursive (_: v: v != null);
+        config = settingsFormat.generate "config.toml" (
+          filterNonNull (cfg.settings
+            //
+            (
+              let
+                credentialPath = id: "$CREDENTIALS_DIRECTORY/${id}";
+                # NOTE: We would like to remove all `null` values inside `cfg.settings`
+                # recursively, since `settingsFormat.generate` cannot handle `null`.
+                # This would require to traverse both attribute sets and lists recursively.
+                # `filterAttrsRecursive` only recurses into attribute sets, but not
+                # into values that might contain other attribute sets (such as lists,
+                # e.g. `cfg.settings.peers`). Here, we just specialize on `cfg.settings.peers`,
+                # and this may break unexpectedly whenever a `null` value is contained
+                # in a list in `cfg.settings`, other than `cfg.settings.peers`.
+                peersWithoutNulls = map filterNonNull cfg.settings.peers;
+              in
+              {
+                secret_key = credentialPath "pqsk";
+                public_key = credentialPath "pqpk";
+                peers = peersWithoutNulls;
+              }
+            )
+          )
+        );
+      in
+      rec {
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-online.target" ];
+        path = [ cfg.package pkgs.wireguard-tools ];
+
+        serviceConfig = {
+          User = "rosenpass";
+          Group = "rosenpass";
+          RuntimeDirectory = "rosenpass";
+          DynamicUser = true;
+          AmbientCapabilities = [ "CAP_NET_ADMIN" ];
+          LoadCredential = [
+            "pqsk:${cfg.settings.secret_key}"
+            "pqpk:${cfg.settings.public_key}"
+          ];
+        };
+
+        # See <https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers>
+        environment.CONFIG = "%t/${serviceConfig.RuntimeDirectory}/config.toml";
+
+        preStart = "${getExe pkgs.envsubst} -i ${config} -o \"$CONFIG\"";
+        script = "rosenpass exchange-config \"$CONFIG\"";
+      };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/networking/syncthing.nix b/nixpkgs/nixos/modules/services/networking/syncthing.nix
index c4b2d0e80f9b..bdcdaf056d03 100644
--- a/nixpkgs/nixos/modules/services/networking/syncthing.nix
+++ b/nixpkgs/nixos/modules/services/networking/syncthing.nix
@@ -10,6 +10,21 @@ let
   settingsFormat = pkgs.formats.json { };
   cleanedConfig = converge (filterAttrsRecursive (_: v: v != null && v != {})) cfg.settings;
 
+  isUnixGui = (builtins.substring 0 1 cfg.guiAddress) == "/";
+
+  # Syncthing supports serving the GUI over Unix sockets. If that happens, the
+  # API is served over the Unix socket as well.  This function returns the correct
+  # curl arguments for the address portion of the curl command for both network
+  # and Unix socket addresses.
+  curlAddressArgs = path: if isUnixGui
+    # if cfg.guiAddress is a unix socket, tell curl explicitly about it
+    # note that the dot in front of `${path}` is the hostname, which is
+    # required.
+    then "--unix-socket ${cfg.guiAddress} http://.${path}"
+    # no adjustements are needed if cfg.guiAddress is a network address
+    else "${cfg.guiAddress}${path}"
+    ;
+
   devices = mapAttrsToList (_: device: device // {
     deviceID = device.id;
   }) cfg.settings.devices;
@@ -62,14 +77,14 @@ let
       GET_IdAttrName = "deviceID";
       override = cfg.overrideDevices;
       conf = devices;
-      baseAddress = "${cfg.guiAddress}/rest/config/devices";
+      baseAddress = curlAddressArgs "/rest/config/devices";
     };
     dirs = {
       new_conf_IDs = map (v: v.id) folders;
       GET_IdAttrName = "id";
       override = cfg.overrideFolders;
       conf = folders;
-      baseAddress = "${cfg.guiAddress}/rest/config/folders";
+      baseAddress = curlAddressArgs "/rest/config/folders";
     };
   } [
     # Now for each of these attributes, write the curl commands that are
@@ -117,15 +132,14 @@ let
     builtins.attrNames
     (lib.subtractLists ["folders" "devices"])
     (map (subOption: ''
-      curl -X PUT -d ${lib.escapeShellArg (builtins.toJSON cleanedConfig.${subOption})} \
-        ${cfg.guiAddress}/rest/config/${subOption}
+      curl -X PUT -d ${lib.escapeShellArg (builtins.toJSON cleanedConfig.${subOption})} ${curlAddressArgs "/rest/config/${subOption}"}
     ''))
     (lib.concatStringsSep "\n")
   ]) + ''
     # restart Syncthing if required
-    if curl ${cfg.guiAddress}/rest/config/restart-required |
+    if curl ${curlAddressArgs "/rest/config/restart-required"} |
        ${jq} -e .requiresRestart > /dev/null; then
-        curl -X POST ${cfg.guiAddress}/rest/system/restart
+        curl -X POST ${curlAddressArgs "/rest/system/restart"}
     fi
   '');
 in {
@@ -651,7 +665,7 @@ in {
           ExecStart = ''
             ${cfg.package}/bin/syncthing \
               -no-browser \
-              -gui-address=${cfg.guiAddress} \
+              -gui-address=${if isUnixGui then "unix://" else ""}${cfg.guiAddress} \
               -home=${cfg.configDir} ${escapeShellArgs cfg.extraFlags}
           '';
           MemoryDenyWriteExecute = true;
diff --git a/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix b/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix
index 0595e9e6df23..90d9c68433cf 100644
--- a/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix
@@ -530,5 +530,5 @@ in {
     '';
   };
 
-  meta.maintainers = with lib.maintainers; [ globin rnhmjoj ];
+  meta.maintainers = with lib.maintainers; [ rnhmjoj ];
 }
diff --git a/nixpkgs/nixos/modules/services/web-apps/akkoma.nix b/nixpkgs/nixos/modules/services/web-apps/akkoma.nix
index 8d1775258612..eaee70c712bb 100644
--- a/nixpkgs/nixos/modules/services/web-apps/akkoma.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/akkoma.nix
@@ -282,11 +282,11 @@ let
         AKKOMA_CONFIG_PATH="$RUNTIME_DIRECTORY/config.exs" \
         ERL_EPMD_ADDRESS="${cfg.dist.address}" \
         ERL_EPMD_PORT="${toString cfg.dist.epmdPort}" \
-        ERL_FLAGS="${concatStringsSep " " [
-          "-kernel inet_dist_use_interface '${erlAddr cfg.dist.address}'"
-          "-kernel inet_dist_listen_min ${toString cfg.dist.portMin}"
-          "-kernel inet_dist_listen_max ${toString cfg.dist.portMax}"
-        ]}" \
+        ERL_FLAGS=${lib.escapeShellArg (lib.escapeShellArgs ([
+          "-kernel" "inet_dist_use_interface" (erlAddr cfg.dist.address)
+          "-kernel" "inet_dist_listen_min" (toString cfg.dist.portMin)
+          "-kernel" "inet_dist_listen_max" (toString cfg.dist.portMax)
+        ] ++ cfg.dist.extraFlags))} \
         RELEASE_COOKIE="$(<"$RUNTIME_DIRECTORY/cookie")" \
         RELEASE_NAME="akkoma" \
           exec "${cfg.package}/bin/$(basename "$0")" "$@"
@@ -553,6 +553,13 @@ in {
           description = mdDoc "TCP port to bind Erlang Port Mapper Daemon to.";
         };
 
+        extraFlags = mkOption {
+          type = with types; listOf str;
+          default = [ ];
+          description = mdDoc "Extra flags to pass to Erlang";
+          example = [ "+sbwt" "none" "+sbwtdcpu" "none" "+sbwtdio" "none" ];
+        };
+
         portMin = mkOption {
           type = types.port;
           default = 49152;
diff --git a/nixpkgs/nixos/modules/services/web-apps/lanraragi.nix b/nixpkgs/nixos/modules/services/web-apps/lanraragi.nix
new file mode 100644
index 000000000000..f1ab8b8b4eb4
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/lanraragi.nix
@@ -0,0 +1,100 @@
+{ pkgs, lib, config, ... }:
+
+let
+  cfg = config.services.lanraragi;
+in
+{
+  meta.maintainers = with lib.maintainers; [ tomasajt ];
+
+  options.services = {
+    lanraragi = {
+      enable = lib.mkEnableOption (lib.mdDoc "LANraragi");
+      package = lib.mkPackageOptionMD pkgs "lanraragi" { };
+
+      port = lib.mkOption {
+        type = lib.types.port;
+        default = 3000;
+        description = lib.mdDoc "Port for LANraragi's web interface.";
+      };
+
+      passwordFile = lib.mkOption {
+        type = lib.types.nullOr lib.types.path;
+        default = null;
+        example = "/run/keys/lanraragi-password";
+        description = lib.mdDoc ''
+          A file containing the password for LANraragi's admin interface.
+        '';
+      };
+
+      redis = {
+        port = lib.mkOption {
+          type = lib.types.port;
+          default = 6379;
+          description = lib.mdDoc "Port for LANraragi's Redis server.";
+        };
+        passwordFile = lib.mkOption {
+          type = lib.types.nullOr lib.types.path;
+          default = null;
+          example = "/run/keys/redis-lanraragi-password";
+          description = lib.mdDoc ''
+            A file containing the password for LANraragi's Redis server.
+          '';
+        };
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    services.redis.servers.lanraragi = {
+      enable = true;
+      port = cfg.redis.port;
+      requirePassFile = cfg.redis.passwordFile;
+    };
+
+    systemd.services.lanraragi = {
+      description = "LANraragi main service";
+      after = [ "network.target" "redis-lanraragi.service" ];
+      requires = [ "redis-lanraragi.service" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = lib.getExe cfg.package;
+        DynamicUser = true;
+        StateDirectory = "lanraragi";
+        RuntimeDirectory = "lanraragi";
+        LogsDirectory = "lanraragi";
+        Restart = "on-failure";
+        WorkingDirectory = "/var/lib/lanraragi";
+      };
+      environment = {
+        "LRR_TEMP_DIRECTORY" = "/run/lanraragi";
+        "LRR_LOG_DIRECTORY" = "/var/log/lanraragi";
+        "LRR_NETWORK" = "http://*:${toString cfg.port}";
+        "HOME" = "/var/lib/lanraragi";
+      };
+      preStart = ''
+        REDIS_PASS=${lib.optionalString (cfg.redis.passwordFile != null) "$(head -n1 ${cfg.redis.passwordFile})"}
+        cat > lrr.conf <<EOF
+        {
+          redis_address => "127.0.0.1:${toString cfg.redis.port}",
+          redis_password => "$REDIS_PASS",
+          redis_database => "0",
+          redis_database_minion => "1",
+          redis_database_config => "2",
+          redis_database_search => "3",
+        }
+        EOF
+      '' + lib.optionalString (cfg.passwordFile != null) ''
+        PASS_HASH=$(
+          PASS=$(head -n1 ${cfg.passwordFile}) ${cfg.package.perlEnv}/bin/perl -I${cfg.package}/share/lanraragi/lib -e \
+            'use LANraragi::Controller::Config; print LANraragi::Controller::Config::make_password_hash($ENV{PASS})' \
+            2>/dev/null
+        )
+
+        ${lib.getExe pkgs.redis} -h 127.0.0.1 -p ${toString cfg.redis.port} -a "$REDIS_PASS" <<EOF
+          SELECT 2
+          HSET LRR_CONFIG password $PASS_HASH
+        EOF
+      '';
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix
index c82f02ecefec..9db4c8e23025 100644
--- a/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix
@@ -35,7 +35,10 @@ with lib;
           };
           port = mkOption {
             type = types.nullOr port;
-            description = lib.mdDoc "Port number.";
+            description = lib.mdDoc ''
+              Port number to listen on.
+              If unset and the listen address is not a socket then nginx defaults to 80.
+            '';
             default = null;
           };
           ssl = mkOption {
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
index 285d0a181931..fc3287045710 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -379,7 +379,7 @@ in
       # Update the start menu for each user that is currently logged in
       system.userActivationScripts.plasmaSetup = activationScript;
 
-      programs.firefox.wrapperConfig.enablePlasmaBrowserIntegration = true;
+      programs.firefox.nativeMessagingHosts.packages = [ pkgs.plasma5Packages.plasma-browser-integration ];
     })
 
     (mkIf (cfg.kwinrc != {}) {
diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
index 64c8ab74bba6..6f0a62d0ea89 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
+++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
@@ -49,7 +49,7 @@ let
     '';
   };
 
-  checkedSystemdBootBuilder = pkgs.runCommandLocal "systemd-boot" {
+  checkedSystemdBootBuilder = pkgs.runCommand "systemd-boot" {
     nativeBuildInputs = [ pkgs.mypy ];
   } ''
     install -m755 ${systemdBootBuilder} $out
diff --git a/nixpkgs/nixos/modules/system/boot/systemd/tmpfiles.nix b/nixpkgs/nixos/modules/system/boot/systemd/tmpfiles.nix
index 3065392b1d20..f7ef45aab3c9 100644
--- a/nixpkgs/nixos/modules/system/boot/systemd/tmpfiles.nix
+++ b/nixpkgs/nixos/modules/system/boot/systemd/tmpfiles.nix
@@ -20,6 +20,102 @@ in
       '';
     };
 
+    systemd.tmpfiles.settings = mkOption {
+      description = lib.mdDoc ''
+        Declare systemd-tmpfiles rules to create, delete, and clean up volatile
+        and temporary files and directories.
+
+        Even though the service is called `*tmp*files` you can also create
+        persistent files.
+      '';
+      example = {
+        "10-mypackage" = {
+          "/var/lib/my-service/statefolder".d = {
+            mode = "0755";
+            user = "root";
+            group = "root";
+          };
+        };
+      };
+      default = {};
+      type = types.attrsOf (types.attrsOf (types.attrsOf (types.submodule ({ name, config, ... }: {
+        options.type = mkOption {
+          type = types.str;
+          default = name;
+          example = "d";
+          description = lib.mdDoc ''
+            The type of operation to perform on the file.
+
+            The type consists of a single letter and optionally one or more
+            modifier characters.
+
+            Please see the upstream documentation for the available types and
+            more details:
+            <https://www.freedesktop.org/software/systemd/man/tmpfiles.d>
+          '';
+        };
+        options.mode = mkOption {
+          type = types.str;
+          default = "-";
+          example = "0755";
+          description = lib.mdDoc ''
+            The file access mode to use when creating this file or directory.
+          '';
+        };
+        options.user = mkOption {
+          type = types.str;
+          default = "-";
+          example = "root";
+          description = lib.mdDoc ''
+            The user of the file.
+
+            This may either be a numeric ID or a user/group name.
+
+            If omitted or when set to `"-"`, the user and group of the user who
+            invokes systemd-tmpfiles is used.
+          '';
+        };
+        options.group = mkOption {
+          type = types.str;
+          default = "-";
+          example = "root";
+          description = lib.mdDoc ''
+            The group of the file.
+
+            This may either be a numeric ID or a user/group name.
+
+            If omitted or when set to `"-"`, the user and group of the user who
+            invokes systemd-tmpfiles is used.
+          '';
+        };
+        options.age = mkOption {
+          type = types.str;
+          default = "-";
+          example = "10d";
+          description = lib.mdDoc ''
+            Delete a file when it reaches a certain age.
+
+            If a file or directory is older than the current time minus the age
+            field, it is deleted.
+
+            If set to `"-"` no automatic clean-up is done.
+          '';
+        };
+        options.argument = mkOption {
+          type = types.str;
+          default = "";
+          example = "";
+          description = lib.mdDoc ''
+            An argument whose meaning depends on the type of operation.
+
+            Please see the upstream documentation for the meaning of this
+            parameter in different situations:
+            <https://www.freedesktop.org/software/systemd/man/tmpfiles.d>
+          '';
+        };
+      }))));
+    };
+
     systemd.tmpfiles.packages = mkOption {
       type = types.listOf types.package;
       default = [];
@@ -102,7 +198,13 @@ in
           ${concatStringsSep "\n" cfg.rules}
         '';
       })
-    ];
+    ] ++ (mapAttrsToList (name: paths:
+      pkgs.writeTextDir "lib/tmpfiles.d/${name}.conf" (concatStrings (mapAttrsToList (path: types:
+        concatStrings (mapAttrsToList (_type: entry: ''
+          '${entry.type}' '${path}' '${entry.mode}' '${entry.user}' '${entry.group}' '${entry.age}' ${entry.argument}
+        '') types)
+      ) paths ))
+    ) cfg.settings);
 
     systemd.tmpfiles.rules = [
       "d  /nix/var                           0755 root root - -"
diff --git a/nixpkgs/nixos/modules/virtualisation/lxc-container.nix b/nixpkgs/nixos/modules/virtualisation/lxc-container.nix
index 1034c699629d..61d7c4cb73fe 100644
--- a/nixpkgs/nixos/modules/virtualisation/lxc-container.nix
+++ b/nixpkgs/nixos/modules/virtualisation/lxc-container.nix
@@ -37,7 +37,6 @@ in {
         ${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
       '';
 
-    # TODO: build rootfs as squashfs for faster unpack
     system.build.tarball = pkgs.callPackage ../../lib/make-system-tarball.nix {
       extraArgs = "--owner=0";
 
@@ -64,6 +63,23 @@ in {
       extraCommands = "mkdir -p proc sys dev";
     };
 
+    system.build.squashfs = pkgs.callPackage ../../lib/make-squashfs.nix {
+      fileName = "nixos-lxc-image-${pkgs.stdenv.hostPlatform.system}";
+
+      noStrip = true; # keep directory structure
+      comp = "zstd -Xcompression-level 6";
+
+      storeContents = [config.system.build.toplevel];
+
+      pseudoFiles = [
+        "/sbin d 0755 0 0"
+        "/sbin/init s 0555 0 0 ${config.system.build.toplevel}/init"
+        "/dev d 0755 0 0"
+        "/proc d 0555 0 0"
+        "/sys d 0555 0 0"
+      ];
+    };
+
     system.build.installBootLoader = pkgs.writeScript "install-lxd-sbin-init.sh" ''
       #!${pkgs.runtimeShell}
       ${pkgs.coreutils}/bin/ln -fs "$1/init" /sbin/init
diff --git a/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix b/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
index 737a935711ae..e625c6322d9c 100644
--- a/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
@@ -198,6 +198,39 @@ let
         fi
       ''}
 
+      ${lib.optionalString cfg.tpm.enable ''
+        NIX_SWTPM_DIR=$(readlink -f "''${NIX_SWTPM_DIR:-${config.system.name}-swtpm}")
+        mkdir -p "$NIX_SWTPM_DIR"
+        ${lib.getExe cfg.tpm.package} \
+          socket \
+          --tpmstate dir="$NIX_SWTPM_DIR" \
+          --ctrl type=unixio,path="$NIX_SWTPM_DIR"/socket,terminate \
+          --pid file="$NIX_SWTPM_DIR"/pid --daemon \
+          --tpm2 \
+          --log file="$NIX_SWTPM_DIR"/stdout,level=6
+
+        # Enable `fdflags` builtin in Bash
+        # We will need it to perform surgical modification of the file descriptor
+        # passed in the coprocess to remove `FD_CLOEXEC`, i.e. close the file descriptor
+        # on exec.
+        # If let alone, it will trigger the coprocess to read EOF when QEMU is `exec`
+        # at the end of this script. To work around that, we will just clear
+        # the `FD_CLOEXEC` bits as a first step.
+        enable -f ${hostPkgs.bash}/lib/bash/fdflags fdflags
+        # leave a dangling subprocess because the swtpm ctrl socket has
+        # "terminate" when the last connection disconnects, it stops swtpm.
+        # When qemu stops, or if the main shell process ends, the coproc will
+        # get signaled by virtue of the pipe between main and coproc ending.
+        # Which in turns triggers a socat connect-disconnect to swtpm which
+        # will stop it.
+        coproc waitingswtpm {
+          read || :
+          echo "" | ${lib.getExe hostPkgs.socat} STDIO UNIX-CONNECT:"$NIX_SWTPM_DIR"/socket
+        }
+        # Clear `FD_CLOEXEC` on the coprocess' file descriptor stdin.
+        fdflags -s-cloexec ''${waitingswtpm[1]}
+      ''}
+
       cd "$TMPDIR"
 
       ${lib.optionalString (cfg.emptyDiskImages != []) "idx=0"}
@@ -657,8 +690,8 @@ in
       package =
         mkOption {
           type = types.package;
-          default = hostPkgs.qemu_kvm;
-          defaultText = literalExpression "config.virtualisation.host.pkgs.qemu_kvm";
+          default = if hostPkgs.stdenv.hostPlatform.qemuArch == pkgs.stdenv.hostPlatform.qemuArch then hostPkgs.qemu_kvm else hostPkgs.qemu;
+          defaultText = literalExpression "if hostPkgs.stdenv.hostPlatform.qemuArch == pkgs.stdenv.hostPlatform.qemuArch then config.virtualisation.host.pkgs.qemu_kvm else config.virtualisation.host.pkgs.qemu";
           example = literalExpression "pkgs.qemu_test";
           description = lib.mdDoc "QEMU package to use.";
         };
@@ -863,6 +896,32 @@ in
       };
     };
 
+    virtualisation.tpm = {
+      enable = mkEnableOption "a TPM device in the virtual machine with a driver, using swtpm.";
+
+      package = mkPackageOptionMD cfg.host.pkgs "swtpm" { };
+
+      deviceModel = mkOption {
+        type = types.str;
+        default = ({
+          "i686-linux" = "tpm-tis";
+          "x86_64-linux" = "tpm-tis";
+          "ppc64-linux" = "tpm-spapr";
+          "armv7-linux" = "tpm-tis-device";
+          "aarch64-linux" = "tpm-tis-device";
+        }.${pkgs.hostPlatform.system} or (throw "Unsupported system for TPM2 emulation in QEMU"));
+        defaultText = ''
+          Based on the guest platform Linux system:
+
+          - `tpm-tis` for (i686, x86_64)
+          - `tpm-spapr` for ppc64
+          - `tpm-tis-device` for (armv7, aarch64)
+        '';
+        example = "tpm-tis-device";
+        description = lib.mdDoc "QEMU device model for the TPM, uses the appropriate default based on th guest platform system and the package passed.";
+      };
+    };
+
     virtualisation.useDefaultFilesystems =
       mkOption {
         type = types.bool;
@@ -1028,7 +1087,8 @@ in
 
     boot.initrd.availableKernelModules =
       optional cfg.writableStore "overlay"
-      ++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx";
+      ++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx"
+      ++ optional (cfg.tpm.enable) "tpm_tis";
 
     virtualisation.additionalPaths = [ config.system.build.toplevel ];
 
@@ -1099,6 +1159,11 @@ in
       (mkIf (!cfg.graphics) [
         "-nographic"
       ])
+      (mkIf (cfg.tpm.enable) [
+        "-chardev socket,id=chrtpm,path=\"$NIX_SWTPM_DIR\"/socket"
+        "-tpmdev emulator,id=tpm_dev_0,chardev=chrtpm"
+        "-device ${cfg.tpm.deviceModel},tpmdev=tpm_dev_0"
+      ])
     ];
 
     virtualisation.qemu.drives = mkMerge [
diff --git a/nixpkgs/nixos/release-combined.nix b/nixpkgs/nixos/release-combined.nix
index 20bcb6802881..149a924de4d0 100644
--- a/nixpkgs/nixos/release-combined.nix
+++ b/nixpkgs/nixos/release-combined.nix
@@ -97,6 +97,7 @@ in rec {
         (onSystems ["x86_64-linux"] "nixos.tests.installer.simpleUefiSystemdBoot")
         (onSystems ["x86_64-linux"] "nixos.tests.installer.simple")
         (onSystems ["x86_64-linux"] "nixos.tests.installer.swraid")
+        (onSystems ["x86_64-linux"] "nixos.tests.nixos-rebuild-specialisations")
         (onFullSupported "nixos.tests.ipv6")
         (onFullSupported "nixos.tests.keymap.azerty")
         (onFullSupported "nixos.tests.keymap.colemak")
@@ -163,7 +164,6 @@ in rec {
         (onFullSupported "nixos.tests.switchTest")
         (onFullSupported "nixos.tests.udisks2")
         (onFullSupported "nixos.tests.xfce")
-        (onSystems ["i686-linux"] "nixos.tests.zfs.installer")
         (onFullSupported "nixpkgs.emacs")
         (onFullSupported "nixpkgs.jdk")
         ["nixpkgs.tarball"]
diff --git a/nixpkgs/nixos/release.nix b/nixpkgs/nixos/release.nix
index abaa7ef9a711..60f4cc94399c 100644
--- a/nixpkgs/nixos/release.nix
+++ b/nixpkgs/nixos/release.nix
@@ -328,6 +328,21 @@ in rec {
 
   );
 
+  lxdContainerImageSquashfs = forMatchingSystems [ "x86_64-linux" "aarch64-linux" ] (system:
+
+    with import ./.. { inherit system; };
+
+    hydraJob ((import lib/eval-config.nix {
+      inherit system;
+      modules =
+        [ configuration
+          versionModule
+          ./maintainers/scripts/lxd/lxd-container-image.nix
+        ];
+    }).config.system.build.squashfs)
+
+  );
+
   # Metadata for the lxd image
   lxdContainerMeta = forMatchingSystems [ "x86_64-linux" "aarch64-linux" ] (system:
 
diff --git a/nixpkgs/nixos/tests/all-tests.nix b/nixpkgs/nixos/tests/all-tests.nix
index 1c8ee32428ea..3531930d863a 100644
--- a/nixpkgs/nixos/tests/all-tests.nix
+++ b/nixpkgs/nixos/tests/all-tests.nix
@@ -248,6 +248,7 @@ in {
   ec2-nixops = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-nixops or {};
   ecryptfs = handleTest ./ecryptfs.nix {};
   fscrypt = handleTest ./fscrypt.nix {};
+  fastnetmon-advanced = runTest ./fastnetmon-advanced.nix;
   ejabberd = handleTest ./xmpp/ejabberd.nix {};
   elk = handleTestOn ["x86_64-linux"] ./elk.nix {};
   emacs-daemon = handleTest ./emacs-daemon.nix {};
@@ -431,6 +432,7 @@ in {
   kubo = import ./kubo { inherit recurseIntoAttrs runTest; };
   ladybird = handleTest ./ladybird.nix {};
   languagetool = handleTest ./languagetool.nix {};
+  lanraragi = handleTest ./lanraragi.nix {};
   latestKernel.login = handleTest ./login.nix { latestKernel = true; };
   leaps = handleTest ./leaps.nix {};
   lemmy = handleTest ./lemmy.nix {};
@@ -569,7 +571,8 @@ in {
   nix-serve-ssh = handleTest ./nix-serve-ssh.nix {};
   nixops = handleTest ./nixops/default.nix {};
   nixos-generate-config = handleTest ./nixos-generate-config.nix {};
-  nixos-rebuild-specialisations = handleTest ./nixos-rebuild-specialisations.nix {};
+  nixos-rebuild-install-bootloader = handleTestOn ["x86_64-linux"] ./nixos-rebuild-install-bootloader.nix {};
+  nixos-rebuild-specialisations = handleTestOn ["x86_64-linux"] ./nixos-rebuild-specialisations.nix {};
   nixpkgs = pkgs.callPackage ../modules/misc/nixpkgs/test.nix { inherit evalMinimalConfig; };
   node-red = handleTest ./node-red.nix {};
   nomad = handleTest ./nomad.nix {};
@@ -702,6 +705,7 @@ in {
   rkvm = handleTest ./rkvm {};
   robustirc-bridge = handleTest ./robustirc-bridge.nix {};
   roundcube = handleTest ./roundcube.nix {};
+  rosenpass = handleTest ./rosenpass.nix {};
   rshim = handleTest ./rshim.nix {};
   rspamd = handleTest ./rspamd.nix {};
   rss2email = handleTest ./rss2email.nix {};
diff --git a/nixpkgs/nixos/tests/cockpit.nix b/nixpkgs/nixos/tests/cockpit.nix
index 6f86d1e2c464..e7165b979014 100644
--- a/nixpkgs/nixos/tests/cockpit.nix
+++ b/nixpkgs/nixos/tests/cockpit.nix
@@ -50,7 +50,8 @@ import ./make-test-python.nix (
             options = Options()
             options.add_argument("--headless")
 
-            driver = webdriver.Firefox(options=options)
+            service = webdriver.FirefoxService(executable_path="${lib.getExe pkgs.geckodriver}")  # noqa: E501
+            driver = webdriver.Firefox(options=options, service=service)
 
             driver.implicitly_wait(10)
 
diff --git a/nixpkgs/nixos/tests/fastnetmon-advanced.nix b/nixpkgs/nixos/tests/fastnetmon-advanced.nix
new file mode 100644
index 000000000000..b2d2713a9211
--- /dev/null
+++ b/nixpkgs/nixos/tests/fastnetmon-advanced.nix
@@ -0,0 +1,65 @@
+{ pkgs, lib, ... }:
+
+{
+  name = "fastnetmon-advanced";
+  meta.maintainers = lib.teams.wdz.members;
+
+  nodes = {
+    bird = { ... }: {
+      networking.firewall.allowedTCPPorts = [ 179 ];
+      services.bird2 = {
+        enable = true;
+        config = ''
+          router id 192.168.1.1;
+
+          protocol bgp fnm {
+            local 192.168.1.1 as 64513;
+            neighbor 192.168.1.2 as 64514;
+            multihop;
+            ipv4 {
+              import all;
+              export none;
+            };
+          }
+        '';
+      };
+    };
+    fnm = { ... }: {
+      networking.firewall.allowedTCPPorts = [ 179 ];
+      services.fastnetmon-advanced = {
+        enable = true;
+        settings = {
+          networks_list = [ "172.23.42.0/24" ];
+          gobgp = true;
+          gobgp_flow_spec_announces = true;
+        };
+        bgpPeers = {
+          bird = {
+            local_asn = 64514;
+            remote_asn = 64513;
+            local_address = "192.168.1.2";
+            remote_address = "192.168.1.1";
+
+            description = "Bird";
+            ipv4_unicast = true;
+            multihop = true;
+            active = true;
+          };
+        };
+      };
+    };
+  };
+
+  testScript = { nodes, ... }: ''
+    start_all()
+    fnm.wait_for_unit("fastnetmon.service")
+    bird.wait_for_unit("bird2.service")
+
+    fnm.wait_until_succeeds('journalctl -eu fastnetmon.service | grep "BGP daemon restarted correctly"')
+    fnm.wait_until_succeeds("journalctl -eu gobgp.service | grep BGP_FSM_OPENCONFIRM")
+    bird.wait_until_succeeds("birdc show protocol fnm | grep Estab")
+    fnm.wait_until_succeeds('journalctl -eu fastnetmon.service | grep "API server listening"')
+    fnm.succeed("fcli set blackhole 172.23.42.123")
+    bird.succeed("birdc show route | grep 172.23.42.123")
+  '';
+}
diff --git a/nixpkgs/nixos/tests/firefox.nix b/nixpkgs/nixos/tests/firefox.nix
index 3f9cea6662fb..fbea95dc7523 100644
--- a/nixpkgs/nixos/tests/firefox.nix
+++ b/nixpkgs/nixos/tests/firefox.nix
@@ -1,14 +1,7 @@
 import ./make-test-python.nix ({ pkgs, firefoxPackage, ... }:
-let firefoxPackage' = firefoxPackage.override (args: {
-      extraPrefsFiles = (args.extraPrefsFiles or []) ++ [
-        # make sure that autoplay is enabled by default for the audio test
-        (builtins.toString (builtins.toFile "autoplay-pref.js" ''defaultPref("media.autoplay.default",0);''))
-      ];
-  });
-
-in
 {
-  name = firefoxPackage'.unwrapped.pname;
+  name = firefoxPackage.pname;
+
   meta = with pkgs.lib.maintainers; {
     maintainers = [ eelco shlevy ];
   };
@@ -17,10 +10,13 @@ in
     { pkgs, ... }:
 
     { imports = [ ./common/x11.nix ];
-      environment.systemPackages = [
-        firefoxPackage'
-        pkgs.xdotool
-      ];
+      environment.systemPackages = [ pkgs.xdotool ];
+
+      programs.firefox = {
+        enable = true;
+        preferences."media.autoplay.default" = 0;
+        package = firefoxPackage;
+      };
 
       # Create a virtual sound device, with mixing
       # and all, for recording audio.
@@ -58,7 +54,9 @@ in
 
     };
 
-  testScript = ''
+  testScript = let
+    exe = firefoxPackage.unwrapped.binaryName;
+  in ''
       from contextlib import contextmanager
 
 
@@ -97,7 +95,7 @@ in
 
       with subtest("Wait until Firefox has finished loading the Valgrind docs page"):
           machine.execute(
-              "xterm -e '${firefoxPackage'.unwrapped.binaryName} file://${pkgs.valgrind.doc}/share/doc/valgrind/html/index.html' >&2 &"
+              "xterm -e '${exe} file://${pkgs.valgrind.doc}/share/doc/valgrind/html/index.html' >&2 &"
           )
           machine.wait_for_window("Valgrind")
           machine.sleep(40)
@@ -105,7 +103,7 @@ in
       with subtest("Check whether Firefox can play sound"):
           with record_audio(machine):
               machine.succeed(
-                  "${firefoxPackage'.unwrapped.binaryName} file://${pkgs.sound-theme-freedesktop}/share/sounds/freedesktop/stereo/phone-incoming-call.oga >&2 &"
+                  "${exe} file://${pkgs.sound-theme-freedesktop}/share/sounds/freedesktop/stereo/phone-incoming-call.oga >&2 &"
               )
               wait_for_sound(machine)
           machine.copy_from_vm("/tmp/record.wav")
diff --git a/nixpkgs/nixos/tests/forgejo.nix b/nixpkgs/nixos/tests/forgejo.nix
index b326819e3190..6acd6acb50fa 100644
--- a/nixpkgs/nixos/tests/forgejo.nix
+++ b/nixpkgs/nixos/tests/forgejo.nix
@@ -37,7 +37,7 @@ let
           settings."repository.signing".SIGNING_KEY = signingPrivateKeyId;
           settings.actions.ENABLED = true;
         };
-        environment.systemPackages = [ config.services.forgejo.package pkgs.gnupg pkgs.jq ];
+        environment.systemPackages = [ config.services.forgejo.package pkgs.gnupg pkgs.jq pkgs.file ];
         services.openssh.enable = true;
 
         specialisation.runner = {
@@ -53,6 +53,14 @@ let
             tokenFile = "/var/lib/forgejo/runner_token";
           };
         };
+        specialisation.dump = {
+          inheritParentConfig = true;
+          configuration.services.forgejo.dump = {
+            enable = true;
+            type = "tar.zst";
+            file = "dump.tar.zst";
+          };
+        };
       };
       client1 = { config, pkgs, ... }: {
         environment.systemPackages = [ pkgs.git ];
@@ -66,8 +74,10 @@ let
       let
         inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
         serverSystem = nodes.server.system.build.toplevel;
+        dumpFile = with nodes.server.specialisation.dump.configuration.services.forgejo.dump; "${backupDir}/${file}";
       in
       ''
+        import json
         GIT_SSH_COMMAND = "ssh -i $HOME/.ssh/privk -o StrictHostKeyChecking=no"
         REPO = "forgejo@server:test/repo"
         PRIVK = "${snakeOilPrivateKey}"
@@ -137,6 +147,11 @@ let
         client2.succeed(f"GIT_SSH_COMMAND='{GIT_SSH_COMMAND}' git clone {REPO}")
         client2.succeed('test "$(cat repo/testfile | xargs echo -n)" = "hello world"')
 
+        with subtest("Testing git protocol version=2 over ssh"):
+            git_protocol = client2.succeed(f"GIT_SSH_COMMAND='{GIT_SSH_COMMAND}' GIT_TRACE2_EVENT=true git -C repo fetch |& grep negotiated-version")
+            version = json.loads(git_protocol).get("value")
+            assert version == "2", f"git did not negotiate protocol version 2, but version {version} instead."
+
         server.wait_until_succeeds(
             'test "$(curl http://localhost:3000/api/v1/repos/test/repo/commits '
             + '-H "Accept: application/json" | jq length)" = "1"',
@@ -150,6 +165,12 @@ let
             server.succeed("${serverSystem}/specialisation/runner/bin/switch-to-configuration test")
             server.wait_for_unit("gitea-runner-test.service")
             server.succeed("journalctl -o cat -u gitea-runner-test.service | grep -q 'Runner registered successfully'")
+
+        with subtest("Testing backup service"):
+            server.succeed("${serverSystem}/specialisation/dump/bin/switch-to-configuration test")
+            server.systemctl("start forgejo-dump")
+            assert "Zstandard compressed data" in server.succeed("file ${dumpFile}")
+            server.copy_from_vm("${dumpFile}")
       '';
   });
 in
diff --git a/nixpkgs/nixos/tests/installer.nix b/nixpkgs/nixos/tests/installer.nix
index 5111cedf9256..9ff1d8f5d039 100644
--- a/nixpkgs/nixos/tests/installer.nix
+++ b/nixpkgs/nixos/tests/installer.nix
@@ -69,8 +69,8 @@ let
   # disk, and then reboot from the hard disk.  It's parameterized with
   # a test script fragment `createPartitions', which must create
   # partitions and filesystems.
-  testScriptFun = { bootLoader, createPartitions, grubDevice, grubUseEfi
-                  , grubIdentifier, preBootCommands, postBootCommands, extraConfig
+  testScriptFun = { bootLoader, createPartitions, grubDevice, grubUseEfi, grubIdentifier
+                  , postInstallCommands, preBootCommands, postBootCommands, extraConfig
                   , testSpecialisationConfig, testFlakeSwitch
                   }:
     let iface = "virtio";
@@ -153,6 +153,8 @@ let
               """
           )
 
+      ${postInstallCommands}
+
       with subtest("Shutdown system after installation"):
           machine.succeed("umount -R /mnt")
           machine.succeed("sync")
@@ -368,7 +370,9 @@ let
 
 
   makeInstallerTest = name:
-    { createPartitions, preBootCommands ? "", postBootCommands ? "", extraConfig ? ""
+    { createPartitions
+    , postInstallCommands ? "", preBootCommands ? "", postBootCommands ? ""
+    , extraConfig ? ""
     , extraInstallerConfig ? {}
     , bootLoader ? "grub" # either "grub" or "systemd-boot"
     , grubDevice ? "/dev/vda", grubIdentifier ? "uuid", grubUseEfi ? false
@@ -479,7 +483,7 @@ let
       };
 
       testScript = testScriptFun {
-        inherit bootLoader createPartitions preBootCommands postBootCommands
+        inherit bootLoader createPartitions postInstallCommands preBootCommands postBootCommands
                 grubDevice grubIdentifier grubUseEfi extraConfig
                 testSpecialisationConfig testFlakeSwitch;
       };
@@ -682,20 +686,32 @@ in {
     createPartitions = ''
       machine.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
-          + " mkpart primary linux-swap 1M 1024M"
-          + " mkpart primary 1024M -1s",
+          + " mkpart primary 1M 100MB"  # bpool
+          + " mkpart primary linux-swap 100M 1024M"
+          + " mkpart primary 1024M -1s", # rpool
           "udevadm settle",
-          "mkswap /dev/vda1 -L swap",
+          "mkswap /dev/vda2 -L swap",
           "swapon -L swap",
-          "zpool create rpool /dev/vda2",
+          "zpool create rpool /dev/vda3",
           "zfs create -o mountpoint=legacy rpool/root",
           "mount -t zfs rpool/root /mnt",
           "zfs create -o mountpoint=legacy rpool/root/usr",
           "mkdir /mnt/usr",
           "mount -t zfs rpool/root/usr /mnt/usr",
+          "zpool create -o compatibility=grub2 bpool /dev/vda1",
+          "zfs create -o mountpoint=legacy bpool/boot",
+          "mkdir /mnt/boot",
+          "mount -t zfs bpool/boot /mnt/boot",
           "udevadm settle",
       )
     '';
+
+    # umount & export bpool before shutdown
+    # this is a fix for "cannot import 'bpool': pool was previously in use from another system."
+    postInstallCommands = ''
+      machine.succeed("umount /mnt/boot")
+      machine.succeed("zpool export bpool")
+    '';
   };
 
   # Create two physical LVM partitions combined into one volume group
diff --git a/nixpkgs/nixos/tests/lanraragi.nix b/nixpkgs/nixos/tests/lanraragi.nix
new file mode 100644
index 000000000000..f513ac9d252b
--- /dev/null
+++ b/nixpkgs/nixos/tests/lanraragi.nix
@@ -0,0 +1,40 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "lanraragi";
+  meta.maintainers = with lib.maintainers; [ tomasajt ];
+
+  nodes = {
+    machine1 = { pkgs, ... }: {
+      services.lanraragi.enable = true;
+    };
+    machine2 = { pkgs, ... }: {
+      services.lanraragi = {
+        enable = true;
+        passwordFile = pkgs.writeText "lrr-test-pass" ''
+          ultra-secure-password
+        '';
+        port = 4000;
+        redis = {
+          port = 4001;
+          passwordFile = pkgs.writeText "redis-lrr-test-pass" ''
+            still-a-very-secure-password
+          '';
+        };
+      };
+    };
+
+
+  };
+
+  testScript = ''
+    start_all()
+
+    machine1.wait_for_unit("lanraragi.service")
+    machine1.wait_until_succeeds("curl -f localhost:3000")
+    machine1.succeed("[ $(curl -o /dev/null -X post 'http://localhost:3000/login' --data-raw 'password=kamimamita' -w '%{http_code}') -eq 302 ]")
+
+    machine2.wait_for_unit("lanraragi.service")
+    machine2.wait_until_succeeds("curl -f localhost:4000")
+    machine2.succeed("[ $(curl -o /dev/null -X post 'http://localhost:4000/login' --data-raw 'password=ultra-secure-password' -w '%{http_code}') -eq 302 ]")
+  '';
+})
+
diff --git a/nixpkgs/nixos/tests/lxd/container.nix b/nixpkgs/nixos/tests/lxd/container.nix
index bdaaebfc0028..0ebe73d872f2 100644
--- a/nixpkgs/nixos/tests/lxd/container.nix
+++ b/nixpkgs/nixos/tests/lxd/container.nix
@@ -13,6 +13,7 @@ let
 
   lxd-image-metadata = releases.lxdContainerMeta.${pkgs.stdenv.hostPlatform.system};
   lxd-image-rootfs = releases.lxdContainerImage.${pkgs.stdenv.hostPlatform.system};
+  lxd-image-rootfs-squashfs = releases.lxdContainerImageSquashfs.${pkgs.stdenv.hostPlatform.system};
 
 in {
   name = "lxd-container";
@@ -23,7 +24,7 @@ in {
 
   nodes.machine = { lib, ... }: {
     virtualisation = {
-      diskSize = 4096;
+      diskSize = 6144;
 
       # Since we're testing `limits.cpu`, we've gotta have a known number of
       # cores to lean on
@@ -65,6 +66,16 @@ in {
         machine.succeed("echo true | lxc exec container /run/current-system/sw/bin/bash -")
         machine.succeed("lxc delete -f container")
 
+    with subtest("Squashfs image is functional"):
+        machine.succeed(
+            "lxc image import ${lxd-image-metadata}/*/*.tar.xz ${lxd-image-rootfs-squashfs} --alias nixos-squashfs"
+        )
+        machine.succeed("lxc launch nixos-squashfs container")
+        with machine.nested("Waiting for instance to start and be usable"):
+          retry(instance_is_up)
+        machine.succeed("echo true | lxc exec container /run/current-system/sw/bin/bash -")
+        machine.succeed("lxc delete -f container")
+
     with subtest("Container is mounted with lxcfs inside"):
         machine.succeed("lxc launch nixos container")
         with machine.nested("Waiting for instance to start and be usable"):
diff --git a/nixpkgs/nixos/tests/misc.nix b/nixpkgs/nixos/tests/misc.nix
index 442b45948c60..e7842debba7a 100644
--- a/nixpkgs/nixos/tests/misc.nix
+++ b/nixpkgs/nixos/tests/misc.nix
@@ -13,6 +13,7 @@ in {
       environment.variables.EDITOR = lib.mkOverride 0 "emacs";
       documentation.nixos.enable = lib.mkOverride 0 true;
       systemd.tmpfiles.rules = [ "d /tmp 1777 root root 10d" ];
+      systemd.tmpfiles.settings."10-test"."/tmp/somefile".d = {};
       virtualisation.fileSystems = { "/tmp2" =
         { fsType = "tmpfs";
           options = [ "mode=1777" "noauto" ];
@@ -117,6 +118,9 @@ in {
           )
           machine.fail("[ -e /tmp/foo ]")
 
+      with subtest("whether systemd-tmpfiles settings works"):
+          machine.succeed("[ -e /tmp/somefile ]")
+
       with subtest("whether automounting works"):
           machine.fail("grep '/tmp2 tmpfs' /proc/mounts")
           machine.succeed("touch /tmp2/x")
diff --git a/nixpkgs/nixos/tests/nixos-rebuild-install-bootloader.nix b/nixpkgs/nixos/tests/nixos-rebuild-install-bootloader.nix
new file mode 100644
index 000000000000..3ade90ea24a7
--- /dev/null
+++ b/nixpkgs/nixos/tests/nixos-rebuild-install-bootloader.nix
@@ -0,0 +1,73 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "nixos-rebuild-install-bootloader";
+
+  nodes = {
+    machine = { lib, pkgs, ... }: {
+      imports = [
+        ../modules/profiles/installation-device.nix
+        ../modules/profiles/base.nix
+      ];
+
+      nix.settings = {
+        substituters = lib.mkForce [ ];
+        hashed-mirrors = null;
+        connect-timeout = 1;
+      };
+
+      system.includeBuildDependencies = true;
+
+      virtualisation = {
+        cores = 2;
+        memorySize = 2048;
+      };
+
+      virtualisation.useBootLoader = true;
+    };
+  };
+
+  testScript =
+    let
+      configFile = pkgs.writeText "configuration.nix" ''
+        { lib, pkgs, ... }: {
+          imports = [
+            ./hardware-configuration.nix
+            <nixpkgs/nixos/modules/testing/test-instrumentation.nix>
+          ];
+
+          boot.loader.grub = {
+            enable = true;
+            device = "/dev/vda";
+            forceInstall = true;
+          };
+
+          documentation.enable = false;
+        }
+      '';
+
+    in
+    ''
+      machine.start()
+      machine.succeed("udevadm settle")
+      machine.wait_for_unit("multi-user.target")
+
+      machine.succeed("nixos-generate-config")
+      machine.copy_from_host(
+          "${configFile}",
+          "/etc/nixos/configuration.nix",
+      )
+      machine.succeed("nixos-rebuild switch")
+
+      # Need to run `nixos-rebuild` twice because the first run will install
+      # GRUB anyway
+      with subtest("Switch system again and install bootloader"):
+          result = machine.succeed("nixos-rebuild switch --install-bootloader")
+          # install-grub2.pl messages
+          assert "updating GRUB 2 menu..." in result
+          assert "installing the GRUB 2 boot loader on /dev/vda..." in result
+          # GRUB message
+          assert "Installation finished. No error reported." in result
+          # at this point we've tested regression #262724, but haven't tested the bootloader itself
+          # TODO: figure out how to how to tell the test driver to start the bootloader instead of
+          # booting into the kernel directly.
+    '';
+})
diff --git a/nixpkgs/nixos/tests/openssh.nix b/nixpkgs/nixos/tests/openssh.nix
index e88625678fec..88d3e54ee76c 100644
--- a/nixpkgs/nixos/tests/openssh.nix
+++ b/nixpkgs/nixos/tests/openssh.nix
@@ -22,7 +22,7 @@ in {
         ];
       };
 
-    server_lazy =
+    server-lazy =
       { ... }:
 
       {
@@ -34,7 +34,7 @@ in {
         ];
       };
 
-    server_localhost_only =
+    server-localhost-only =
       { ... }:
 
       {
@@ -43,7 +43,7 @@ in {
         };
       };
 
-    server_localhost_only_lazy =
+    server-localhost-only-lazy =
       { ... }:
 
       {
@@ -52,7 +52,7 @@ in {
         };
       };
 
-    server_match_rule =
+    server-match-rule =
       { ... }:
 
       {
@@ -119,11 +119,11 @@ in {
         )
 
         client.succeed(
-            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server_lazy 'echo hello world' >&2",
+            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server-lazy 'echo hello world' >&2",
             timeout=30
         )
         client.succeed(
-            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server_lazy 'ulimit -l' | grep 1024",
+            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server-lazy 'ulimit -l' | grep 1024",
             timeout=30
         )
 
@@ -137,7 +137,7 @@ in {
             timeout=30
         )
         client.succeed(
-            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server_lazy true",
+            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server-lazy true",
             timeout=30
         )
 
diff --git a/nixpkgs/nixos/tests/prometheus-exporters.nix b/nixpkgs/nixos/tests/prometheus-exporters.nix
index 8369d6a497ac..7fd824967206 100644
--- a/nixpkgs/nixos/tests/prometheus-exporters.nix
+++ b/nixpkgs/nixos/tests/prometheus-exporters.nix
@@ -416,8 +416,8 @@ let
     };
 
     kea = let
-      controlSocketPathV4 = "/run/kea/dhcp4.sock";
-      controlSocketPathV6 = "/run/kea/dhcp6.sock";
+      controlSocketPathV4 = "/run/kea-dhcp4/dhcp4.sock";
+      controlSocketPathV6 = "/run/kea-dhcp6/dhcp6.sock";
     in
     {
       exporterConfig = {
@@ -512,7 +512,7 @@ let
         wait_for_unit("knot.service")
         wait_for_unit("prometheus-knot-exporter.service")
         wait_for_open_port(9433)
-        succeed("curl -sSf 'localhost:9433' | grep 'knot_server_zone_count 1.0'")
+        succeed("curl -sSf 'localhost:9433' | grep '2\.019031301'")
       '';
     };
 
diff --git a/nixpkgs/nixos/tests/rosenpass.nix b/nixpkgs/nixos/tests/rosenpass.nix
new file mode 100644
index 000000000000..ec4046c8c035
--- /dev/null
+++ b/nixpkgs/nixos/tests/rosenpass.nix
@@ -0,0 +1,217 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+let
+  deviceName = "rp0";
+
+  server = {
+    ip = "fe80::1";
+    wg = {
+      public = "mQufmDFeQQuU/fIaB2hHgluhjjm1ypK4hJr1cW3WqAw=";
+      secret = "4N5Y1dldqrpsbaEiY8O0XBUGUFf8vkvtBtm8AoOX7Eo=";
+      listen = 10000;
+    };
+  };
+  client = {
+    ip = "fe80::2";
+    wg = {
+      public = "Mb3GOlT7oS+F3JntVKiaD7SpHxLxNdtEmWz/9FMnRFU=";
+      secret = "uC5dfGMv7Oxf5UDfdPkj6rZiRZT2dRWp5x8IQxrNcUE=";
+    };
+  };
+in
+{
+  name = "rosenpass";
+
+  nodes =
+    let
+      shared = peer: { config, modulesPath, ... }: {
+        imports = [ "${modulesPath}/services/networking/rosenpass.nix" ];
+
+        boot.kernelModules = [ "wireguard" ];
+
+        services.rosenpass = {
+          enable = true;
+          defaultDevice = deviceName;
+          settings = {
+            verbosity = "Verbose";
+            public_key = "/etc/rosenpass/pqpk";
+            secret_key = "/etc/rosenpass/pqsk";
+          };
+        };
+
+        networking.firewall.allowedUDPPorts = [ 9999 ];
+
+        systemd.network = {
+          enable = true;
+          networks."rosenpass" = {
+            matchConfig.Name = deviceName;
+            networkConfig.IPForward = true;
+            address = [ "${peer.ip}/64" ];
+          };
+
+          netdevs."10-rp0" = {
+            netdevConfig = {
+              Kind = "wireguard";
+              Name = deviceName;
+            };
+            wireguardConfig.PrivateKeyFile = "/etc/wireguard/wgsk";
+          };
+        };
+
+        environment.etc."wireguard/wgsk" = {
+          text = peer.wg.secret;
+          user = "systemd-network";
+          group = "systemd-network";
+        };
+      };
+    in
+    {
+      server = {
+        imports = [ (shared server) ];
+
+        networking.firewall.allowedUDPPorts = [ server.wg.listen ];
+
+        systemd.network.netdevs."10-${deviceName}" = {
+          wireguardConfig.ListenPort = server.wg.listen;
+          wireguardPeers = [
+            {
+              wireguardPeerConfig = {
+                AllowedIPs = [ "::/0" ];
+                PublicKey = client.wg.public;
+              };
+            }
+          ];
+        };
+
+        services.rosenpass.settings = {
+          listen = [ "0.0.0.0:9999" ];
+          peers = [
+            {
+              public_key = "/etc/rosenpass/peers/client/pqpk";
+              peer = client.wg.public;
+            }
+          ];
+        };
+      };
+      client = {
+        imports = [ (shared client) ];
+
+        systemd.network.netdevs."10-${deviceName}".wireguardPeers = [
+          {
+            wireguardPeerConfig = {
+              AllowedIPs = [ "::/0" ];
+              PublicKey = server.wg.public;
+              Endpoint = "server:${builtins.toString server.wg.listen}";
+            };
+          }
+        ];
+
+        services.rosenpass.settings.peers = [
+          {
+            public_key = "/etc/rosenpass/peers/server/pqpk";
+            endpoint = "server:9999";
+            peer = server.wg.public;
+          }
+        ];
+      };
+    };
+
+  testScript = { ... }: ''
+    from os import system
+
+    # Full path to rosenpass in the store, to avoid fiddling with `$PATH`.
+    rosenpass = "${pkgs.rosenpass}/bin/rosenpass"
+
+    # Path in `/etc` where keys will be placed.
+    etc = "/etc/rosenpass"
+
+    start_all()
+
+    for machine in [server, client]:
+        machine.wait_for_unit("multi-user.target")
+
+    # Gently stop Rosenpass to avoid crashes during key generation/distribution.
+    for machine in [server, client]:
+        machine.execute("systemctl stop rosenpass.service")
+
+    for (name, machine, remote) in [("server", server, client), ("client", client, server)]:
+        pk, sk = f"{name}.pqpk", f"{name}.pqsk"
+        system(f"{rosenpass} gen-keys --force --secret-key {sk} --public-key {pk}")
+        machine.copy_from_host(sk, f"{etc}/pqsk")
+        machine.copy_from_host(pk, f"{etc}/pqpk")
+        remote.copy_from_host(pk, f"{etc}/peers/{name}/pqpk")
+
+    for machine in [server, client]:
+        machine.execute("systemctl start rosenpass.service")
+
+    for machine in [server, client]:
+        machine.wait_for_unit("rosenpass.service")
+
+    with subtest("ping"):
+        client.succeed("ping -c 2 -i 0.5 ${server.ip}%${deviceName}")
+
+    with subtest("preshared-keys"):
+        # Rosenpass works by setting the WireGuard preshared key at regular intervals.
+        # Thus, if it is not active, then no key will be set, and the output of `wg show` will contain "none".
+        # Otherwise, if it is active, then the key will be set and "none" will not be found in the output of `wg show`.
+        for machine in [server, client]:
+            machine.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5)
+  '';
+
+  # NOTE: Below configuration is for "interactive" (=developing/debugging) only.
+  interactive.nodes =
+    let
+      inherit (import ./ssh-keys.nix pkgs) snakeOilPublicKey snakeOilPrivateKey;
+
+      sshAndKeyGeneration = {
+        services.openssh.enable = true;
+        users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
+        environment.systemPackages = [
+          (pkgs.writeShellApplication {
+            name = "gen-keys";
+            runtimeInputs = [ pkgs.rosenpass ];
+            text = ''
+              HOST="$(hostname)"
+              if [ "$HOST" == "server" ]
+              then
+                PEER="client"
+              else
+                PEER="server"
+              fi
+
+              # Generate keypair.
+              mkdir -vp /etc/rosenpass/peers/$PEER
+              rosenpass gen-keys --force --secret-key /etc/rosenpass/pqsk --public-key /etc/rosenpass/pqpk
+
+              # Set up SSH key.
+              mkdir -p /root/.ssh
+              cp ${snakeOilPrivateKey} /root/.ssh/id_ecdsa
+              chmod 0400 /root/.ssh/id_ecdsa
+
+              # Copy public key to other peer.
+              # shellcheck disable=SC2029
+              ssh -o StrictHostKeyChecking=no $PEER "mkdir -pv /etc/rosenpass/peers/$HOST"
+              scp /etc/rosenpass/pqpk "$PEER:/etc/rosenpass/peers/$HOST/pqpk"
+            '';
+          })
+        ];
+      };
+
+      # Use kmscon <https://www.freedesktop.org/wiki/Software/kmscon/>
+      # to provide a slightly nicer console, and while we're at it,
+      # also use a nice font.
+      # With kmscon, we can for example zoom in/out using [Ctrl] + [+]
+      # and [Ctrl] + [-]
+      niceConsoleAndAutologin.services.kmscon = {
+        enable = true;
+        autologinUser = "root";
+        fonts = [{
+          name = "Fira Code";
+          package = pkgs.fira-code;
+        }];
+      };
+    in
+    {
+      server = sshAndKeyGeneration // niceConsoleAndAutologin;
+      client = sshAndKeyGeneration // niceConsoleAndAutologin;
+    };
+})
diff --git a/nixpkgs/nixos/tests/stratis/encryption.nix b/nixpkgs/nixos/tests/stratis/encryption.nix
index a555ff8a8e85..81b5f92b4ac4 100644
--- a/nixpkgs/nixos/tests/stratis/encryption.nix
+++ b/nixpkgs/nixos/tests/stratis/encryption.nix
@@ -26,7 +26,7 @@ import ../make-test-python.nix ({ pkgs, ... }:
         # test rebinding encrypted pool
         machine.succeed("stratis pool rebind keyring  testpool testkey2")
         # test restarting encrypted pool
-        machine.succeed("stratis pool stop   testpool")
-        machine.succeed("stratis pool start  --name testpool --unlock-method keyring")
+        machine.succeed("stratis pool stop  --name testpool")
+        machine.succeed("stratis pool start --name testpool --unlock-method keyring")
       '';
   })
diff --git a/nixpkgs/nixos/tests/systemd-credentials-tpm2.nix b/nixpkgs/nixos/tests/systemd-credentials-tpm2.nix
index d2dc1fd7b615..bf7418312236 100644
--- a/nixpkgs/nixos/tests/systemd-credentials-tpm2.nix
+++ b/nixpkgs/nixos/tests/systemd-credentials-tpm2.nix
@@ -1,13 +1,4 @@
-import ./make-test-python.nix ({ lib, pkgs, system, ... }:
-
-let
-  tpmSocketPath = "/tmp/swtpm-sock";
-  tpmDeviceModels = {
-    x86_64-linux = "tpm-tis";
-    aarch64-linux = "tpm-tis-device";
-  };
-in
-
+import ./make-test-python.nix ({ lib, pkgs, ... }:
 {
   name = "systemd-credentials-tpm2";
 
@@ -16,51 +7,11 @@ in
   };
 
   nodes.machine = { pkgs, ... }: {
-    virtualisation = {
-      qemu.options = [
-        "-chardev socket,id=chrtpm,path=${tpmSocketPath}"
-        "-tpmdev emulator,id=tpm_dev_0,chardev=chrtpm"
-        "-device ${tpmDeviceModels.${system}},tpmdev=tpm_dev_0"
-      ];
-    };
-
-    boot.initrd.availableKernelModules = [ "tpm_tis" ];
-
+    virtualisation.tpm.enable = true;
     environment.systemPackages = with pkgs; [ diffutils ];
   };
 
   testScript = ''
-    import subprocess
-    from tempfile import TemporaryDirectory
-
-    # From systemd-initrd-luks-tpm2.nix
-    class Tpm:
-        def __init__(self):
-            self.state_dir = TemporaryDirectory()
-            self.start()
-
-        def start(self):
-            self.proc = subprocess.Popen(["${pkgs.swtpm}/bin/swtpm",
-                "socket",
-                "--tpmstate", f"dir={self.state_dir.name}",
-                "--ctrl", "type=unixio,path=${tpmSocketPath}",
-                "--tpm2",
-                ])
-
-            # Check whether starting swtpm failed
-            try:
-                exit_code = self.proc.wait(timeout=0.2)
-                if exit_code is not None and exit_code != 0:
-                    raise Exception("failed to start swtpm")
-            except subprocess.TimeoutExpired:
-                pass
-
-        """Check whether the swtpm process exited due to an error"""
-        def check(self):
-            exit_code = self.proc.poll()
-            if exit_code is not None and exit_code != 0:
-                raise Exception("swtpm process died")
-
     CRED_NAME = "testkey"
     CRED_RAW_FILE = f"/root/{CRED_NAME}"
     CRED_FILE = f"/root/{CRED_NAME}.cred"
@@ -85,12 +36,6 @@ in
 
         machine.log("systemd-run finished successfully")
 
-    tpm = Tpm()
-
-    @polling_condition
-    def swtpm_running():
-        tpm.check()
-
     machine.wait_for_unit("multi-user.target")
 
     with subtest("Check whether TPM device exists"):
diff --git a/nixpkgs/nixos/tests/systemd-cryptenroll.nix b/nixpkgs/nixos/tests/systemd-cryptenroll.nix
index 055ae7d1681f..034aae1d5e95 100644
--- a/nixpkgs/nixos/tests/systemd-cryptenroll.nix
+++ b/nixpkgs/nixos/tests/systemd-cryptenroll.nix
@@ -8,47 +8,34 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     environment.systemPackages = [ pkgs.cryptsetup ];
     virtualisation = {
       emptyDiskImages = [ 512 ];
-      qemu.options = [
-        "-chardev socket,id=chrtpm,path=/tmp/swtpm-sock"
-        "-tpmdev emulator,id=tpm0,chardev=chrtpm"
-        "-device tpm-tis,tpmdev=tpm0"
-      ];
+      tpm.enable = true;
     };
   };
 
   testScript = ''
-    import subprocess
-    import tempfile
-
-    def start_swtpm(tpmstate):
-        subprocess.Popen(["${pkgs.swtpm}/bin/swtpm", "socket", "--tpmstate", "dir="+tpmstate, "--ctrl", "type=unixio,path=/tmp/swtpm-sock", "--log", "level=0", "--tpm2"])
-
-    with tempfile.TemporaryDirectory() as tpmstate:
-        start_swtpm(tpmstate)
-        machine.start()
-
-        # Verify the TPM device is available and accessible by systemd-cryptenroll
-        machine.succeed("test -e /dev/tpm0")
-        machine.succeed("test -e /dev/tpmrm0")
-        machine.succeed("systemd-cryptenroll --tpm2-device=list")
-
-        # Create LUKS partition
-        machine.succeed("echo -n lukspass | cryptsetup luksFormat -q /dev/vdb -")
-        # Enroll new LUKS key and bind it to Secure Boot state
-        # For more details on PASSWORD variable, check the following issue:
-        # https://github.com/systemd/systemd/issues/20955
-        machine.succeed("PASSWORD=lukspass systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 /dev/vdb")
-        # Add LUKS partition to /etc/crypttab to test auto unlock
-        machine.succeed("echo 'luks /dev/vdb - tpm2-device=auto' >> /etc/crypttab")
-        machine.shutdown()
-
-        start_swtpm(tpmstate)
-        machine.start()
-
-        # Test LUKS partition automatic unlock on boot
-        machine.wait_for_unit("systemd-cryptsetup@luks.service")
-        # Wipe TPM2 slot
-        machine.succeed("systemd-cryptenroll --wipe-slot=tpm2 /dev/vdb")
+    machine.start()
+
+    # Verify the TPM device is available and accessible by systemd-cryptenroll
+    machine.succeed("test -e /dev/tpm0")
+    machine.succeed("test -e /dev/tpmrm0")
+    machine.succeed("systemd-cryptenroll --tpm2-device=list")
+
+    # Create LUKS partition
+    machine.succeed("echo -n lukspass | cryptsetup luksFormat -q /dev/vdb -")
+    # Enroll new LUKS key and bind it to Secure Boot state
+    # For more details on PASSWORD variable, check the following issue:
+    # https://github.com/systemd/systemd/issues/20955
+    machine.succeed("PASSWORD=lukspass systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 /dev/vdb")
+    # Add LUKS partition to /etc/crypttab to test auto unlock
+    machine.succeed("echo 'luks /dev/vdb - tpm2-device=auto' >> /etc/crypttab")
+
+    machine.shutdown()
+    machine.start()
+
+    # Test LUKS partition automatic unlock on boot
+    machine.wait_for_unit("systemd-cryptsetup@luks.service")
+    # Wipe TPM2 slot
+    machine.succeed("systemd-cryptenroll --wipe-slot=tpm2 /dev/vdb")
   '';
 })
 
diff --git a/nixpkgs/nixos/tests/systemd-initrd-luks-tpm2.nix b/nixpkgs/nixos/tests/systemd-initrd-luks-tpm2.nix
index d9dd9118a3a2..e292acfd1c5f 100644
--- a/nixpkgs/nixos/tests/systemd-initrd-luks-tpm2.nix
+++ b/nixpkgs/nixos/tests/systemd-initrd-luks-tpm2.nix
@@ -9,7 +9,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
       # Booting off the TPM2-encrypted device requires an available init script
       mountHostNixStore = true;
       useEFIBoot = true;
-      qemu.options = ["-chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0"];
+      tpm.enable = true;
     };
     boot.loader.systemd-boot.enable = true;
 
@@ -33,29 +33,6 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
   };
 
   testScript = ''
-    import subprocess
-    import os
-    import time
-
-
-    class Tpm:
-        def __init__(self):
-            os.mkdir("/tmp/mytpm1")
-            self.start()
-
-        def start(self):
-            self.proc = subprocess.Popen(["${pkgs.swtpm}/bin/swtpm", "socket", "--tpmstate", "dir=/tmp/mytpm1", "--ctrl", "type=unixio,path=/tmp/mytpm1/swtpm-sock", "--log", "level=20", "--tpm2"])
-
-        def wait_for_death_then_restart(self):
-            while self.proc.poll() is None:
-                print("waiting for tpm to die")
-                time.sleep(1)
-            assert self.proc.returncode == 0
-            self.start()
-
-    tpm = Tpm()
-
-
     # Create encrypted volume
     machine.wait_for_unit("multi-user.target")
     machine.succeed("echo -n supersecret | cryptsetup luksFormat -q --iter-time=1 /dev/vdb -")
@@ -66,8 +43,6 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
     machine.succeed("sync")
     machine.crash()
 
-    tpm.wait_for_death_then_restart()
-
     # Boot and decrypt the disk
     machine.wait_for_unit("multi-user.target")
     assert "/dev/mapper/cryptroot on / type ext4" in machine.succeed("mount")