about summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/config/shells-environment.nix6
-rw-r--r--nixos/modules/config/stevenblack.nix49
-rw-r--r--nixos/modules/config/system-path.nix2
-rw-r--r--nixos/modules/config/update-users-groups.pl2
-rw-r--r--nixos/modules/hardware/decklink.nix16
-rw-r--r--nixos/modules/hardware/video/nvidia.nix9
-rw-r--r--nixos/modules/image/repart-image.nix2
-rw-r--r--nixos/modules/installer/tools/nix-fallback-paths.nix10
-rw-r--r--nixos/modules/misc/locate.nix5
-rw-r--r--nixos/modules/module-list.nix8
-rw-r--r--nixos/modules/profiles/qemu-guest.nix10
-rw-r--r--nixos/modules/programs/envision.nix51
-rw-r--r--nixos/modules/programs/file-roller.nix2
-rw-r--r--nixos/modules/programs/geary.nix2
-rw-r--r--nixos/modules/programs/gnome-disks.nix4
-rw-r--r--nixos/modules/programs/gnome-terminal.nix6
-rw-r--r--nixos/modules/programs/gpaste.nix10
-rw-r--r--nixos/modules/programs/nano.nix1
-rw-r--r--nixos/modules/programs/nautilus-open-any-terminal.nix2
-rw-r--r--nixos/modules/programs/qdmr.nix2
-rw-r--r--nixos/modules/programs/qgroundcontrol.nix53
-rw-r--r--nixos/modules/programs/seahorse.nix6
-rw-r--r--nixos/modules/programs/singularity.nix25
-rw-r--r--nixos/modules/programs/tsm-client.nix2
-rw-r--r--nixos/modules/programs/vim.nix38
-rw-r--r--nixos/modules/security/pam.nix201
-rw-r--r--nixos/modules/services/backup/borgbackup.nix3
-rw-r--r--nixos/modules/services/backup/duplicity.nix24
-rw-r--r--nixos/modules/services/backup/tsm.nix2
-rw-r--r--nixos/modules/services/cluster/patroni/default.nix36
-rw-r--r--nixos/modules/services/cluster/rke2/default.nix2
-rw-r--r--nixos/modules/services/continuous-integration/gitlab-runner.nix15
-rw-r--r--nixos/modules/services/continuous-integration/woodpecker/agents.nix2
-rw-r--r--nixos/modules/services/continuous-integration/woodpecker/server.nix2
-rw-r--r--nixos/modules/services/databases/monetdb.nix2
-rw-r--r--nixos/modules/services/desktop-managers/lomiri.nix19
-rw-r--r--nixos/modules/services/desktops/espanso.nix1
-rw-r--r--nixos/modules/services/desktops/gnome/gnome-keyring.nix23
-rw-r--r--nixos/modules/services/desktops/gnome/gnome-user-share.nix4
-rw-r--r--nixos/modules/services/desktops/gnome/rygel.nix8
-rw-r--r--nixos/modules/services/desktops/gnome/sushi.nix4
-rw-r--r--nixos/modules/services/desktops/playerctld.nix32
-rw-r--r--nixos/modules/services/games/terraria.nix23
-rw-r--r--nixos/modules/services/mail/roundcube.nix12
-rw-r--r--nixos/modules/services/mail/stalwart-mail.nix21
-rw-r--r--nixos/modules/services/misc/dictd.nix3
-rw-r--r--nixos/modules/services/misc/gitlab.nix7
-rw-r--r--nixos/modules/services/misc/jellyseerr.nix7
-rw-r--r--nixos/modules/services/misc/languagetool.nix43
-rw-r--r--nixos/modules/services/misc/ollama.nix3
-rw-r--r--nixos/modules/services/misc/renovate.nix1
-rw-r--r--nixos/modules/services/misc/rkvm.nix2
-rw-r--r--nixos/modules/services/misc/snapper.nix26
-rw-r--r--nixos/modules/services/misc/sonarr.nix8
-rw-r--r--nixos/modules/services/misc/zoneminder.nix14
-rw-r--r--nixos/modules/services/monitoring/grafana.nix2
-rw-r--r--nixos/modules/services/monitoring/nezha-agent.nix15
-rw-r--r--nixos/modules/services/monitoring/opentelemetry-collector.nix47
-rw-r--r--nixos/modules/services/monitoring/prometheus/alertmanager-webhook-logger.nix11
-rw-r--r--nixos/modules/services/monitoring/prometheus/alertmanager.nix52
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters.nix16
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/deluge.nix85
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/fastly.nix41
-rw-r--r--nixos/modules/services/monitoring/prometheus/pushgateway.nix44
-rw-r--r--nixos/modules/services/monitoring/smartd.nix27
-rw-r--r--nixos/modules/services/network-filesystems/samba.nix6
-rw-r--r--nixos/modules/services/networking/bee.nix3
-rw-r--r--nixos/modules/services/networking/blocky.nix4
-rw-r--r--nixos/modules/services/networking/cgit.nix82
-rw-r--r--nixos/modules/services/networking/cloudflare-dyndns.nix13
-rw-r--r--nixos/modules/services/networking/cloudflare-warp.nix91
-rw-r--r--nixos/modules/services/networking/cloudflared.nix10
-rw-r--r--nixos/modules/services/networking/deconz.nix1
-rw-r--r--nixos/modules/services/networking/firefox-syncserver.nix2
-rw-r--r--nixos/modules/services/networking/magic-wormhole-mailbox-server.nix24
-rw-r--r--nixos/modules/services/networking/mihomo.nix12
-rw-r--r--nixos/modules/services/networking/mosquitto.nix2
-rw-r--r--nixos/modules/services/networking/nebula.nix8
-rw-r--r--nixos/modules/services/networking/networkd-dispatcher.nix4
-rw-r--r--nixos/modules/services/networking/networkmanager.nix2
-rw-r--r--nixos/modules/services/networking/oink.nix1
-rw-r--r--nixos/modules/services/networking/prosody.nix70
-rw-r--r--nixos/modules/services/networking/realm.nix50
-rw-r--r--nixos/modules/services/networking/resilio.nix2
-rw-r--r--nixos/modules/services/networking/scion/scion-control.nix10
-rw-r--r--nixos/modules/services/networking/scion/scion-daemon.nix8
-rw-r--r--nixos/modules/services/networking/scion/scion-dispatcher.nix3
-rw-r--r--nixos/modules/services/networking/scion/scion-router.nix3
-rw-r--r--nixos/modules/services/networking/scion/scion.nix16
-rw-r--r--nixos/modules/services/networking/smokeping.nix8
-rw-r--r--nixos/modules/services/networking/syncthing.nix9
-rw-r--r--nixos/modules/services/security/clamav.nix10
-rw-r--r--nixos/modules/services/security/sks.nix2
-rw-r--r--nixos/modules/services/security/yubikey-agent.nix2
-rw-r--r--nixos/modules/services/system/cloud-init.nix11
-rw-r--r--nixos/modules/services/torrent/rtorrent.nix2
-rw-r--r--nixos/modules/services/ttys/kmscon.nix14
-rw-r--r--nixos/modules/services/web-apps/eintopf.nix92
-rw-r--r--nixos/modules/services/web-apps/freshrss.nix46
-rw-r--r--nixos/modules/services/web-apps/glance.md39
-rw-r--r--nixos/modules/services/web-apps/glance.nix141
-rw-r--r--nixos/modules/services/web-apps/jitsi-meet.nix14
-rw-r--r--nixos/modules/services/web-apps/keycloak.nix6
-rw-r--r--nixos/modules/services/web-apps/mediawiki.nix194
-rw-r--r--nixos/modules/services/web-apps/nextcloud.md23
-rw-r--r--nixos/modules/services/web-apps/nextcloud.nix6
-rw-r--r--nixos/modules/services/web-apps/onlyoffice.nix58
-rw-r--r--nixos/modules/services/web-apps/pixelfed.nix2
-rw-r--r--nixos/modules/services/web-apps/shiori.nix80
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix20
-rw-r--r--nixos/modules/services/web-servers/fcgiwrap.nix130
-rw-r--r--nixos/modules/services/x11/desktop-managers/budgie.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/cinnamon.nix14
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome.md2
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome.nix44
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.nix10
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix4
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix14
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix4
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix12
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/slick.nix12
-rw-r--r--nixos/modules/services/x11/window-managers/herbstluftwm.nix5
-rw-r--r--nixos/modules/system/boot/initrd-ssh.nix10
-rw-r--r--nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py93
-rw-r--r--nixos/modules/system/boot/networkd.nix11
-rw-r--r--nixos/modules/system/boot/systemd/journald.nix2
-rw-r--r--nixos/modules/virtualisation/ec2-data.nix3
-rw-r--r--nixos/modules/virtualisation/virtualbox-host.nix14
128 files changed, 2046 insertions, 763 deletions
diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix
index 2c19fb8a029d3..50796f8bc6f1e 100644
--- a/nixos/modules/config/shells-environment.nix
+++ b/nixos/modules/config/shells-environment.nix
@@ -42,8 +42,10 @@ in
         strings.  The latter is concatenated, interspersed with colon
         characters.
       '';
-      type = with types; attrsOf (oneOf [ (listOf (oneOf [ float int str ])) float int str path ]);
-      apply = mapAttrs (n: v: if isList v then concatMapStringsSep ":" toString v else toString v);
+      type = with types; attrsOf (oneOf [ (listOf (oneOf [ int str path ])) int str path ]);
+      apply = let
+        toStr = v: if isPath v then "${v}" else toString v;
+      in mapAttrs (n: v: if isList v then concatMapStringsSep ":" toStr v else toStr v);
     };
 
     environment.profiles = mkOption {
diff --git a/nixos/modules/config/stevenblack.nix b/nixos/modules/config/stevenblack.nix
index 5b85073c6908d..95f6c9e73eb3e 100644
--- a/nixos/modules/config/stevenblack.nix
+++ b/nixos/modules/config/stevenblack.nix
@@ -1,34 +1,49 @@
-{ config, lib, pkgs, ... }:
-
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
 let
-  inherit (lib) optionals mkOption mkEnableOption types mkIf elem concatStringsSep maintainers;
-  cfg = config.networking.stevenblack;
+  inherit (lib)
+    getOutput
+    maintainers
+    mkEnableOption
+    mkIf
+    mkOption
+    mkPackageOption
+    types
+    ;
 
-  # needs to be in a specific order
-  activatedHosts = with cfg; [ ]
-    ++ optionals (elem "fakenews" block) [ "fakenews" ]
-    ++ optionals (elem "gambling" block) [ "gambling" ]
-    ++ optionals (elem "porn" block) [ "porn" ]
-    ++ optionals (elem "social" block) [ "social" ];
-
-  hostsPath = "${pkgs.stevenblack-blocklist}/alternates/" + concatStringsSep "-" activatedHosts + "/hosts";
+  cfg = config.networking.stevenblack;
 in
 {
   options.networking.stevenblack = {
     enable = mkEnableOption "the stevenblack hosts file blocklist";
 
+    package = mkPackageOption pkgs "stevenblack-blocklist" { };
+
     block = mkOption {
-      type = types.listOf (types.enum [ "fakenews" "gambling" "porn" "social" ]);
+      type = types.listOf (
+        types.enum [
+          "fakenews"
+          "gambling"
+          "porn"
+          "social"
+        ]
+      );
       default = [ ];
       description = "Additional blocklist extensions.";
     };
   };
 
   config = mkIf cfg.enable {
-    networking.hostFiles = [ ]
-      ++ optionals (activatedHosts != [ ]) [ hostsPath ]
-      ++ optionals (activatedHosts == [ ]) [ "${pkgs.stevenblack-blocklist}/hosts" ];
+    networking.hostFiles = map (x: "${getOutput x cfg.package}/hosts") ([ "ads" ] ++ cfg.block);
   };
 
-  meta.maintainers = [ maintainers.moni maintainers.artturin ];
+  meta.maintainers = with maintainers; [
+    moni
+    artturin
+    frontear
+  ];
 }
diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix
index 562100ad6201c..21280d023a4ce 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -153,10 +153,8 @@ in
         "/sbin"
         "/share/emacs"
         "/share/hunspell"
-        "/share/nano"
         "/share/org"
         "/share/themes"
-        "/share/vim-plugins"
         "/share/vulkan"
         "/share/kservices5"
         "/share/kservicetypes5"
diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl
index 7c6851473f42f..f0b692a759d1a 100644
--- a/nixos/modules/config/update-users-groups.pl
+++ b/nixos/modules/config/update-users-groups.pl
@@ -234,7 +234,7 @@ foreach my $u (@{$spec->{users}}) {
 
     # Ensure home directory incl. ownership and permissions.
     if ($u->{createHome} and !$is_dry) {
-        make_path($u->{home}, { mode => oct($u->{homeMode}) }) if ! -e $u->{home};
+        make_path($u->{home}, { mode => 0755 }) if ! -e $u->{home};
         chown $u->{uid}, $u->{gid}, $u->{home};
         chmod oct($u->{homeMode}), $u->{home};
     }
diff --git a/nixos/modules/hardware/decklink.nix b/nixos/modules/hardware/decklink.nix
deleted file mode 100644
index d179e1d7634ff..0000000000000
--- a/nixos/modules/hardware/decklink.nix
+++ /dev/null
@@ -1,16 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-let
-  cfg = config.hardware.decklink;
-  kernelPackages = config.boot.kernelPackages;
-in
-{
-  options.hardware.decklink.enable = lib.mkEnableOption "hardware support for the Blackmagic Design Decklink audio/video interfaces";
-
-  config = lib.mkIf cfg.enable {
-    boot.kernelModules = [ "blackmagic" "blackmagic-io" "snd_blackmagic-io" ];
-    boot.extraModulePackages = [ kernelPackages.decklink ];
-    systemd.packages = [ pkgs.blackmagic-desktop-video ];
-    systemd.services.DesktopVideoHelper.wantedBy = [ "multi-user.target" ];
-  };
-}
diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix
index e38050e637b1c..94d6acbdefea0 100644
--- a/nixos/modules/hardware/video/nvidia.nix
+++ b/nixos/modules/hardware/video/nvidia.nix
@@ -96,7 +96,11 @@ in
         Enabling this fixes screen tearing when using Optimus via PRIME (see
         {option}`hardware.nvidia.prime.sync.enable`. This is not enabled
         by default because it is not officially supported by NVIDIA and would not
-        work with SLI
+        work with SLI.
+
+        Enabling this and using version 545 or newer of the proprietary NVIDIA
+        driver causes it to provide its own framebuffer device, which can cause
+        Wayland compositors to work when they otherwise wouldn't.
       '';
 
       prime.nvidiaBusId = lib.mkOption {
@@ -568,9 +572,10 @@ in
               "nvidia_drm"
             ];
 
-            # If requested enable modesetting via kernel parameter.
+            # If requested enable modesetting via kernel parameters.
             kernelParams =
               lib.optional (offloadCfg.enable || cfg.modesetting.enable) "nvidia-drm.modeset=1"
+              ++ lib.optional ((offloadCfg.enable || cfg.modesetting.enable) && lib.versionAtLeast nvidia_x11.version "545") "nvidia-drm.fbdev=1"
               ++ lib.optional cfg.powerManagement.enable "nvidia.NVreg_PreserveVideoMemoryAllocations=1"
               ++ lib.optional cfg.open "nvidia.NVreg_OpenRmEnableUnsupportedGpus=1"
               ++ lib.optional (config.boot.kernelPackages.kernel.kernelAtLeast "6.2" && !ibtSupport) "ibt=off";
diff --git a/nixos/modules/image/repart-image.nix b/nixos/modules/image/repart-image.nix
index de03beeafc0b7..41f68a0282ac9 100644
--- a/nixos/modules/image/repart-image.nix
+++ b/nixos/modules/image/repart-image.nix
@@ -69,7 +69,7 @@ let
     patchShebangs --build $out
 
     black --check --diff $out
-    ruff --line-length 88 $out
+    ruff check --line-length 88 $out
     mypy --strict $out
   '';
 
diff --git a/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixos/modules/installer/tools/nix-fallback-paths.nix
index 54d3a107d6276..f9ea7eb395973 100644
--- a/nixos/modules/installer/tools/nix-fallback-paths.nix
+++ b/nixos/modules/installer/tools/nix-fallback-paths.nix
@@ -1,7 +1,7 @@
 {
-  x86_64-linux = "/nix/store/1w4b47zhp33md29wjhgg549pc281vv02-nix-2.18.4";
-  i686-linux = "/nix/store/hz02kn0ffn3wdi2xs7lndpr88v4v4fp2-nix-2.18.4";
-  aarch64-linux = "/nix/store/90zwqa9z2fgldc7ki1p5gfvglchjh9r6-nix-2.18.4";
-  x86_64-darwin = "/nix/store/bd1ix5mj9lj2yh7bqnmdjc24zlg5jivk-nix-2.18.4";
-  aarch64-darwin = "/nix/store/5hvsmklhqiay5i4q5vdkg60p8qpc69rz-nix-2.18.4";
+  x86_64-linux = "/nix/store/f409bhlpp0xkzvdz95qr2yvfjfi8r9jc-nix-2.18.5";
+  i686-linux = "/nix/store/ra39jzrxq3bcpf55aahwv5037akvylf5-nix-2.18.5";
+  aarch64-linux = "/nix/store/xiw8a4jbnw18svgdb04hyqzg5bsjspqf-nix-2.18.5";
+  x86_64-darwin = "/nix/store/k2gzx7i90x3h2c8g6xdi1jkwbl6ic895-nix-2.18.5";
+  aarch64-darwin = "/nix/store/rqwymbndaqxma6p8s5brcl9k32n5xx54-nix-2.18.5";
 }
diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix
index 0e9adefff5e1e..4692ed15a9567 100644
--- a/nixos/modules/misc/locate.nix
+++ b/nixos/modules/misc/locate.nix
@@ -297,7 +297,10 @@ in
       description = "Update timer for locate database";
       partOf = [ "update-locatedb.service" ];
       wantedBy = [ "timers.target" ];
-      timerConfig.OnCalendar = cfg.interval;
+      timerConfig = {
+        OnCalendar = cfg.interval;
+        Persistent = true;
+      };
     };
   };
 
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 3cfdd943b35b0..eb2f049985c91 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -59,7 +59,6 @@
   ./hardware/cpu/intel-microcode.nix
   ./hardware/cpu/intel-sgx.nix
   ./hardware/cpu/x86-msr.nix
-  ./hardware/decklink.nix
   ./hardware/device-tree.nix
   ./hardware/digitalbitbox.nix
   ./hardware/flipperzero.nix
@@ -181,6 +180,7 @@
   ./programs/dublin-traceroute.nix
   ./programs/ecryptfs.nix
   ./programs/environment.nix
+  ./programs/envision.nix
   ./programs/evince.nix
   ./programs/extra-container.nix
   ./programs/fcast-receiver.nix
@@ -258,6 +258,7 @@
   ./programs/projecteur.nix
   ./programs/proxychains.nix
   ./programs/qdmr.nix
+  ./programs/qgroundcontrol.nix
   ./programs/qt5ct.nix
   ./programs/quark-goldleaf.nix
   ./programs/regreet.nix
@@ -487,6 +488,7 @@
   ./services/desktops/espanso.nix
   ./services/desktops/flatpak.nix
   ./services/desktops/geoclue2.nix
+  ./services/desktops/playerctld.nix
   ./services/desktops/gnome/at-spi2-core.nix
   ./services/desktops/gnome/evolution-data-server.nix
   ./services/desktops/gnome/glib-networking.nix
@@ -971,6 +973,7 @@
   ./services/networking/clatd.nix
   ./services/networking/cloudflare-dyndns.nix
   ./services/networking/cloudflared.nix
+  ./services/networking/cloudflare-warp.nix
   ./services/networking/cntlm.nix
   ./services/networking/connman.nix
   ./services/networking/consul.nix
@@ -1148,6 +1151,7 @@
   ./services/networking/radicale.nix
   ./services/networking/radvd.nix
   ./services/networking/rdnssd.nix
+  ./services/networking/realm.nix
   ./services/networking/redsocks.nix
   ./services/networking/resilio.nix
   ./services/networking/robustirc-bridge.nix
@@ -1369,6 +1373,7 @@
   ./services/web-apps/documize.nix
   ./services/web-apps/dokuwiki.nix
   ./services/web-apps/dolibarr.nix
+  ./services/web-apps/eintopf.nix
   ./services/web-apps/engelsystem.nix
   ./services/web-apps/ethercalc.nix
   ./services/web-apps/filesender.nix
@@ -1378,6 +1383,7 @@
   ./services/web-apps/freshrss.nix
   ./services/web-apps/galene.nix
   ./services/web-apps/gerrit.nix
+  ./services/web-apps/glance.nix
   ./services/web-apps/gotify-server.nix
   ./services/web-apps/gotosocial.nix
   ./services/web-apps/grocy.nix
diff --git a/nixos/modules/profiles/qemu-guest.nix b/nixos/modules/profiles/qemu-guest.nix
index 8b3df97ae0db9..a7015c8bcc61d 100644
--- a/nixos/modules/profiles/qemu-guest.nix
+++ b/nixos/modules/profiles/qemu-guest.nix
@@ -5,13 +5,5 @@
 
 {
   boot.initrd.availableKernelModules = [ "virtio_net" "virtio_pci" "virtio_mmio" "virtio_blk" "virtio_scsi" "9p" "9pnet_virtio" ];
-  boot.initrd.kernelModules = [ "virtio_balloon" "virtio_console" "virtio_rng" ];
-
-  boot.initrd.postDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable)
-    ''
-      # Set the system time from the hardware clock to work around a
-      # bug in qemu-kvm > 1.5.2 (where the VM clock is initialised
-      # to the *boot time* of the host).
-      hwclock -s
-    '';
+  boot.initrd.kernelModules = [ "virtio_balloon" "virtio_console" "virtio_rng" "virtio_gpu" ];
 }
diff --git a/nixos/modules/programs/envision.nix b/nixos/modules/programs/envision.nix
new file mode 100644
index 0000000000000..56acd83d7daf8
--- /dev/null
+++ b/nixos/modules/programs/envision.nix
@@ -0,0 +1,51 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+
+let
+  cfg = config.programs.envision;
+in
+{
+
+  options = {
+    programs.envision = {
+      enable = lib.mkEnableOption "envision";
+
+      package = lib.mkPackageOption pkgs "envision" {};
+
+      openFirewall = lib.mkEnableOption "the default ports in the firewall for the WiVRn server" // {
+        default = true;
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    services.avahi = {
+      enable = true;
+      publish = {
+        enable = true;
+        userServices = true;
+      };
+    };
+
+    services.udev = {
+      enable = true;
+      packages = with pkgs; [
+        android-udev-rules
+        xr-hardware
+      ];
+    };
+
+    environment.systemPackages = [ cfg.package ];
+
+    networking.firewall = lib.mkIf cfg.openFirewall {
+      allowedTCPPorts = [ 9757 ];
+      allowedUDPPorts = [ 9757 ];
+    };
+  };
+
+  meta.maintainers = pkgs.envision.meta.maintainers;
+}
diff --git a/nixos/modules/programs/file-roller.nix b/nixos/modules/programs/file-roller.nix
index f64bd732855bf..d58af9cd59a58 100644
--- a/nixos/modules/programs/file-roller.nix
+++ b/nixos/modules/programs/file-roller.nix
@@ -14,7 +14,7 @@ in {
 
       enable = lib.mkEnableOption "File Roller, an archive manager for GNOME";
 
-      package = lib.mkPackageOption pkgs [ "gnome" "file-roller" ] { };
+      package = lib.mkPackageOption pkgs "file-roller" { };
 
     };
 
diff --git a/nixos/modules/programs/geary.nix b/nixos/modules/programs/geary.nix
index cfd5bed78d971..7c22d88a9ad55 100644
--- a/nixos/modules/programs/geary.nix
+++ b/nixos/modules/programs/geary.nix
@@ -13,7 +13,7 @@ in {
   };
 
   config = lib.mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.gnome.geary ];
+    environment.systemPackages = [ pkgs.geary ];
     programs.dconf.enable = true;
     services.gnome.gnome-keyring.enable = true;
     services.gnome.gnome-online-accounts.enable = true;
diff --git a/nixos/modules/programs/gnome-disks.nix b/nixos/modules/programs/gnome-disks.nix
index 954f1fd9bc078..8c0cee906c564 100644
--- a/nixos/modules/programs/gnome-disks.nix
+++ b/nixos/modules/programs/gnome-disks.nix
@@ -32,9 +32,9 @@
 
   config = lib.mkIf config.programs.gnome-disks.enable {
 
-    environment.systemPackages = [ pkgs.gnome.gnome-disk-utility ];
+    environment.systemPackages = [ pkgs.gnome-disk-utility ];
 
-    services.dbus.packages = [ pkgs.gnome.gnome-disk-utility ];
+    services.dbus.packages = [ pkgs.gnome-disk-utility ];
 
   };
 
diff --git a/nixos/modules/programs/gnome-terminal.nix b/nixos/modules/programs/gnome-terminal.nix
index a5dda83edd11f..a065adfe61c4f 100644
--- a/nixos/modules/programs/gnome-terminal.nix
+++ b/nixos/modules/programs/gnome-terminal.nix
@@ -19,9 +19,9 @@ in
   };
 
   config = lib.mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.gnome.gnome-terminal ];
-    services.dbus.packages = [ pkgs.gnome.gnome-terminal ];
-    systemd.packages = [ pkgs.gnome.gnome-terminal ];
+    environment.systemPackages = [ pkgs.gnome-terminal ];
+    services.dbus.packages = [ pkgs.gnome-terminal ];
+    systemd.packages = [ pkgs.gnome-terminal ];
 
     programs.bash.vteIntegration = true;
     programs.zsh.vteIntegration = true;
diff --git a/nixos/modules/programs/gpaste.nix b/nixos/modules/programs/gpaste.nix
index 32b81434bdd94..f0c3baf10da03 100644
--- a/nixos/modules/programs/gpaste.nix
+++ b/nixos/modules/programs/gpaste.nix
@@ -18,12 +18,12 @@
 
   ###### implementation
   config = lib.mkIf config.programs.gpaste.enable {
-    environment.systemPackages = [ pkgs.gnome.gpaste ];
-    services.dbus.packages = [ pkgs.gnome.gpaste ];
-    systemd.packages = [ pkgs.gnome.gpaste ];
+    environment.systemPackages = [ pkgs.gpaste ];
+    services.dbus.packages = [ pkgs.gpaste ];
+    systemd.packages = [ pkgs.gpaste ];
     # gnome-control-center crashes in Keyboard Shortcuts pane without the GSettings schemas.
-    services.xserver.desktopManager.gnome.sessionPath = [ pkgs.gnome.gpaste ];
+    services.xserver.desktopManager.gnome.sessionPath = [ pkgs.gpaste ];
     # gpaste-reloaded applet doesn't work without the typelib
-    services.xserver.desktopManager.cinnamon.sessionPath = [ pkgs.gnome.gpaste ];
+    services.xserver.desktopManager.cinnamon.sessionPath = [ pkgs.gpaste ];
   };
 }
diff --git a/nixos/modules/programs/nano.nix b/nixos/modules/programs/nano.nix
index 10fa2a0dfbcdf..1ae350ea66b28 100644
--- a/nixos/modules/programs/nano.nix
+++ b/nixos/modules/programs/nano.nix
@@ -43,6 +43,7 @@ in
         include "${cfg.package}/share/nano/extra/*.nanorc"
       '') + cfg.nanorc;
       systemPackages = [ cfg.package ];
+      pathsToLink = [ "/share/nano" ];
     };
   };
 }
diff --git a/nixos/modules/programs/nautilus-open-any-terminal.nix b/nixos/modules/programs/nautilus-open-any-terminal.nix
index 8a38c4cb5e483..ff0e77607b5e1 100644
--- a/nixos/modules/programs/nautilus-open-any-terminal.nix
+++ b/nixos/modules/programs/nautilus-open-any-terminal.nix
@@ -19,7 +19,7 @@ in
 
   config = lib.mkIf cfg.enable {
     environment.systemPackages = with pkgs; [
-      gnome.nautilus-python
+      nautilus-python
       nautilus-open-any-terminal
     ];
     programs.dconf = lib.optionalAttrs (cfg.terminal != null) {
diff --git a/nixos/modules/programs/qdmr.nix b/nixos/modules/programs/qdmr.nix
index efd0e1fc98859..1444be9c6923a 100644
--- a/nixos/modules/programs/qdmr.nix
+++ b/nixos/modules/programs/qdmr.nix
@@ -8,7 +8,7 @@
 let
   cfg = config.programs.qdmr;
 in {
-  meta.maintainers = [ lib.maintainers.janik ];
+  meta.maintainers = [ ];
 
   options = {
     programs.qdmr = {
diff --git a/nixos/modules/programs/qgroundcontrol.nix b/nixos/modules/programs/qgroundcontrol.nix
new file mode 100644
index 0000000000000..4534d79f25dd8
--- /dev/null
+++ b/nixos/modules/programs/qgroundcontrol.nix
@@ -0,0 +1,53 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+
+let
+  cfg = config.programs.qgroundcontrol;
+in
+{
+
+  options = {
+    programs.qgroundcontrol = {
+      enable = lib.mkEnableOption "qgroundcontrol";
+
+      package = lib.mkPackageOption pkgs "qgroundcontrol" {};
+
+      blacklistModemManagerFromTTYUSB = lib.mkOption {
+        type = lib.types.bool;
+        default = true;
+        description = ''
+          Disallow ModemManager from interfering with serial connections that QGroundControl might use.
+
+          Note that if you use a modem that's connected via USB, you might want to disable this option.
+        '';
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    # ModemManager is known to interfere with serial connections;
+    # QGC recommends disabling it, but we don't want to if we can avoid it
+    # Instead, we blacklist tty devices using udev rules, which is a more targeted approach
+    services.udev = lib.mkIf cfg.blacklistModemManagerFromTTYUSB {
+      enable = true;
+      extraRules = ''
+        # nixos/qgroundcontrol: Blacklist ttyUSB devices from ModemManager
+        SUBSYSTEM=="tty", KERNEL=="ttyUSB*", ENV{ID_MM_DEVICE_IGNORE}="1"
+      '';
+    };
+
+    # Security wrapper
+    security.wrappers.qgroundcontrol = {
+      source = lib.getExe cfg.package;
+      owner = "root"; # Sensible default; not setuid so this is not a security risk
+      group = "tty";
+      setgid = true;
+    };
+  };
+
+  meta.maintainers = pkgs.qgroundcontrol.meta.maintainers;
+}
diff --git a/nixos/modules/programs/seahorse.nix b/nixos/modules/programs/seahorse.nix
index 53fff50e0a8b9..3f6ec8c1a6a6d 100644
--- a/nixos/modules/programs/seahorse.nix
+++ b/nixos/modules/programs/seahorse.nix
@@ -21,14 +21,14 @@
 
   config = lib.mkIf config.programs.seahorse.enable {
 
-    programs.ssh.askPassword = lib.mkDefault "${pkgs.gnome.seahorse}/libexec/seahorse/ssh-askpass";
+    programs.ssh.askPassword = lib.mkDefault "${pkgs.seahorse}/libexec/seahorse/ssh-askpass";
 
     environment.systemPackages = [
-      pkgs.gnome.seahorse
+      pkgs.seahorse
     ];
 
     services.dbus.packages = [
-      pkgs.gnome.seahorse
+      pkgs.seahorse
     ];
 
   };
diff --git a/nixos/modules/programs/singularity.nix b/nixos/modules/programs/singularity.nix
index bc989ad2dbaf5..d1115b361593b 100644
--- a/nixos/modules/programs/singularity.nix
+++ b/nixos/modules/programs/singularity.nix
@@ -56,9 +56,12 @@ in
     enableFakeroot = lib.mkOption {
       type = lib.types.bool;
       default = true;
-      example = false;
       description = ''
         Whether to enable the `--fakeroot` support of Singularity/Apptainer.
+
+        This option is deprecated and has no effect.
+        `--fakeroot` support is enabled automatically,
+        as `systemBinPaths = [ "/run/wrappers/bin" ]` is always specified.
       '';
     };
     enableSuid = lib.mkOption {
@@ -74,22 +77,34 @@ in
         Whether to enable the SUID support of Singularity/Apptainer.
       '';
     };
+    systemBinPaths = lib.mkOption {
+      type = lib.types.listOf lib.types.path;
+      default = [ ];
+      description = ''
+        (Extra) system-wide /**/bin paths
+        for Apptainer/Singularity to find command-line utilities in.
+
+        `"/run/wrappers/bin"` is included by default to make
+        utilities with SUID bit set available to Apptainer/Singularity.
+        Use `lib.mkForce` to shadow the default values.
+      '';
+    };
   };
 
   config = lib.mkIf cfg.enable {
     programs.singularity.packageOverriden = (
       cfg.package.override (
-        lib.optionalAttrs cfg.enableExternalLocalStateDir { externalLocalStateDir = "/var/lib"; }
-        // lib.optionalAttrs cfg.enableFakeroot {
-          newuidmapPath = "/run/wrappers/bin/newuidmap";
-          newgidmapPath = "/run/wrappers/bin/newgidmap";
+        {
+          systemBinPaths = cfg.systemBinPaths;
         }
+        // lib.optionalAttrs cfg.enableExternalLocalStateDir { externalLocalStateDir = "/var/lib"; }
         // lib.optionalAttrs cfg.enableSuid {
           enableSuid = true;
           starterSuidPath = "/run/wrappers/bin/${cfg.package.projectName}-suid";
         }
       )
     );
+    programs.singularity.systemBinPaths = [ "/run/wrappers/bin" ];
     environment.systemPackages = [ cfg.packageOverriden ];
     security.wrappers."${cfg.packageOverriden.projectName}-suid" = lib.mkIf cfg.enableSuid {
       setuid = true;
diff --git a/nixos/modules/programs/tsm-client.nix b/nixos/modules/programs/tsm-client.nix
index 82fbc9b26e2d3..ff517b9bef53a 100644
--- a/nixos/modules/programs/tsm-client.nix
+++ b/nixos/modules/programs/tsm-client.nix
@@ -22,7 +22,7 @@ let
   serverOptions = { name, config, ... }: {
     freeformType = attrsOf (either scalarType (listOf scalarType));
     # Client system-options file directives are explained here:
-    # https://www.ibm.com/docs/en/storage-protect/8.1.22?topic=commands-processing-options
+    # https://www.ibm.com/docs/en/storage-protect/8.1.23?topic=commands-processing-options
     options.servername = mkOption {
       type = servernameType;
       default = name;
diff --git a/nixos/modules/programs/vim.nix b/nixos/modules/programs/vim.nix
index 8232340ddebbf..7fb50e0f4147a 100644
--- a/nixos/modules/programs/vim.nix
+++ b/nixos/modules/programs/vim.nix
@@ -1,25 +1,31 @@
-{ config, lib, pkgs, ... }:
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
 
 let
   cfg = config.programs.vim;
-in {
+in
+{
   options.programs.vim = {
-    defaultEditor = lib.mkOption {
-      type = lib.types.bool;
-      default = false;
-      description = ''
-        When enabled, installs vim and configures vim to be the default editor
-        using the EDITOR environment variable.
-      '';
-    };
+    enable = lib.mkEnableOption "Vi IMproved, an advanced text";
 
-    package = lib.mkPackageOption pkgs "vim" {
-      example = "vim-full";
-    };
+    defaultEditor = lib.mkEnableOption "vim as the default editor";
+
+    package = lib.mkPackageOption pkgs "vim" { example = "vim-full"; };
   };
 
-  config = lib.mkIf cfg.defaultEditor {
-    environment.systemPackages = [ cfg.package ];
-    environment.variables = { EDITOR = lib.mkOverride 900 "vim"; };
+  # TODO: convert it into assert after 24.11 release
+  config = lib.mkIf (cfg.enable || cfg.defaultEditor) {
+    warnings = lib.mkIf (cfg.defaultEditor && !cfg.enable) [
+      "programs.vim.defaultEditor will only work if programs.vim.enable is enabled, will be encfored after the 24.11 release"
+    ];
+    environment = {
+      systemPackages = [ cfg.package ];
+      variables.EDITOR = lib.mkIf cfg.defaultEditor (lib.mkOverride 900 "vim");
+      pathsToLink = [ "/share/vim-plugins" ];
+    };
   };
 }
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index f77e819d0c83a..b63eb6276a81a 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -7,6 +7,13 @@ with lib;
 
 let
 
+  moduleSettingsType = with types; attrsOf (nullOr (oneOf [ bool str int pathInStore ]));
+  moduleSettingsDescription = ''
+    Boolean values render just the key if true, and nothing if false.
+    Null values are ignored.
+    All other values are rendered as key-value pairs.
+  '';
+
   mkRulesTypeOption = type: mkOption {
     # These options are experimental and subject to breaking changes without notice.
     description = ''
@@ -71,12 +78,12 @@ let
           '';
         };
         settings = mkOption {
-          type = with types; attrsOf (nullOr (oneOf [ bool str int pathInStore ]));
+          type = moduleSettingsType;
           default = {};
           description = ''
             Settings to add as `module-arguments`.
 
-            Boolean values render just the key if true, and nothing if false. Null values are ignored. All other values are rendered as key-value pairs.
+            ${moduleSettingsDescription}
           '';
         };
       };
@@ -660,11 +667,7 @@ let
           (let p11 = config.security.pam.p11; in { name = "p11"; enable = cfg.p11Auth; control = p11.control; modulePath = "${pkgs.pam_p11}/lib/security/pam_p11.so"; args = [
             "${pkgs.opensc}/lib/opensc-pkcs11.so"
           ]; })
-          (let u2f = config.security.pam.u2f; in { name = "u2f"; enable = cfg.u2fAuth; control = u2f.control; modulePath = "${pkgs.pam_u2f}/lib/security/pam_u2f.so"; settings = {
-            inherit (u2f) debug interactive cue origin;
-            authfile = u2f.authFile;
-            appid = u2f.appId;
-          }; })
+          (let u2f = config.security.pam.u2f; in { name = "u2f"; enable = cfg.u2fAuth; control = u2f.control; modulePath = "${pkgs.pam_u2f}/lib/security/pam_u2f.so"; inherit (u2f) settings; })
           (let ussh = config.security.pam.ussh; in { name = "ussh"; enable = config.security.pam.ussh.enable && cfg.usshAuth; control = ussh.control; modulePath = "${pkgs.pam_ussh}/lib/security/pam_ussh.so"; settings = {
             ca_file = ussh.caFile;
             authorized_principals = ussh.authorizedPrincipals;
@@ -723,7 +726,7 @@ let
                 disable_interactive = true;
               }; }
               { name = "kwallet"; enable = cfg.kwallet.enable; control = "optional"; modulePath = "${cfg.kwallet.package}/lib/security/pam_kwallet5.so"; }
-              { name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so"; }
+              { name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so"; }
               { name = "intune"; enable = config.services.intune.enable; control = "optional"; modulePath = "${pkgs.intune-portal}/lib/security/pam_intune.so"; }
               { name = "gnupg"; enable = cfg.gnupg.enable; control = "optional"; modulePath = "${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"; settings = {
                 store-only = cfg.gnupg.storeOnly;
@@ -789,7 +792,7 @@ let
           { name = "krb5"; enable = config.security.pam.krb5.enable; control = "sufficient"; modulePath = "${pam_krb5}/lib/security/pam_krb5.so"; settings = {
             use_first_pass = true;
           }; }
-          { name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so"; settings = {
+          { name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so"; settings = {
             use_authtok = true;
           }; }
         ];
@@ -858,7 +861,7 @@ let
             debug = true;
           }; }
           { name = "kwallet"; enable = cfg.kwallet.enable; control = "optional"; modulePath = "${cfg.kwallet.package}/lib/security/pam_kwallet5.so"; }
-          { name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so"; settings = {
+          { name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so"; settings = {
             auto_start = true;
           }; }
           { name = "gnupg"; enable = cfg.gnupg.enable; control = "optional"; modulePath = "${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"; settings = {
@@ -952,6 +955,12 @@ in
   imports = [
     (mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ])
     (mkRenamedOptionModule [ "security" "pam" "enableSSHAgentAuth" ] [ "security" "pam" "sshAgentAuth" "enable" ])
+    (mkRenamedOptionModule [ "security" "pam" "u2f" "authFile" ] [ "security" "pam" "u2f" "settings" "authfile" ])
+    (mkRenamedOptionModule [ "security" "pam" "u2f" "appId" ] [ "security" "pam" "u2f" "settings" "appid" ])
+    (mkRenamedOptionModule [ "security" "pam" "u2f" "origin" ] [ "security" "pam" "u2f" "settings" "origin" ])
+    (mkRenamedOptionModule [ "security" "pam" "u2f" "debug" ] [ "security" "pam" "u2f" "settings" "debug" ])
+    (mkRenamedOptionModule [ "security" "pam" "u2f" "interactive" ] [ "security" "pam" "u2f" "settings" "interactive" ])
+    (mkRenamedOptionModule [ "security" "pam" "u2f" "cue" ] [ "security" "pam" "u2f" "settings" "cue" ])
   ];
 
   ###### interface
@@ -1144,57 +1153,6 @@ in
         '';
       };
 
-      authFile = mkOption {
-        default = null;
-        type = with types; nullOr path;
-        description = ''
-          By default `pam-u2f` module reads the keys from
-          {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
-          {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
-          not set).
-
-          If you want to change auth file locations or centralize database (for
-          example use {file}`/etc/u2f-mappings`) you can set this
-          option.
-
-          File format is:
-          `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
-          This file can be generated using {command}`pamu2fcfg` command.
-
-          More information can be found [here](https://developers.yubico.com/pam-u2f/).
-        '';
-      };
-
-      appId = mkOption {
-        default = null;
-        type = with types; nullOr str;
-        description = ''
-            By default `pam-u2f` module sets the application
-            ID to `pam://$HOSTNAME`.
-
-            When using {command}`pamu2fcfg`, you can specify your
-            application ID with the `-i` flag.
-
-            More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
-        '';
-      };
-
-      origin = mkOption {
-        default = null;
-        type = with types; nullOr str;
-        description = ''
-            By default `pam-u2f` module sets the origin
-            to `pam://$HOSTNAME`.
-            Setting origin to an host independent value will allow you to
-            reuse credentials across machines
-
-            When using {command}`pamu2fcfg`, you can specify your
-            application ID with the `-o` flag.
-
-            More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
-        '';
-      };
-
       control = mkOption {
         default = "sufficient";
         type = types.enum [ "required" "requisite" "sufficient" "optional" ];
@@ -1209,33 +1167,104 @@ in
         '';
       };
 
-      debug = mkOption {
-        default = false;
-        type = types.bool;
-        description = ''
-          Debug output to stderr.
-        '';
-      };
-
-      interactive = mkOption {
-        default = false;
-        type = types.bool;
-        description = ''
-          Set to prompt a message and wait before testing the presence of a U2F device.
-          Recommended if your device doesn’t have a tactile trigger.
-        '';
-      };
-
-      cue = mkOption {
-        default = false;
-        type = types.bool;
+      settings = mkOption {
+        type = types.submodule {
+          freeformType = moduleSettingsType;
+
+          options = {
+            authfile = mkOption {
+              default = null;
+              type = with types; nullOr path;
+              description = ''
+                By default `pam-u2f` module reads the keys from
+                {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
+                {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
+                not set).
+
+                If you want to change auth file locations or centralize database (for
+                example use {file}`/etc/u2f-mappings`) you can set this
+                option.
+
+                File format is:
+                `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
+                This file can be generated using {command}`pamu2fcfg` command.
+
+                More information can be found [here](https://developers.yubico.com/pam-u2f/).
+              '';
+            };
+
+            appid = mkOption {
+              default = null;
+              type = with types; nullOr str;
+              description = ''
+                  By default `pam-u2f` module sets the application
+                  ID to `pam://$HOSTNAME`.
+
+                  When using {command}`pamu2fcfg`, you can specify your
+                  application ID with the `-i` flag.
+
+                  More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
+              '';
+            };
+
+            origin = mkOption {
+              default = null;
+              type = with types; nullOr str;
+              description = ''
+                  By default `pam-u2f` module sets the origin
+                  to `pam://$HOSTNAME`.
+                  Setting origin to an host independent value will allow you to
+                  reuse credentials across machines
+
+                  When using {command}`pamu2fcfg`, you can specify your
+                  application ID with the `-o` flag.
+
+                  More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
+              '';
+            };
+
+            debug = mkOption {
+              default = false;
+              type = types.bool;
+              description = ''
+                Debug output to stderr.
+              '';
+            };
+
+            interactive = mkOption {
+              default = false;
+              type = types.bool;
+              description = ''
+                Set to prompt a message and wait before testing the presence of a U2F device.
+                Recommended if your device doesn’t have a tactile trigger.
+              '';
+            };
+
+            cue = mkOption {
+              default = false;
+              type = types.bool;
+              description = ''
+                By default `pam-u2f` module does not inform user
+                that he needs to use the u2f device, it just waits without a prompt.
+
+                If you set this option to `true`,
+                `cue` option is added to `pam-u2f`
+                module and reminder message will be displayed.
+              '';
+            };
+          };
+        };
+        default = { };
+        example = {
+          authfile = "/etc/u2f_keys";
+          authpending_file = "";
+          userpresence = 0;
+          pinverification = 1;
+        };
         description = ''
-          By default `pam-u2f` module does not inform user
-          that he needs to use the u2f device, it just waits without a prompt.
+          Options to pass to the PAM module.
 
-          If you set this option to `true`,
-          `cue` option is added to `pam-u2f`
-          module and reminder message will be displayed.
+          ${moduleSettingsDescription}
         '';
       };
     };
diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix
index a3c0715c9e607..abb7925e0935f 100644
--- a/nixos/modules/services/backup/borgbackup.nix
+++ b/nixos/modules/services/backup/borgbackup.nix
@@ -104,6 +104,9 @@ let
             --what="sleep" \
             --why="Scheduled backup" \
         '' + backupScript;
+      unitConfig = optionalAttrs (isLocalPath cfg.repo) {
+        RequiresMountsFor = [ cfg.repo ];
+      };
       serviceConfig = {
         User = cfg.user;
         Group = cfg.group;
diff --git a/nixos/modules/services/backup/duplicity.nix b/nixos/modules/services/backup/duplicity.nix
index 033d0cffd8d6e..46625ec5460e4 100644
--- a/nixos/modules/services/backup/duplicity.nix
+++ b/nixos/modules/services/backup/duplicity.nix
@@ -42,6 +42,28 @@ in
       '';
     };
 
+    includeFileList = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      example = /path/to/fileList.txt;
+      description = ''
+        File containing newline-separated list of paths to include into the
+        backups. See the FILE SELECTION section in {manpage}`duplicity(1)` for
+        details on the syntax.
+      '';
+    };
+
+    excludeFileList = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      example = /path/to/fileList.txt;
+      description = ''
+        File containing newline-separated list of paths to exclude into the
+        backups. See the FILE SELECTION section in {manpage}`duplicity(1)` for
+        details on the syntax.
+      '';
+    };
+
     targetUrl = mkOption {
       type = types.str;
       example = "s3://host:port/prefix";
@@ -154,6 +176,8 @@ in
             ${lib.optionalString (cfg.cleanup.maxIncr != null) "${dup} remove-all-inc-of-but-n-full ${toString cfg.cleanup.maxIncr} ${target} --force ${extra}"}
             exec ${dup} ${if cfg.fullIfOlderThan == "always" then "full" else "incr"} ${lib.escapeShellArgs (
               [ cfg.root cfg.targetUrl ]
+              ++ lib.optionals (cfg.includeFileList != null) [ "--include-filelist" cfg.includeFileList ]
+              ++ lib.optionals (cfg.excludeFileList != null) [ "--exclude-filelist" cfg.excludeFileList ]
               ++ concatMap (p: [ "--include" p ]) cfg.include
               ++ concatMap (p: [ "--exclude" p ]) cfg.exclude
               ++ (lib.optionals (cfg.fullIfOlderThan != "never" && cfg.fullIfOlderThan != "always") [ "--full-if-older-than" cfg.fullIfOlderThan ])
diff --git a/nixos/modules/services/backup/tsm.nix b/nixos/modules/services/backup/tsm.nix
index dc5d8f09e069b..9e1abb85bfe54 100644
--- a/nixos/modules/services/backup/tsm.nix
+++ b/nixos/modules/services/backup/tsm.nix
@@ -90,7 +90,7 @@ in
       environment.HOME = "/var/lib/tsm-backup";
       serviceConfig = {
         # for exit status description see
-        # https://www.ibm.com/docs/en/storage-protect/8.1.22?topic=clients-client-return-codes
+        # https://www.ibm.com/docs/en/storage-protect/8.1.23?topic=clients-client-return-codes
         SuccessExitStatus = "4 8";
         # The `-se` option must come after the command.
         # The `-optfile` option suppresses a `dsm.opt`-not-found warning.
diff --git a/nixos/modules/services/cluster/patroni/default.nix b/nixos/modules/services/cluster/patroni/default.nix
index d1a165603fdaa..3b563bb89fffb 100644
--- a/nixos/modules/services/cluster/patroni/default.nix
+++ b/nixos/modules/services/cluster/patroni/default.nix
@@ -10,6 +10,15 @@ let
   configFile = format.generate configFileName cfg.settings;
 in
 {
+  imports = [
+    (lib.mkRemovedOptionModule [ "services" "patroni" "raft" ] ''
+      Raft has been deprecated by upstream.
+    '')
+    (lib.mkRemovedOptionModule [ "services" "patroni" "raftPort" ] ''
+      Raft has been deprecated by upstream.
+    '')
+  ];
+
   options.services.patroni = {
 
     enable = mkEnableOption "Patroni";
@@ -68,7 +77,7 @@ in
       type = types.path;
       default = "/var/lib/patroni";
       description = ''
-        Folder where Patroni data will be written, used by Raft as well if enabled.
+        Folder where Patroni data will be written, this is where the pgpass password file will be written.
       '';
     };
 
@@ -120,22 +129,6 @@ in
       '';
     };
 
-    raft = mkOption {
-      type = types.bool;
-      default = false;
-      description = ''
-        This will configure Patroni to use its own RAFT implementation instead of using a dedicated DCS.
-      '';
-    };
-
-    raftPort = mkOption {
-      type = types.port;
-      default = 5010;
-      description = ''
-        The port on which RAFT listens.
-      '';
-    };
-
     softwareWatchdog = mkOption {
       type = types.bool;
       default = false;
@@ -178,12 +171,6 @@ in
         connect_address = "${cfg.nodeIp}:${toString cfg.restApiPort}";
       };
 
-      raft = mkIf cfg.raft {
-        data_dir = "${cfg.dataDir}/raft";
-        self_addr = "${cfg.nodeIp}:5010";
-        partner_addrs = map (ip: ip + ":5010") cfg.otherNodesIps;
-      };
-
       postgresql = {
         listen = "${cfg.nodeIp}:${toString cfg.postgresqlPort}";
         connect_address = "${cfg.nodeIp}:${toString cfg.postgresqlPort}";
@@ -235,7 +222,7 @@ in
             KillMode = "process";
           }
           (mkIf (cfg.postgresqlDataDir == "/var/lib/postgresql/${cfg.postgresqlPackage.psqlSchema}" && cfg.dataDir == "/var/lib/patroni") {
-            StateDirectory = "patroni patroni/raft postgresql postgresql/${cfg.postgresqlPackage.psqlSchema}";
+            StateDirectory = "patroni postgresql postgresql/${cfg.postgresqlPackage.psqlSchema}";
             StateDirectoryMode = "0750";
           })
         ];
@@ -251,7 +238,6 @@ in
     environment.systemPackages = [
       pkgs.patroni
       cfg.postgresqlPackage
-      (mkIf cfg.raft pkgs.python310Packages.pysyncobj)
     ];
 
     environment.etc."${configFileName}".source = configFile;
diff --git a/nixos/modules/services/cluster/rke2/default.nix b/nixos/modules/services/cluster/rke2/default.nix
index 9ddbd299fdf8d..51b849ebcc802 100644
--- a/nixos/modules/services/cluster/rke2/default.nix
+++ b/nixos/modules/services/cluster/rke2/default.nix
@@ -241,7 +241,7 @@ in
       "kernel.panic_on_oops" = 1;
     };
 
-    systemd.services.rke2 = {
+    systemd.services."rke2-${cfg.role}" = {
       description = "Rancher Kubernetes Engine v2";
       documentation = [ "https://github.com/rancher/rke2#readme" ];
       after = [ "network-online.target" ];
diff --git a/nixos/modules/services/continuous-integration/gitlab-runner.nix b/nixos/modules/services/continuous-integration/gitlab-runner.nix
index 1771ca0b980b9..c603aff38038a 100644
--- a/nixos/modules/services/continuous-integration/gitlab-runner.nix
+++ b/nixos/modules/services/continuous-integration/gitlab-runner.nix
@@ -137,8 +137,10 @@ let
             "--builds-dir ${service.buildsDir}"
             ++ optional (service.cloneUrl != null)
             "--clone-url ${service.cloneUrl}"
-            ++ optional (service.preCloneScript != null)
-            "--pre-clone-script ${service.preCloneScript}"
+            ++ optional (service.preGetSourcesScript != null)
+            "--pre-get-sources-script ${service.preGetSourcesScript}"
+            ++ optional (service.postGetSourcesScript != null)
+            "--post-get-sources-script ${service.postGetSourcesScript}"
             ++ optional (service.preBuildScript != null)
             "--pre-build-script ${service.preBuildScript}"
             ++ optional (service.postBuildScript != null)
@@ -495,13 +497,20 @@ in {
               Whitelist allowed services.
             '';
           };
-          preCloneScript = mkOption {
+          preGetSourcesScript = mkOption {
             type = types.nullOr types.path;
             default = null;
             description = ''
               Runner-specific command script executed before code is pulled.
             '';
           };
+          postGetSourcesScript = mkOption {
+            type = types.nullOr types.path;
+            default = null;
+            description = ''
+              Runner-specific command script executed after code is pulled.
+            '';
+          };
           preBuildScript = mkOption {
             type = types.nullOr types.path;
             default = null;
diff --git a/nixos/modules/services/continuous-integration/woodpecker/agents.nix b/nixos/modules/services/continuous-integration/woodpecker/agents.nix
index ce5926a246bbe..b88bc6a0ccac0 100644
--- a/nixos/modules/services/continuous-integration/woodpecker/agents.nix
+++ b/nixos/modules/services/continuous-integration/woodpecker/agents.nix
@@ -109,7 +109,7 @@ let
   };
 in
 {
-  meta.maintainers = with lib.maintainers; [ janik ambroisie ];
+  meta.maintainers = with lib.maintainers; [ ambroisie ];
 
   options = {
     services.woodpecker-agents = {
diff --git a/nixos/modules/services/continuous-integration/woodpecker/server.nix b/nixos/modules/services/continuous-integration/woodpecker/server.nix
index 54d8da8a59e5e..6e3cfb0b0114c 100644
--- a/nixos/modules/services/continuous-integration/woodpecker/server.nix
+++ b/nixos/modules/services/continuous-integration/woodpecker/server.nix
@@ -8,7 +8,7 @@ let
   cfg = config.services.woodpecker-server;
 in
 {
-  meta.maintainers = with lib.maintainers; [ janik ambroisie ];
+  meta.maintainers = with lib.maintainers; [ ambroisie ];
 
 
   options = {
diff --git a/nixos/modules/services/databases/monetdb.nix b/nixos/modules/services/databases/monetdb.nix
index 5025eb30369b4..ee24cf2b0fc20 100644
--- a/nixos/modules/services/databases/monetdb.nix
+++ b/nixos/modules/services/databases/monetdb.nix
@@ -6,7 +6,7 @@ let
   cfg = config.services.monetdb;
 
 in {
-  meta.maintainers = with maintainers; [ StillerHarpo primeos ];
+  meta.maintainers = with maintainers; [ StillerHarpo ];
 
   ###### interface
   options = {
diff --git a/nixos/modules/services/desktop-managers/lomiri.nix b/nixos/modules/services/desktop-managers/lomiri.nix
index 0b871aa38183e..e1de29ba3b597 100644
--- a/nixos/modules/services/desktop-managers/lomiri.nix
+++ b/nixos/modules/services/desktop-managers/lomiri.nix
@@ -21,8 +21,11 @@ in {
         history-service
         libusermetrics
         lomiri
+        lomiri-calculator-app
+        lomiri-clock-app
         lomiri-download-manager
         lomiri-filemanager-app
+        lomiri-polkit-agent
         lomiri-schemas # exposes some required dbus interfaces
         lomiri-session # wrappers to properly launch the session
         lomiri-sounds
@@ -35,7 +38,7 @@ in {
         morph-browser
         qtmir # not having its desktop file for Xwayland available causes any X11 application to crash the session
         suru-icon-theme
-        # telephony-service # currently broken: https://github.com/NixOS/nixpkgs/pull/314043
+        telephony-service
       ]);
       variables = {
         # To override the keyboard layouts in Lomiri
@@ -84,7 +87,7 @@ in {
       ] ++ lib.optionals (config.hardware.pulseaudio.enable || config.services.pipewire.pulse.enable) [
         ayatana-indicator-sound
       ]) ++ (with pkgs.lomiri; [
-        # telephony-service # currently broken: https://github.com/NixOS/nixpkgs/pull/314043
+        telephony-service
       ] ++ lib.optionals config.networking.networkmanager.enable [
         lomiri-indicator-network
       ]);
@@ -145,6 +148,18 @@ in {
           ExecStart = "${pkgs.lomiri.lomiri-url-dispatcher}/libexec/lomiri-url-dispatcher/lomiri-update-directory /run/current-system/sw/share/lomiri-url-dispatcher/urls/";
         };
       };
+
+      "lomiri-polkit-agent" = rec {
+        description = "Lomiri Polkit agent";
+        wantedBy = [ "lomiri.service" "lomiri-full-greeter.service" "lomiri-full-shell.service" "lomiri-greeter.service" "lomiri-shell.service" ];
+        after = [ "graphical-session.target" ];
+        partOf = wantedBy;
+        serviceConfig = {
+          Type = "simple";
+          Restart = "always";
+          ExecStart = "${pkgs.lomiri.lomiri-polkit-agent}/libexec/lomiri-polkit-agent/policykit-agent";
+        };
+      };
     };
 
     systemd.services = {
diff --git a/nixos/modules/services/desktops/espanso.nix b/nixos/modules/services/desktops/espanso.nix
index a6b8a078247b1..a2c4b77b90464 100644
--- a/nixos/modules/services/desktops/espanso.nix
+++ b/nixos/modules/services/desktops/espanso.nix
@@ -8,6 +8,7 @@ in {
   options = {
     services.espanso = {
       enable = mkEnableOption "Espanso";
+      wayland = mkEnableOption "use the Wayland compatible espanso package";
       package = mkPackageOption pkgs "espanso" {
         example = "pkgs.espanso-wayland";
       };
diff --git a/nixos/modules/services/desktops/gnome/gnome-keyring.nix b/nixos/modules/services/desktops/gnome/gnome-keyring.nix
index 02b198fd81cb9..550c6ba8eff54 100644
--- a/nixos/modules/services/desktops/gnome/gnome-keyring.nix
+++ b/nixos/modules/services/desktops/gnome/gnome-keyring.nix
@@ -26,33 +26,22 @@ in
   };
 
   config = lib.mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.gnome.gnome-keyring ];
+    environment.systemPackages = [ pkgs.gnome-keyring ];
 
     services.dbus.packages = [
-      pkgs.gnome.gnome-keyring
+      pkgs.gnome-keyring
       pkgs.gcr
     ];
 
-    xdg.portal.extraPortals = [ pkgs.gnome.gnome-keyring ];
-
-    security.pam.services = lib.mkMerge [
-      {
-        login.enableGnomeKeyring = true;
-      }
-      (lib.mkIf config.services.xserver.displayManager.gdm.enable {
-        gdm-password.enableGnomeKeyring = true;
-        gdm-autologin.enableGnomeKeyring = true;
-      })
-      (lib.mkIf (config.services.xserver.displayManager.gdm.enable && config.services.fprintd.enable) {
-        gdm-fingerprint.enableGnomeKeyring = true;
-      })
-    ];
+    xdg.portal.extraPortals = [ pkgs.gnome-keyring ];
+
+    security.pam.services.login.enableGnomeKeyring = true;
 
     security.wrappers.gnome-keyring-daemon = {
       owner = "root";
       group = "root";
       capabilities = "cap_ipc_lock=ep";
-      source = "${pkgs.gnome.gnome-keyring}/bin/gnome-keyring-daemon";
+      source = "${pkgs.gnome-keyring}/bin/gnome-keyring-daemon";
     };
   };
 }
diff --git a/nixos/modules/services/desktops/gnome/gnome-user-share.nix b/nixos/modules/services/desktops/gnome/gnome-user-share.nix
index 2c6d94b7bdfc6..518beb80419a9 100644
--- a/nixos/modules/services/desktops/gnome/gnome-user-share.nix
+++ b/nixos/modules/services/desktops/gnome/gnome-user-share.nix
@@ -26,11 +26,11 @@
   config = lib.mkIf config.services.gnome.gnome-user-share.enable {
 
     environment.systemPackages = [
-      pkgs.gnome.gnome-user-share
+      pkgs.gnome-user-share
     ];
 
     systemd.packages = [
-      pkgs.gnome.gnome-user-share
+      pkgs.gnome-user-share
     ];
 
   };
diff --git a/nixos/modules/services/desktops/gnome/rygel.nix b/nixos/modules/services/desktops/gnome/rygel.nix
index c980b239d521e..7ce7e079b6af6 100644
--- a/nixos/modules/services/desktops/gnome/rygel.nix
+++ b/nixos/modules/services/desktops/gnome/rygel.nix
@@ -23,12 +23,12 @@
 
   ###### implementation
   config = lib.mkIf config.services.gnome.rygel.enable {
-    environment.systemPackages = [ pkgs.gnome.rygel ];
+    environment.systemPackages = [ pkgs.rygel ];
 
-    services.dbus.packages = [ pkgs.gnome.rygel ];
+    services.dbus.packages = [ pkgs.rygel ];
 
-    systemd.packages = [ pkgs.gnome.rygel ];
+    systemd.packages = [ pkgs.rygel ];
 
-    environment.etc."rygel.conf".source = "${pkgs.gnome.rygel}/etc/rygel.conf";
+    environment.etc."rygel.conf".source = "${pkgs.rygel}/etc/rygel.conf";
   };
 }
diff --git a/nixos/modules/services/desktops/gnome/sushi.nix b/nixos/modules/services/desktops/gnome/sushi.nix
index 946030e4bb229..7f7360488eb41 100644
--- a/nixos/modules/services/desktops/gnome/sushi.nix
+++ b/nixos/modules/services/desktops/gnome/sushi.nix
@@ -31,9 +31,9 @@
 
   config = lib.mkIf config.services.gnome.sushi.enable {
 
-    environment.systemPackages = [ pkgs.gnome.sushi ];
+    environment.systemPackages = [ pkgs.sushi ];
 
-    services.dbus.packages = [ pkgs.gnome.sushi ];
+    services.dbus.packages = [ pkgs.sushi ];
 
   };
 
diff --git a/nixos/modules/services/desktops/playerctld.nix b/nixos/modules/services/desktops/playerctld.nix
new file mode 100644
index 0000000000000..ef4866d75715d
--- /dev/null
+++ b/nixos/modules/services/desktops/playerctld.nix
@@ -0,0 +1,32 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+
+let
+  cfg = config.services.playerctld;
+in
+{
+  options.services.playerctld = {
+    enable = lib.mkEnableOption "the playerctld daemon";
+
+    package = lib.mkPackageOption pkgs "playerctl" { };
+  };
+
+  config = lib.mkIf cfg.enable {
+    environment.systemPackages = [ cfg.package ];
+    systemd.user.services.playerctld = {
+      description = "Playerctld daemon to track media player activity";
+      wantedBy = [ "default.target" ];
+
+      serviceConfig = {
+        Type = "exec";
+        ExecStart = "${cfg.package}/bin/playerctld";
+      };
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ aacebedo ];
+}
diff --git a/nixos/modules/services/games/terraria.nix b/nixos/modules/services/games/terraria.nix
index 57417b614f713..4c32cc92a1b94 100644
--- a/nixos/modules/services/games/terraria.nix
+++ b/nixos/modules/services/games/terraria.nix
@@ -19,15 +19,28 @@ let
     (boolFlag "secure" cfg.secure)
     (boolFlag "noupnp" cfg.noUPnP)
   ];
-  stopScript = pkgs.writeScript "terraria-stop" ''
-    #!${pkgs.runtimeShell}
 
+  tmuxCmd = "${lib.getExe pkgs.tmux} -S ${lib.escapeShellArg cfg.dataDir}/terraria.sock";
+
+  stopScript = pkgs.writeShellScript "terraria-stop" ''
     if ! [ -d "/proc/$1" ]; then
       exit 0
     fi
 
-    ${getBin pkgs.tmux}/bin/tmux -S ${cfg.dataDir}/terraria.sock send-keys Enter exit Enter
-    ${getBin pkgs.coreutils}/bin/tail --pid="$1" -f /dev/null
+    lastline=$(${tmuxCmd} capture-pane -p | grep . | tail -n1)
+
+    # If the service is not configured to auto-start a world, it will show the world selection prompt
+    # If the last non-empty line on-screen starts with "Choose World", we know the prompt is open
+    if [[ "$lastline" =~ ^'Choose World' ]]; then
+      # In this case, nothing needs to be saved, so we can kill the process
+      ${tmuxCmd} kill-session
+    else
+      # Otherwise, we send the `exit` command
+      ${tmuxCmd} send-keys Enter exit Enter
+    fi
+
+    # Wait for the process to stop
+    tail --pid="$1" -f /dev/null
   '';
 in
 {
@@ -152,7 +165,7 @@ in
         Type = "forking";
         GuessMainPID = true;
         UMask = 007;
-        ExecStart = "${getBin pkgs.tmux}/bin/tmux -S ${cfg.dataDir}/terraria.sock new -d ${pkgs.terraria-server}/bin/TerrariaServer ${concatStringsSep " " flags}";
+        ExecStart = "${tmuxCmd} new -d ${pkgs.terraria-server}/bin/TerrariaServer ${concatStringsSep " " flags}";
         ExecStop = "${stopScript} $MAINPID";
       };
     };
diff --git a/nixos/modules/services/mail/roundcube.nix b/nixos/modules/services/mail/roundcube.nix
index 78f627d33e2df..2914877bdccde 100644
--- a/nixos/modules/services/mail/roundcube.nix
+++ b/nixos/modules/services/mail/roundcube.nix
@@ -93,13 +93,17 @@ in
     maxAttachmentSize = mkOption {
       type = types.int;
       default = 18;
+      apply = configuredMaxAttachmentSize: "${toString (configuredMaxAttachmentSize * 1.37)}M";
       description = ''
         The maximum attachment size in MB.
-
-        Note: Since roundcube only uses 70% of max upload values configured in php
-        30% is added automatically to [](#opt-services.roundcube.maxAttachmentSize).
+        [upstream issue comment]: https://github.com/roundcube/roundcubemail/issues/7979#issuecomment-808879209
+        ::: {.note}
+        Since there is some overhead in base64 encoding applied to attachments, + 37% will be added
+        to the value set in this option in order to offset the overhead. For example, setting
+        `maxAttachmentSize` to `100` would result in `137M` being the real value in the configuration.
+        See [upstream issue comment] for more details on the motivations behind this.
+        :::
       '';
-      apply = configuredMaxAttachmentSize: "${toString (configuredMaxAttachmentSize * 1.3)}M";
     };
 
     configureNginx = lib.mkOption {
diff --git a/nixos/modules/services/mail/stalwart-mail.nix b/nixos/modules/services/mail/stalwart-mail.nix
index 776243a68af53..1025788f0d84d 100644
--- a/nixos/modules/services/mail/stalwart-mail.nix
+++ b/nixos/modules/services/mail/stalwart-mail.nix
@@ -9,12 +9,28 @@ let
   dataDir = "/var/lib/stalwart-mail";
   useLegacyStorage = versionOlder config.system.stateVersion "24.11";
 
+  parsePorts = listeners: let
+    parseAddresses = listeners: lib.flatten(lib.mapAttrsToList (name: value: value.bind) listeners);
+    splitAddress = addr: strings.splitString ":" addr;
+    extractPort = addr: strings.toInt(builtins.foldl' (a: b: b) "" (splitAddress addr));
+  in
+    builtins.map(address: extractPort address) (parseAddresses listeners);
+
 in {
   options.services.stalwart-mail = {
     enable = mkEnableOption "the Stalwart all-in-one email server";
 
     package = mkPackageOption pkgs "stalwart-mail" { };
 
+    openFirewall = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to open TCP firewall ports, which are specified in
+        {option}`services.stalwart-mail.settings.listener` on all interfaces.
+      '';
+    };
+
     settings = mkOption {
       inherit (configFormat) type;
       default = { };
@@ -138,6 +154,11 @@ in {
 
     # Make admin commands available in the shell
     environment.systemPackages = [ cfg.package ];
+
+    networking.firewall = mkIf (cfg.openFirewall
+      && (builtins.hasAttr "listener" cfg.settings.server)) {
+      allowedTCPPorts = parsePorts cfg.settings.server.listener;
+    };
   };
 
   meta = {
diff --git a/nixos/modules/services/misc/dictd.nix b/nixos/modules/services/misc/dictd.nix
index 8cb51bb0b7a7f..6660d5e977ffb 100644
--- a/nixos/modules/services/misc/dictd.nix
+++ b/nixos/modules/services/misc/dictd.nix
@@ -62,6 +62,9 @@ in
       description = "DICT.org Dictionary Server";
       wantedBy = [ "multi-user.target" ];
       environment = { LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; };
+      # Work around the fact that dictd doesn't handle SIGTERM; it terminates
+      # with code 143 instead of exiting with code 0.
+      serviceConfig.SuccessExitStatus = [ 143 ];
       serviceConfig.Type = "forking";
       script = "${pkgs.dict}/sbin/dictd -s -c ${dictdb}/share/dictd/dictd.conf --locale en_US.UTF-8";
     };
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 7b96a182f0d94..492c669f180a9 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -12,7 +12,7 @@ let
   postgresqlPackage = if config.services.postgresql.enable then
                         config.services.postgresql.package
                       else
-                        pkgs.postgresql_13;
+                        pkgs.postgresql_14;
 
   gitlabSocket = "${cfg.statePath}/tmp/sockets/gitlab.socket";
   gitalySocket = "${cfg.statePath}/tmp/sockets/gitaly.socket";
@@ -1119,8 +1119,8 @@ in {
         message = "services.gitlab.secrets.jwsFile must be set!";
       }
       {
-        assertion = versionAtLeast postgresqlPackage.version "13.6.0";
-        message = "PostgreSQL >=13.6 is required to run GitLab 16. Follow the instructions in the manual section for upgrading PostgreSQL here: https://nixos.org/manual/nixos/stable/index.html#module-services-postgres-upgrading";
+        assertion = versionAtLeast postgresqlPackage.version "14.9";
+        message = "PostgreSQL >= 14.9 is required to run GitLab 17. Follow the instructions in the manual section for upgrading PostgreSQL here: https://nixos.org/manual/nixos/stable/index.html#module-services-postgres-upgrading";
       }
     ];
 
@@ -1282,6 +1282,7 @@ in {
       "d ${gitlabConfig.production.shared.path}/registry 0750 ${cfg.user} ${cfg.group} -"
       "d ${gitlabConfig.production.shared.path}/terraform_state 0750 ${cfg.user} ${cfg.group} -"
       "d ${gitlabConfig.production.shared.path}/ci_secure_files 0750 ${cfg.user} ${cfg.group} -"
+      "d ${gitlabConfig.production.shared.path}/external-diffs 0750 ${cfg.user} ${cfg.group} -"
       "L+ /run/gitlab/config - - - - ${cfg.statePath}/config"
       "L+ /run/gitlab/log - - - - ${cfg.statePath}/log"
       "L+ /run/gitlab/tmp - - - - ${cfg.statePath}/tmp"
diff --git a/nixos/modules/services/misc/jellyseerr.nix b/nixos/modules/services/misc/jellyseerr.nix
index 7599a1af33840..9aab517e0493b 100644
--- a/nixos/modules/services/misc/jellyseerr.nix
+++ b/nixos/modules/services/misc/jellyseerr.nix
@@ -9,6 +9,7 @@ in
 
   options.services.jellyseerr = {
     enable = mkEnableOption ''Jellyseerr, a requests manager for Jellyfin'';
+    package = mkPackageOption pkgs "jellyseerr" { };
 
     openFirewall = mkOption {
       type = types.bool;
@@ -32,10 +33,10 @@ in
       serviceConfig = {
         Type = "exec";
         StateDirectory = "jellyseerr";
-        WorkingDirectory = "${pkgs.jellyseerr}/libexec/jellyseerr/deps/jellyseerr";
+        WorkingDirectory = "${cfg.package}/libexec/jellyseerr/deps/jellyseerr";
         DynamicUser = true;
-        ExecStart = "${pkgs.jellyseerr}/bin/jellyseerr";
-        BindPaths = [ "/var/lib/jellyseerr/:${pkgs.jellyseerr}/libexec/jellyseerr/deps/jellyseerr/config/" ];
+        ExecStart = lib.getExe cfg.package;
+        BindPaths = [ "/var/lib/jellyseerr/:${cfg.package}/libexec/jellyseerr/deps/jellyseerr/config/" ];
         Restart = "on-failure";
         ProtectHome = true;
         ProtectSystem = "strict";
diff --git a/nixos/modules/services/misc/languagetool.nix b/nixos/modules/services/misc/languagetool.nix
index ba563dace4737..2a7e68c9053a3 100644
--- a/nixos/modules/services/misc/languagetool.nix
+++ b/nixos/modules/services/misc/languagetool.nix
@@ -1,14 +1,17 @@
-{ config, lib, options, pkgs, ... }:
+{ config, lib, pkgs, ... }:
 
 with lib;
 
 let
   cfg = config.services.languagetool;
-  settingsFormat = pkgs.formats.javaProperties {};
-in {
+  settingsFormat = pkgs.formats.javaProperties { };
+in
+{
   options.services.languagetool = {
     enable = mkEnableOption "the LanguageTool server, a multilingual spelling, style, and grammar checker that helps correct or paraphrase texts";
 
+    package = mkPackageOption pkgs "languagetool" { };
+
     port = mkOption {
       type = types.port;
       default = 8081;
@@ -31,7 +34,7 @@ in {
       '';
     };
 
-    settings = lib.mkOption {
+    settings = mkOption {
       type = types.submodule {
         freeformType = settingsFormat.type;
 
@@ -49,11 +52,25 @@ in {
         for supported settings.
       '';
     };
+
+    jrePackage = mkPackageOption pkgs "jre" { };
+
+    jvmOptions = mkOption {
+      description = ''
+        Extra command line options for the JVM running languagetool.
+        More information can be found here: https://docs.oracle.com/en/java/javase/19/docs/specs/man/java.html#standard-options-for-java
+      '';
+      default = [ ];
+      type = types.listOf types.str;
+      example = [
+        "-Xmx512m"
+      ];
+    };
   };
 
   config = mkIf cfg.enable {
 
-    systemd.services.languagetool =  {
+    systemd.services.languagetool = {
       description = "LanguageTool HTTP server";
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
@@ -65,13 +82,17 @@ in {
         RestrictNamespaces = [ "" ];
         SystemCallFilter = [ "@system-service" "~ @privileged" ];
         ProtectHome = "yes";
+        Restart = "on-failure";
         ExecStart = ''
-          ${pkgs.languagetool}/bin/languagetool-http-server \
-            --port ${toString cfg.port} \
-            ${optionalString cfg.public "--public"} \
-            ${optionalString (cfg.allowOrigin != null) "--allow-origin ${cfg.allowOrigin}"} \
-            "--config" ${settingsFormat.generate "languagetool.conf" cfg.settings}
-          '';
+          ${cfg.jrePackage}/bin/java \
+            -cp ${cfg.package}/share/languagetool-server.jar \
+            ${toString cfg.jvmOptions} \
+            org.languagetool.server.HTTPServer \
+              --port ${toString cfg.port} \
+              ${optionalString cfg.public "--public"} \
+              ${optionalString (cfg.allowOrigin != null) "--allow-origin ${cfg.allowOrigin}"} \
+              "--config" ${settingsFormat.generate "languagetool.conf" cfg.settings}
+        '';
       };
     };
   };
diff --git a/nixos/modules/services/misc/ollama.nix b/nixos/modules/services/misc/ollama.nix
index c460514783efc..a0a32f1702bf3 100644
--- a/nixos/modules/services/misc/ollama.nix
+++ b/nixos/modules/services/misc/ollama.nix
@@ -5,9 +5,6 @@ let
   cfg = config.services.ollama;
   ollamaPackage = cfg.package.override {
     inherit (cfg) acceleration;
-    linuxPackages = config.boot.kernelPackages // {
-      nvidia_x11 = config.hardware.nvidia.package;
-    };
   };
 in
 {
diff --git a/nixos/modules/services/misc/renovate.nix b/nixos/modules/services/misc/renovate.nix
index 25a719c91cbd8..9062b7424b681 100644
--- a/nixos/modules/services/misc/renovate.nix
+++ b/nixos/modules/services/misc/renovate.nix
@@ -128,6 +128,7 @@ in
         RestrictAddressFamilies = [
           "AF_INET"
           "AF_INET6"
+          "AF_UNIX"
         ];
         RestrictNamespaces = true;
         RestrictRealtime = true;
diff --git a/nixos/modules/services/misc/rkvm.nix b/nixos/modules/services/misc/rkvm.nix
index 9d41669e00f61..b149c3d3979f5 100644
--- a/nixos/modules/services/misc/rkvm.nix
+++ b/nixos/modules/services/misc/rkvm.nix
@@ -7,7 +7,7 @@ let
   toml = pkgs.formats.toml { };
 in
 {
-  meta.maintainers = with maintainers; [ ckie ];
+  meta.maintainers = with maintainers; [ ];
 
   options.services.rkvm = {
     enable = mkOption {
diff --git a/nixos/modules/services/misc/snapper.nix b/nixos/modules/services/misc/snapper.nix
index 1b16ef7958ad2..fc57683de3280 100644
--- a/nixos/modules/services/misc/snapper.nix
+++ b/nixos/modules/services/misc/snapper.nix
@@ -96,48 +96,48 @@ let
     };
 
     TIMELINE_LIMIT_HOURLY = mkOption {
-      type = types.str;
-      default = "10";
+      type = types.int;
+      default = 10;
       description = ''
         Limits for timeline cleanup.
       '';
     };
 
     TIMELINE_LIMIT_DAILY = mkOption {
-      type = types.str;
-      default = "10";
+      type = types.int;
+      default = 10;
       description = ''
         Limits for timeline cleanup.
       '';
     };
 
     TIMELINE_LIMIT_WEEKLY = mkOption {
-      type = types.str;
-      default = "0";
+      type = types.int;
+      default = 0;
       description = ''
         Limits for timeline cleanup.
       '';
     };
 
     TIMELINE_LIMIT_MONTHLY = mkOption {
-      type = types.str;
-      default = "10";
+      type = types.int;
+      default = 10;
       description = ''
         Limits for timeline cleanup.
       '';
     };
 
     TIMELINE_LIMIT_QUARTERLY = mkOption {
-      type = types.str;
-      default = "0";
+      type = types.int;
+      default = 0;
       description = ''
         Limits for timeline cleanup.
       '';
     };
 
     TIMELINE_LIMIT_YEARLY = mkOption {
-      type = types.str;
-      default = "10";
+      type = types.int;
+      default = 10;
       description = ''
         Limits for timeline cleanup.
       '';
@@ -353,4 +353,6 @@ in
       ) (attrNames cfg.configs);
     }
   );
+
+  meta.maintainers = with lib.maintainers; [ Djabx ];
 }
diff --git a/nixos/modules/services/misc/sonarr.nix b/nixos/modules/services/misc/sonarr.nix
index 228a2d48f5a9c..60e73198d60de 100644
--- a/nixos/modules/services/misc/sonarr.nix
+++ b/nixos/modules/services/misc/sonarr.nix
@@ -1,4 +1,4 @@
-{ config, pkgs, lib, ... }:
+{ config, pkgs, lib, utils, ... }:
 
 with lib;
 
@@ -54,7 +54,11 @@ in
         Type = "simple";
         User = cfg.user;
         Group = cfg.group;
-        ExecStart = "${cfg.package}/bin/NzbDrone -nobrowser -data='${cfg.dataDir}'";
+        ExecStart = utils.escapeSystemdExecArgs [
+          (lib.getExe cfg.package)
+          "-nobrowser"
+          "-data=${cfg.dataDir}"
+        ];
         Restart = "on-failure";
       };
     };
diff --git a/nixos/modules/services/misc/zoneminder.nix b/nixos/modules/services/misc/zoneminder.nix
index d09cd87febfff..8db63d5386332 100644
--- a/nixos/modules/services/misc/zoneminder.nix
+++ b/nixos/modules/services/misc/zoneminder.nix
@@ -202,10 +202,10 @@ in {
     ];
 
     services = {
-      fcgiwrap = lib.mkIf useNginx {
-        enable = true;
-        preforkProcesses = cfg.cameras;
-        inherit user group;
+      fcgiwrap.zoneminder = lib.mkIf useNginx {
+        process.prefork = cfg.cameras;
+        process.user = user;
+        process.group = group;
       };
 
       mysql = lib.mkIf cfg.database.createLocally {
@@ -225,9 +225,7 @@ in {
             default = true;
             root = "${pkg}/share/zoneminder/www";
             listen = [ { addr = "0.0.0.0"; inherit (cfg) port; } ];
-            extraConfig = let
-              fcgi = config.services.fcgiwrap;
-            in ''
+            extraConfig = ''
               index index.php;
 
               location / {
@@ -257,7 +255,7 @@ in {
                   fastcgi_param HTTP_PROXY "";
                   fastcgi_intercept_errors on;
 
-                  fastcgi_pass ${fcgi.socketType}:${fcgi.socketAddress};
+                  fastcgi_pass unix:${config.services.fcgiwrap.zoneminder.socket.address};
                 }
 
                 location /cache/ {
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
index 32919950adc1e..eae2658b7ffb8 100644
--- a/nixos/modules/services/monitoring/grafana.nix
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -105,7 +105,7 @@ let
       };
       url = mkOption {
         type = types.str;
-        default = "localhost";
+        default = "";
         description = "Url of the datasource.";
       };
       editable = mkOption {
diff --git a/nixos/modules/services/monitoring/nezha-agent.nix b/nixos/modules/services/monitoring/nezha-agent.nix
index 8312a425d28fc..7ebbc7f2f3297 100644
--- a/nixos/modules/services/monitoring/nezha-agent.nix
+++ b/nixos/modules/services/monitoring/nezha-agent.nix
@@ -24,6 +24,13 @@ in
           Enable SSL/TLS encryption.
         '';
       };
+      gpu = lib.mkOption {
+        type = lib.types.bool;
+        default = true;
+        description = ''
+          Enable GPU monitoring.
+        '';
+      };
       disableCommandExecute = lib.mkOption {
         type = lib.types.bool;
         default = true;
@@ -46,7 +53,12 @@ in
         '';
       };
       reportDelay = lib.mkOption {
-        type = lib.types.enum [ 1 2 3 4 ];
+        type = lib.types.enum [
+          1
+          2
+          3
+          4
+        ];
         default = 1;
         description = ''
           The interval between system status reportings.
@@ -96,6 +108,7 @@ in
         ++ lib.optional cfg.skipConnection "--skip-conn"
         ++ lib.optional cfg.skipProcess "--skip-procs"
         ++ lib.optional cfg.tls "--tls"
+        ++ lib.optional cfg.gpu "--gpu"
       );
       wantedBy = [ "multi-user.target" ];
     };
diff --git a/nixos/modules/services/monitoring/opentelemetry-collector.nix b/nixos/modules/services/monitoring/opentelemetry-collector.nix
index 459cc85324902..d9b8c27ccdfe3 100644
--- a/nixos/modules/services/monitoring/opentelemetry-collector.nix
+++ b/nixos/modules/services/monitoring/opentelemetry-collector.nix
@@ -6,8 +6,9 @@ let
   cfg = config.services.opentelemetry-collector;
   opentelemetry-collector = cfg.package;
 
-  settingsFormat = pkgs.formats.yaml {};
-in {
+  settingsFormat = pkgs.formats.yaml { };
+in
+{
   options.services.opentelemetry-collector = {
     enable = mkEnableOption "Opentelemetry Collector";
 
@@ -15,7 +16,7 @@ in {
 
     settings = mkOption {
       type = settingsFormat.type;
-      default = {};
+      default = { };
       description = ''
         Specify the configuration for Opentelemetry Collector in Nix.
 
@@ -35,9 +36,9 @@ in {
   config = mkIf cfg.enable {
     assertions = [{
       assertion = (
-        (cfg.settings == {}) != (cfg.configFile == null)
+        (cfg.settings == { }) != (cfg.configFile == null)
       );
-      message  = ''
+      message = ''
         Please specify a configuration for Opentelemetry Collector with either
         'services.opentelemetry-collector.settings' or
         'services.opentelemetry-collector.configFile'.
@@ -48,21 +49,27 @@ in {
       description = "Opentelemetry Collector Service Daemon";
       wantedBy = [ "multi-user.target" ];
 
-      serviceConfig = let
-        conf = if cfg.configFile == null
-               then settingsFormat.generate "config.yaml" cfg.settings
-               else cfg.configFile;
-      in
-      {
-        ExecStart = "${getExe opentelemetry-collector} --config=file:${conf}";
-        DynamicUser = true;
-        Restart = "always";
-        ProtectSystem = "full";
-        DevicePolicy = "closed";
-        NoNewPrivileges = true;
-        WorkingDirectory = "/var/lib/opentelemetry-collector";
-        StateDirectory = "opentelemetry-collector";
-      };
+      serviceConfig =
+        let
+          conf =
+            if cfg.configFile == null
+            then settingsFormat.generate "config.yaml" cfg.settings
+            else cfg.configFile;
+        in
+        {
+          ExecStart = "${getExe opentelemetry-collector} --config=file:${conf}";
+          DynamicUser = true;
+          Restart = "always";
+          ProtectSystem = "full";
+          DevicePolicy = "closed";
+          NoNewPrivileges = true;
+          WorkingDirectory = "%S/opentelemetry-collector";
+          StateDirectory = "opentelemetry-collector";
+          SupplementaryGroups = [
+            # allow to read the systemd journal for opentelemetry-collector
+            "systemd-journal"
+          ];
+        };
     };
   };
 }
diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager-webhook-logger.nix b/nixos/modules/services/monitoring/prometheus/alertmanager-webhook-logger.nix
index b4307a76e1b02..b3665b66ba406 100644
--- a/nixos/modules/services/monitoring/prometheus/alertmanager-webhook-logger.nix
+++ b/nixos/modules/services/monitoring/prometheus/alertmanager-webhook-logger.nix
@@ -32,9 +32,15 @@ in
           ${escapeShellArgs cfg.extraFlags}
         '';
 
+        CapabilityBoundingSet = [ "" ];
+        DeviceAllow = [ "" ];
         DynamicUser = true;
         NoNewPrivileges = true;
 
+        MemoryDenyWriteExecute = true;
+
+        LockPersonality = true;
+
         ProtectProc = "invisible";
         ProtectSystem = "strict";
         ProtectHome = "tmpfs";
@@ -43,6 +49,8 @@ in
         PrivateDevices = true;
         PrivateIPC = true;
 
+        ProcSubset = "pid";
+
         ProtectHostname = true;
         ProtectClock = true;
         ProtectKernelTunables = true;
@@ -50,7 +58,10 @@ in
         ProtectKernelLogs = true;
         ProtectControlGroups = true;
 
+        Restart  = "on-failure";
+
         RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+        RestrictNamespaces = true;
         RestrictRealtime = true;
         RestrictSUIDSGID = true;
 
diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
index d1d8f2caaf63d..f40ac3c9138ff 100644
--- a/nixos/modules/services/monitoring/prometheus/alertmanager.nix
+++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
@@ -181,15 +181,57 @@ in {
                                                     -i "${alertmanagerYml}"
         '';
         serviceConfig = {
-          Restart  = "always";
-          StateDirectory = "alertmanager";
-          DynamicUser = true; # implies PrivateTmp
-          EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
-          WorkingDirectory = "/tmp";
           ExecStart = "${cfg.package}/bin/alertmanager" +
             optionalString (length cmdlineArgs != 0) (" \\\n  " +
               concatStringsSep " \\\n  " cmdlineArgs);
           ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+
+          EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
+
+          CapabilityBoundingSet = [ "" ];
+          DeviceAllow = [ "" ];
+          DynamicUser = true;
+          NoNewPrivileges = true;
+
+          MemoryDenyWriteExecute = true;
+
+          LockPersonality = true;
+
+          ProtectProc = "invisible";
+          ProtectSystem = "strict";
+          ProtectHome = "tmpfs";
+
+          PrivateTmp = true;
+          PrivateDevices = true;
+          PrivateIPC = true;
+
+          ProcSubset = "pid";
+
+          ProtectHostname = true;
+          ProtectClock = true;
+          ProtectKernelTunables = true;
+          ProtectKernelModules = true;
+          ProtectKernelLogs = true;
+          ProtectControlGroups = true;
+
+          Restart  = "always";
+
+          RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_NETLINK" ];
+          RestrictNamespaces = true;
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+
+          StateDirectory = "alertmanager";
+          SystemCallFilter = [
+            "@system-service"
+            "~@cpu-emulation"
+            "~@privileged"
+            "~@reboot"
+            "~@setuid"
+            "~@swap"
+          ];
+
+          WorkingDirectory = "/tmp";
         };
       };
     })
diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix
index dc357f6cc5fb3..0a9d4ef985227 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -29,6 +29,7 @@ let
     "blackbox"
     "buildkite-agent"
     "collectd"
+    "deluge"
     "dmarc"
     "dnsmasq"
     "dnssec"
@@ -408,6 +409,14 @@ in
         Please ensure you have either `services.prometheus.exporters.idrac.configuration'
           or `services.prometheus.exporters.idrac.configurationPath' set!
       '';
+    } {
+      assertion = cfg.deluge.enable -> (
+        (cfg.deluge.delugePassword == null) != (cfg.deluge.delugePasswordFile == null)
+      );
+      message = ''
+        Please ensure you have either `services.prometheus.exporters.deluge.delugePassword'
+          or `services.prometheus.exporters.deluge.delugePasswordFile' set!
+      '';
     } ] ++ (flip map (attrNames exporterOpts) (exporter: {
       assertion = cfg.${exporter}.firewallFilter != null -> cfg.${exporter}.openFirewall;
       message = ''
@@ -437,6 +446,13 @@ in
     hardware.rtl-sdr.enable = mkDefault true;
   })] ++ [(mkIf config.services.postfix.enable {
     services.prometheus.exporters.postfix.group = mkDefault config.services.postfix.setgidGroup;
+  })] ++ [(mkIf config.services.prometheus.exporters.deluge.enable {
+    system.activationScripts = {
+      deluge-exported.text = ''
+      mkdir -p /etc/deluge-exporter
+      echo "DELUGE_PASSWORD=$(cat ${config.services.prometheus.exporters.deluge.delugePasswordFile})" > /etc/deluge-exporter/password
+      '';
+    };
   })] ++ (mapAttrsToList (name: conf:
     mkExporterConf {
       inherit name;
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/deluge.nix b/nixos/modules/services/monitoring/prometheus/exporters/deluge.nix
new file mode 100644
index 0000000000000..5943b46eeb5fc
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/exporters/deluge.nix
@@ -0,0 +1,85 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.prometheus.exporters.deluge;
+  inherit (lib) mkOption types concatStringsSep;
+in
+{
+  port = 9354;
+
+  extraOpts = {
+    delugeHost = mkOption {
+      type = types.str;
+      default = "localhost";
+      description = ''
+        Hostname where deluge server is running.
+      '';
+    };
+
+    delugePort = mkOption {
+      type = types.port;
+      default = 58846;
+      description = ''
+        Port where deluge server is listening.
+      '';
+    };
+
+    delugeUser = mkOption {
+      type = types.str;
+      default = "localclient";
+      description = ''
+        User to connect to deluge server.
+      '';
+    };
+
+    delugePassword = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        Password to connect to deluge server.
+
+        This stores the password unencrypted in the nix store and is thus considered unsafe. Prefer
+        using the delugePasswordFile option.
+      '';
+    };
+
+    delugePasswordFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        File containing the password to connect to deluge server.
+      '';
+    };
+
+    exportPerTorrentMetrics = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable per-torrent metrics.
+
+        This may significantly increase the number of time series depending on the number of
+        torrents in your Deluge instance.
+      '';
+    };
+  };
+  serviceOpts = {
+    serviceConfig = {
+      ExecStart = ''
+        ${pkgs.prometheus-deluge-exporter}/bin/deluge-exporter
+      '';
+      Environment = [
+        "LISTEN_PORT=${toString cfg.port}"
+        "LISTEN_ADDRESS=${toString cfg.listenAddress}"
+
+        "DELUGE_HOST=${cfg.delugeHost}"
+        "DELUGE_USER=${cfg.delugeUser}"
+        "DELUGE_PORT=${toString cfg.delugePort}"
+      ] ++ lib.optionals (cfg.delugePassword != null) [
+        "DELUGE_PASSWORD=${cfg.delugePassword}"
+      ] ++ lib.optionals cfg.exportPerTorrentMetrics [
+        "PER_TORRENT_METRICS=1"
+      ];
+      EnvironmentFile = lib.optionalString (cfg.delugePasswordFile != null) "/etc/deluge-exporter/password";
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/fastly.nix b/nixos/modules/services/monitoring/prometheus/exporters/fastly.nix
index 097ea39594788..e470ebe2eb592 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/fastly.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/fastly.nix
@@ -1,17 +1,20 @@
-{ config
-, lib
-, pkgs
-, options
-, ...
+{
+  config,
+  lib,
+  pkgs,
+  utils,
+  ...
 }:
 
 let
   inherit (lib)
-    escapeShellArgs
+    getExe
     mkOption
     optionals
     types
-  ;
+    ;
+
+  inherit (utils) escapeSystemdExecArgs;
 
   cfg = config.services.prometheus.exporters.fastly;
 in
@@ -39,17 +42,19 @@ in
   serviceOpts = {
     serviceConfig = {
       LoadCredential = "fastly-api-token:${cfg.tokenPath}";
+      Environment = [ "FASTLY_API_TOKEN=%d/fastly-api-token" ];
+      ExecStart = escapeSystemdExecArgs (
+        [
+          (getExe pkgs.prometheus-fastly-exporter)
+          "-listen"
+          "${cfg.listenAddress}:${toString cfg.port}"
+        ]
+        ++ optionals (cfg.configFile != null) [
+          "--config-file"
+          cfg.configFile
+        ]
+        ++ cfg.extraFlags
+      );
     };
-    script = let
-      call = escapeShellArgs ([
-        "${pkgs.prometheus-fastly-exporter}/bin/fastly-exporter"
-        "-listen" "${cfg.listenAddress}:${toString cfg.port}"
-      ] ++ optionals (cfg.configFile != null) [
-        "--config-file" cfg.configFile
-      ] ++ cfg.extraFlags);
-    in ''
-      export FASTLY_API_TOKEN="$(cat $CREDENTIALS_DIRECTORY/fastly-api-token)"
-      ${call}
-    '';
   };
 }
diff --git a/nixos/modules/services/monitoring/prometheus/pushgateway.nix b/nixos/modules/services/monitoring/prometheus/pushgateway.nix
index 80e2339f59256..d4f9c4a29f386 100644
--- a/nixos/modules/services/monitoring/prometheus/pushgateway.nix
+++ b/nixos/modules/services/monitoring/prometheus/pushgateway.nix
@@ -147,12 +147,52 @@ in {
       wantedBy = [ "multi-user.target" ];
       after    = [ "network.target" ];
       serviceConfig = {
-        Restart  = "always";
-        DynamicUser = true;
         ExecStart = "${cfg.package}/bin/pushgateway" +
           optionalString (length cmdlineArgs != 0) (" \\\n  " +
             concatStringsSep " \\\n  " cmdlineArgs);
+
+        CapabilityBoundingSet = [ "" ];
+        DeviceAllow = [ "" ];
+        DynamicUser = true;
+        NoNewPrivileges = true;
+
+        MemoryDenyWriteExecute = true;
+
+        LockPersonality = true;
+
+        ProtectProc = "invisible";
+        ProtectSystem = "strict";
+        ProtectHome = "tmpfs";
+
+        PrivateTmp = true;
+        PrivateDevices = true;
+        PrivateIPC = true;
+
+        ProcSubset = "pid";
+
+        ProtectHostname = true;
+        ProtectClock = true;
+        ProtectKernelTunables = true;
+        ProtectKernelModules = true;
+        ProtectKernelLogs = true;
+        ProtectControlGroups = true;
+
+        Restart  = "always";
+
+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+
         StateDirectory = if cfg.persistMetrics then cfg.stateDir else null;
+        SystemCallFilter = [
+          "@system-service"
+          "~@cpu-emulation"
+          "~@privileged"
+          "~@reboot"
+          "~@setuid"
+          "~@swap"
+        ];
       };
     };
   };
diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix
index 2c05eaad25ace..6fd3b5707ab67 100644
--- a/nixos/modules/services/monitoring/smartd.nix
+++ b/nixos/modules/services/monitoring/smartd.nix
@@ -10,6 +10,7 @@ let
   opt = options.services.smartd;
 
   nm = cfg.notifications.mail;
+  ns = cfg.notifications.systembus-notify;
   nw = cfg.notifications.wall;
   nx = cfg.notifications.x11;
 
@@ -28,6 +29,12 @@ let
       ${pkgs.smartmontools}/sbin/smartctl -a -d "$SMARTD_DEVICETYPE" "$SMARTD_DEVICE"
       } | ${nm.mailer} -i "${nm.recipient}"
     ''}
+    ${optionalString ns.enable ''
+      ${pkgs.dbus}/bin/dbus-send --system \
+        / net.nuetzlich.SystemNotifications.Notify \
+        "string:Problem detected with disk: $SMARTD_DEVICESTRING" \
+        "string:Warning message from smartd is: $SMARTD_MESSAGE"
+    ''}
     ${optionalString nw.enable ''
       {
       ${pkgs.coreutils}/bin/cat << EOF
@@ -159,6 +166,24 @@ in
           };
         };
 
+        systembus-notify = {
+          enable = mkOption {
+            default = false;
+            type = types.bool;
+            description = ''
+              Whenever to send systembus-notify notifications.
+
+              WARNING: enabling this option (while convenient) should *not* be done on a
+              machine where you do not trust the other users as it allows any other
+              local user to DoS your session by spamming notifications.
+
+              To actually see the notifications in your GUI session, you need to have
+              `systembus-notify` running as your user, which this
+              option handles by enabling {option}`services.systembus-notify`.
+            '';
+          };
+        };
+
         wall = {
           enable = mkOption {
             default = true;
@@ -247,6 +272,8 @@ in
       serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd ${lib.concatStringsSep " " cfg.extraOptions} --no-fork --configfile=${smartdConf}";
     };
 
+    services.systembus-notify.enable = mkDefault ns.enable;
+
   };
 
 }
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index c70d0cf7beac3..a887f964ca428 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -55,6 +55,7 @@ let
         PIDFile = "/run/${appName}.pid";
         Type = "notify";
         NotifyAccess = "all"; #may not do anything...
+        Slice = "system-samba.slice";
       };
       unitConfig.RequiresMountsFor = "/var/lib/samba";
 
@@ -216,6 +217,11 @@ in
             wants = [ "network-online.target" ];
             wantedBy = [ "multi-user.target" ];
           };
+
+          slices.system-samba = {
+            description = "Samba slice";
+          };
+
           # Refer to https://github.com/samba-team/samba/tree/master/packaging/systemd
           # for correct use with systemd
           services = {
diff --git a/nixos/modules/services/networking/bee.nix b/nixos/modules/services/networking/bee.nix
index da11ac9399abd..72483c41d02d1 100644
--- a/nixos/modules/services/networking/bee.nix
+++ b/nixos/modules/services/networking/bee.nix
@@ -101,8 +101,7 @@ in {
 
       preStart = with cfg.settings; ''
         if ! test -f ${password-file}; then
-          < /dev/urandom tr -dc _A-Z-a-z-0-9 2> /dev/null | head -c32 > ${password-file}
-          chmod 0600 ${password-file}
+          < /dev/urandom tr -dc _A-Z-a-z-0-9 2> /dev/null | head -c32 | install -m 600 /dev/stdin ${password-file}
           echo "Initialized ${password-file} from /dev/urandom"
         fi
         if [ ! -f ${data-dir}/keys/libp2p.key ]; then
diff --git a/nixos/modules/services/networking/blocky.nix b/nixos/modules/services/networking/blocky.nix
index b98c8b7bdb730..4bc6ffa3f46ab 100644
--- a/nixos/modules/services/networking/blocky.nix
+++ b/nixos/modules/services/networking/blocky.nix
@@ -12,6 +12,8 @@ in
   options.services.blocky = {
     enable = mkEnableOption "blocky, a fast and lightweight DNS proxy as ad-blocker for local network with many features";
 
+    package = mkPackageOption pkgs "blocky" { };
+
     settings = mkOption {
       type = format.type;
       default = { };
@@ -30,7 +32,7 @@ in
 
       serviceConfig = {
         DynamicUser = true;
-        ExecStart = "${pkgs.blocky}/bin/blocky --config ${configFile}";
+        ExecStart = "${getExe cfg.package} --config ${configFile}";
         Restart = "on-failure";
 
         AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
diff --git a/nixos/modules/services/networking/cgit.nix b/nixos/modules/services/networking/cgit.nix
index 0ccbef756812e..de8128ed5a59c 100644
--- a/nixos/modules/services/networking/cgit.nix
+++ b/nixos/modules/services/networking/cgit.nix
@@ -25,14 +25,14 @@ let
 
   regexLocation = cfg: regexEscape (stripLocation cfg);
 
-  mkFastcgiPass = cfg: ''
+  mkFastcgiPass = name: cfg: ''
     ${if cfg.nginx.location == "/" then ''
       fastcgi_param PATH_INFO $uri;
     '' else ''
       fastcgi_split_path_info ^(${regexLocation cfg})(/.+)$;
       fastcgi_param PATH_INFO $fastcgi_path_info;
     ''
-    }fastcgi_pass unix:${config.services.fcgiwrap.socketAddress};
+    }fastcgi_pass unix:${config.services.fcgiwrap."cgit-${name}".socket.address};
   '';
 
   cgitrcLine = name: value: "${name}=${
@@ -72,25 +72,11 @@ let
     ${cfg.extraConfig}
   '';
 
-  mkCgitReposDir = cfg:
-    if cfg.scanPath != null then
-      cfg.scanPath
-    else
-      pkgs.runCommand "cgit-repos" {
-        preferLocalBuild = true;
-        allowSubstitutes = false;
-      } ''
-        mkdir -p "$out"
-        ${
-          concatStrings (
-            mapAttrsToList
-              (name: value: ''
-                ln -s ${escapeShellArg value.path} "$out"/${escapeShellArg name}
-              '')
-              cfg.repos
-          )
-        }
-      '';
+  fcgiwrapUnitName = name: "fcgiwrap-cgit-${name}";
+  fcgiwrapRuntimeDir = name: "/run/${fcgiwrapUnitName name}";
+  gitProjectRoot = name: cfg: if cfg.scanPath != null
+    then cfg.scanPath
+    else "${fcgiwrapRuntimeDir name}/repos";
 
 in
 {
@@ -154,6 +140,18 @@ in
             type = types.lines;
             default = "";
           };
+
+          user = mkOption {
+            description = "User to run the cgit service as.";
+            type = types.str;
+            default = "cgit";
+          };
+
+          group = mkOption {
+            description = "Group to run the cgit service as.";
+            type = types.str;
+            default = "cgit";
+          };
         };
       }));
     };
@@ -165,18 +163,46 @@ in
       message = "Exactly one of services.cgit.${vhost}.scanPath or services.cgit.${vhost}.repos must be set.";
     }) cfgs;
 
-    services.fcgiwrap.enable = true;
+    users = mkMerge (flip mapAttrsToList cfgs (_: cfg: {
+      users.${cfg.user} = {
+        isSystemUser = true;
+        inherit (cfg) group;
+      };
+      groups.${cfg.group} = { };
+    }));
+
+    services.fcgiwrap = flip mapAttrs' cfgs (name: cfg:
+      nameValuePair "cgit-${name}" {
+        process = { inherit (cfg) user group; };
+        socket = { inherit (config.services.nginx) user group; };
+      }
+    );
+
+    systemd.services = flip mapAttrs' cfgs (name: cfg:
+      nameValuePair (fcgiwrapUnitName name)
+      (mkIf (cfg.repos != { }) {
+        serviceConfig.RuntimeDirectory = fcgiwrapUnitName name;
+        preStart = ''
+          GIT_PROJECT_ROOT=${escapeShellArg (gitProjectRoot name cfg)}
+          mkdir -p "$GIT_PROJECT_ROOT"
+          cd "$GIT_PROJECT_ROOT"
+          ${concatLines (flip mapAttrsToList cfg.repos (name: repo: ''
+            ln -s ${escapeShellArg repo.path} ${escapeShellArg name}
+          ''))}
+        '';
+      }
+    ));
 
     services.nginx.enable = true;
 
-    services.nginx.virtualHosts = mkMerge (mapAttrsToList (_: cfg: {
+    services.nginx.virtualHosts = mkMerge (mapAttrsToList (name: cfg: {
       ${cfg.nginx.virtualHost} = {
         locations = (
           genAttrs'
             [ "cgit.css" "cgit.png" "favicon.ico" "robots.txt" ]
-            (name: nameValuePair "= ${stripLocation cfg}/${name}" {
+            (fileName: nameValuePair "= ${stripLocation cfg}/${fileName}" {
               extraConfig = ''
-                alias ${cfg.package}/cgit/${name};
+                alias ${cfg.package}/cgit/${fileName};
               '';
             })
         ) // {
@@ -184,10 +210,10 @@ in
             fastcgiParams = rec {
               SCRIPT_FILENAME = "${pkgs.git}/libexec/git-core/git-http-backend";
               GIT_HTTP_EXPORT_ALL = "1";
-              GIT_PROJECT_ROOT = mkCgitReposDir cfg;
+              GIT_PROJECT_ROOT = gitProjectRoot name cfg;
               HOME = GIT_PROJECT_ROOT;
             };
-            extraConfig = mkFastcgiPass cfg;
+            extraConfig = mkFastcgiPass name cfg;
           };
           "${stripLocation cfg}/" = {
             fastcgiParams = {
@@ -196,7 +222,7 @@ in
               HTTP_HOST = "$server_name";
               CGIT_CONFIG = mkCgitrc cfg;
             };
-            extraConfig = mkFastcgiPass cfg;
+            extraConfig = mkFastcgiPass name cfg;
           };
         };
       };
diff --git a/nixos/modules/services/networking/cloudflare-dyndns.nix b/nixos/modules/services/networking/cloudflare-dyndns.nix
index ab5b1a08539a5..a15de2ddd861b 100644
--- a/nixos/modules/services/networking/cloudflare-dyndns.nix
+++ b/nixos/modules/services/networking/cloudflare-dyndns.nix
@@ -28,6 +28,16 @@ in
         '';
       };
 
+      frequency = mkOption {
+        type = types.nullOr types.str;
+        default = "*:0/5";
+        description = ''
+          Run cloudflare-dyndns with the given frequency (see
+          {manpage}`systemd.time(7)` for the format).
+          If null, do not run automatically.
+        '';
+      };
+
       proxied = mkOption {
         type = types.bool;
         default = false;
@@ -67,7 +77,6 @@ in
       description = "CloudFlare Dynamic DNS Client";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      startAt = "*:0/5";
 
       environment = {
         CLOUDFLARE_DOMAINS = toString cfg.domains;
@@ -88,6 +97,8 @@ in
           in
           "${pkgs.cloudflare-dyndns}/bin/cloudflare-dyndns ${toString args}";
       };
+    } // optionalAttrs (cfg.frequency != null) {
+      startAt = cfg.frequency;
     };
   };
 }
diff --git a/nixos/modules/services/networking/cloudflare-warp.nix b/nixos/modules/services/networking/cloudflare-warp.nix
new file mode 100644
index 0000000000000..2ab5f287ac496
--- /dev/null
+++ b/nixos/modules/services/networking/cloudflare-warp.nix
@@ -0,0 +1,91 @@
+{ config, lib, pkgs, ... }:
+let
+  cfg = config.services.cloudflare-warp;
+in
+{
+  options.services.cloudflare-warp = {
+    enable = lib.mkEnableOption "Cloudflare Zero Trust client daemon";
+
+    package = lib.mkPackageOption pkgs "cloudflare-warp" { };
+
+    rootDir = lib.mkOption {
+      type = lib.types.str;
+      default = "/var/lib/cloudflare-warp";
+      description = ''
+        Working directory for the warp-svc daemon.
+      '';
+    };
+
+    udpPort = lib.mkOption {
+      type = lib.types.port;
+      default = 2408;
+      description = ''
+        The UDP port to open in the firewall. Warp uses port 2408 by default, but fallback ports can be used
+        if that conflicts with another service. See the [firewall documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/deployment/firewall#warp-udp-ports)
+        for the pre-configured available fallback ports.
+      '';
+    };
+
+    openFirewall = lib.mkEnableOption "opening UDP ports in the firewall" // {
+      default = true;
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    environment.systemPackages = [ cfg.package ];
+
+    networking.firewall = lib.mkIf cfg.openFirewall {
+      allowedUDPPorts = [ cfg.udpPort ];
+    };
+
+    systemd.tmpfiles.rules = [
+      "d ${cfg.rootDir}    - root root"
+      "z ${cfg.rootDir}    - root root"
+    ];
+
+    systemd.services.cloudflare-warp = {
+      enable = true;
+      description = "Cloudflare Zero Trust Client Daemon";
+
+      # lsof is used by the service to determine which UDP port to bind to
+      # in the case that it detects collisions.
+      path = [ pkgs.lsof ];
+      requires = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig =
+        let
+          caps = [
+            "CAP_NET_ADMIN"
+            "CAP_NET_BIND_SERVICE"
+            "CAP_SYS_PTRACE"
+          ];
+        in
+        {
+          Type = "simple";
+          ExecStart = "${cfg.package}/bin/warp-svc";
+          ReadWritePaths = [ "${cfg.rootDir}" "/etc/resolv.conf" ];
+          CapabilityBoundingSet = caps;
+          AmbientCapabilities = caps;
+          Restart = "always";
+          RestartSec = 5;
+          Environment = [ "RUST_BACKTRACE=full" ];
+          WorkingDirectory = cfg.rootDir;
+
+          # See the systemd.exec docs for the canonicalized paths, the service
+          # makes use of them for logging, and account state info tracking.
+          # https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#RuntimeDirectory=
+          StateDirectory = "cloudflare-warp";
+          RuntimeDirectory = "cloudflare-warp";
+          LogsDirectory = "cloudflare-warp";
+
+          # The service needs to write to /etc/resolv.conf to configure DNS, so that file would have to
+          # be world read/writable to run as anything other than root.
+          User = "root";
+          Group = "root";
+        };
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ treyfortmuller ];
+}
diff --git a/nixos/modules/services/networking/cloudflared.nix b/nixos/modules/services/networking/cloudflared.nix
index 60f6b7c466892..c0d1012ffb80d 100644
--- a/nixos/modules/services/networking/cloudflared.nix
+++ b/nixos/modules/services/networking/cloudflared.nix
@@ -131,7 +131,7 @@ let
         `cloudflared` starts a proxy server to translate HTTP traffic into TCP when proxying, for example, SSH or RDP. This configures what type of proxy will be started. Valid options are:
 
         - `""` for the regular proxy
-        - `"socks"` for a SOCKS5 proxy. Refer to the [https://developers.cloudflare.com/cloudflare-one/tutorials/kubectl/](tutorial on connecting through Cloudflare Access using kubectl) for more information.
+        - `"socks"` for a SOCKS5 proxy. Refer to the [tutorial on connecting through Cloudflare Access using kubectl](https://developers.cloudflare.com/cloudflare-one/tutorials/kubectl/) for more information.
       '';
     };
   };
@@ -167,7 +167,7 @@ in
             description = ''
               Credential file.
 
-              See [https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-useful-terms/#credentials-file](Credentials file).
+              See [Credentials file](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-useful-terms/#credentials-file).
             '';
           };
 
@@ -178,7 +178,7 @@ in
               description = ''
                 Enable warp routing.
 
-                See [https://developers.cloudflare.com/cloudflare-one/tutorials/warp-to-tunnel/](Connect from WARP to a private network on Cloudflare using Cloudflare Tunnel).
+                See [Connect from WARP to a private network on Cloudflare using Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/tutorials/warp-to-tunnel/).
               '';
             };
           };
@@ -204,7 +204,7 @@ in
                   description = ''
                     Service to pass the traffic.
 
-                    See [https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configuration/local-management/ingress/#supported-protocols](Supported protocols).
+                    See [Supported protocols](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configuration/local-management/ingress/#supported-protocols).
                   '';
                   example = "http://localhost:80, tcp://localhost:8000, unix:/home/production/echo.sock, hello_world or http_status:404";
                 };
@@ -226,7 +226,7 @@ in
             description = ''
               Ingress rules.
 
-              See [https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configuration/local-management/ingress/](Ingress rules).
+              See [Ingress rules](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configuration/local-management/ingress/).
             '';
             example = {
               "*.domain.com" = "http://localhost:80";
diff --git a/nixos/modules/services/networking/deconz.nix b/nixos/modules/services/networking/deconz.nix
index 88b0ee612d871..e023f8e866c0d 100644
--- a/nixos/modules/services/networking/deconz.nix
+++ b/nixos/modules/services/networking/deconz.nix
@@ -122,6 +122,7 @@ in
         RuntimeDirectory = name;
         RuntimeDirectoryMode = "0700";
         StateDirectory = name;
+        SuccessExitStatus = [ 143 ];
         WorkingDirectory = stateDir;
         # For access to /dev/ttyACM0 (ConBee).
         SupplementaryGroups = [ "dialout" ];
diff --git a/nixos/modules/services/networking/firefox-syncserver.nix b/nixos/modules/services/networking/firefox-syncserver.nix
index a9fcd883beb07..674a424fb0a42 100644
--- a/nixos/modules/services/networking/firefox-syncserver.nix
+++ b/nixos/modules/services/networking/firefox-syncserver.nix
@@ -316,7 +316,7 @@ in
   };
 
   meta = {
-    maintainers = with lib.maintainers; [ pennae ];
+    maintainers = with lib.maintainers; [ ];
     doc = ./firefox-syncserver.md;
   };
 }
diff --git a/nixos/modules/services/networking/magic-wormhole-mailbox-server.nix b/nixos/modules/services/networking/magic-wormhole-mailbox-server.nix
index 03210bca371cf..5b700269037c2 100644
--- a/nixos/modules/services/networking/magic-wormhole-mailbox-server.nix
+++ b/nixos/modules/services/networking/magic-wormhole-mailbox-server.nix
@@ -1,18 +1,27 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
 
 let
   cfg = config.services.magic-wormhole-mailbox-server;
+  # keep semicolon in dataDir for backward compatibility
   dataDir = "/var/lib/magic-wormhole-mailbox-server;";
-  python = pkgs.python3.withPackages (py: [ py.magic-wormhole-mailbox-server py.twisted ]);
+  python = pkgs.python311.withPackages (
+    py: with py; [
+      magic-wormhole-mailbox-server
+      twisted
+    ]
+  );
 in
 {
   options.services.magic-wormhole-mailbox-server = {
-    enable = mkEnableOption "Magic Wormhole Mailbox Server";
+    enable = lib.mkEnableOption "Magic Wormhole Mailbox Server";
   };
 
-  config = mkIf cfg.enable {
+  config = lib.mkIf cfg.enable {
     systemd.services.magic-wormhole-mailbox-server = {
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
@@ -23,6 +32,7 @@ in
         StateDirectory = baseNameOf dataDir;
       };
     };
-
   };
+
+  meta.maintainers = [ lib.maintainers.mjoerg ];
 }
diff --git a/nixos/modules/services/networking/mihomo.nix b/nixos/modules/services/networking/mihomo.nix
index d4bb10496279d..a425952b54ced 100644
--- a/nixos/modules/services/networking/mihomo.nix
+++ b/nixos/modules/services/networking/mihomo.nix
@@ -2,10 +2,11 @@
 # cfg.configFile contains secrets such as proxy servers' credential!
 # we dont want plaintext secrets in world-readable `/nix/store`.
 
-{ lib
-, config
-, pkgs
-, ...
+{
+  lib,
+  config,
+  pkgs,
+  ...
 }:
 let
   cfg = config.services.mihomo;
@@ -17,7 +18,6 @@ in
     package = lib.mkPackageOption pkgs "mihomo" { };
 
     configFile = lib.mkOption {
-      default = null;
       type = lib.types.nullOr lib.types.path;
       description = "Configuration file to use.";
     };
@@ -67,7 +67,7 @@ in
           ExecStart = lib.concatStringsSep " " [
             (lib.getExe cfg.package)
             "-d /var/lib/private/mihomo"
-            (lib.optionalString (cfg.configFile != null) "-f \${CREDENTIALS_DIRECTORY}/config.yaml")
+            "-f \${CREDENTIALS_DIRECTORY}/config.yaml"
             (lib.optionalString (cfg.webui != null) "-ext-ui ${cfg.webui}")
             (lib.optionalString (cfg.extraOpts != null) cfg.extraOpts)
           ];
diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix
index 9825af47777e5..7baaf93a1bcfa 100644
--- a/nixos/modules/services/networking/mosquitto.nix
+++ b/nixos/modules/services/networking/mosquitto.nix
@@ -721,7 +721,7 @@ in
   };
 
   meta = {
-    maintainers = with lib.maintainers; [ pennae ];
+    maintainers = with lib.maintainers; [ ];
     doc = ./mosquitto.md;
   };
 }
diff --git a/nixos/modules/services/networking/nebula.nix b/nixos/modules/services/networking/nebula.nix
index 56eed04c3e8d9..d69af8d16b52c 100644
--- a/nixos/modules/services/networking/nebula.nix
+++ b/nixos/modules/services/networking/nebula.nix
@@ -51,8 +51,8 @@ in
             };
 
             key = mkOption {
-              type = types.path;
-              description = "Path to the host key.";
+              type = types.oneOf [types.nonEmptyStr types.path];
+              description = "Path or reference to the host key.";
               example = "/etc/nebula/host.key";
             };
 
@@ -241,7 +241,7 @@ in
               ProtectKernelModules = true;
               ProtectKernelTunables = true;
               ProtectProc = "invisible";
-              ProtectSystem = "strict";
+              ProtectSystem = true;
               RestrictNamespaces = true;
               RestrictSUIDSGID = true;
               User = networkId;
@@ -269,4 +269,6 @@ in
       ${nameToId netName} = {};
     }) enabledNetworks);
   };
+
+  meta.maintainers = [ numinit ];
 }
diff --git a/nixos/modules/services/networking/networkd-dispatcher.nix b/nixos/modules/services/networking/networkd-dispatcher.nix
index 427835870e59f..cced406934c1a 100644
--- a/nixos/modules/services/networking/networkd-dispatcher.nix
+++ b/nixos/modules/services/networking/networkd-dispatcher.nix
@@ -13,7 +13,7 @@ in {
 
       enable = mkEnableOption ''
         Networkd-dispatcher service for systemd-networkd connection status
-        change. See [https://gitlab.com/craftyguy/networkd-dispatcher](upstream instructions)
+        change. See [upstream instructions](https://gitlab.com/craftyguy/networkd-dispatcher)
         for usage
       '';
 
@@ -35,7 +35,7 @@ in {
         '';
         description = ''
           Declarative configuration of networkd-dispatcher rules. See
-          [https://gitlab.com/craftyguy/networkd-dispatcher](upstream instructions)
+          [upstream instructions](https://gitlab.com/craftyguy/networkd-dispatcher)
           for an introduction and example scripts.
         '';
         type = types.attrsOf (types.submodule {
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index b7143cf520f96..fda8245ba97d1 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -127,7 +127,7 @@ in
 {
 
   meta = {
-    maintainers = teams.freedesktop.members ++ [ lib.maintainers.janik ];
+    maintainers = teams.freedesktop.members;
   };
 
   ###### interface
diff --git a/nixos/modules/services/networking/oink.nix b/nixos/modules/services/networking/oink.nix
index cd0fdf172331d..3497ca9220a80 100644
--- a/nixos/modules/services/networking/oink.nix
+++ b/nixos/modules/services/networking/oink.nix
@@ -77,6 +77,7 @@ in
   config = mkIf cfg.enable {
     systemd.services.oink = {
       description = "Dynamic DNS client for Porkbun";
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       script = "${cfg.package}/bin/oink -c ${oinkConfig}";
     };
diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix
index 0de07a9b870c6..9e54dfc17dfe7 100644
--- a/nixos/modules/services/networking/prosody.nix
+++ b/nixos/modules/services/networking/prosody.nix
@@ -266,6 +266,13 @@ let
     else if builtins.isList x then "{ ${lib.concatMapStringsSep ", " toLua x} }"
     else throw "Invalid Lua value";
 
+  settingsToLua = prefix: settings: generators.toKeyValue {
+    listsAsDuplicateKeys = false;
+    mkKeyValue = k: generators.mkKeyValueDefault {
+      mkValueString = toLua;
+    } " = " (prefix + k);
+  } (filterAttrs (k: v: v != null) settings);
+
   createSSLOptsStr = o: ''
     ssl = {
       cafile = "/etc/ssl/certs/ca-bundle.crt";
@@ -418,15 +425,26 @@ let
       httpUploadPath = mkOption {
         type = types.str;
         description = ''
-          Directory where the uploaded files will be stored. By
-          default, uploaded files are put in a sub-directory of the
-          default Prosody storage path (usually /var/lib/prosody).
+          Directory where the uploaded files will be stored when the http_upload module is used.
+          By default, uploaded files are put in a sub-directory of the default Prosody storage path (usually /var/lib/prosody).
         '';
         default = "/var/lib/prosody";
       };
     };
   };
 
+  httpFileShareOpts = { ... }: {
+    freeformType = with types;
+      let atom = oneOf [ int bool str (listOf atom) ]; in
+      attrsOf (nullOr atom) // {
+        description = "int, bool, string or list of them";
+      };
+    options.domain = mkOption {
+      type = with types; nullOr str;
+      description = "Domain name for a http_file_share service.";
+    };
+  };
+
   vHostOpts = { ... }: {
 
     options = {
@@ -650,7 +668,7 @@ in
 
       uploadHttp = mkOption {
         description = ''
-          Configures the Prosody builtin HTTP server to handle user uploads.
+          Configures the old Prosody builtin HTTP server to handle user uploads.
         '';
         type = types.nullOr (types.submodule uploadHttpOpts);
         default = null;
@@ -659,6 +677,17 @@ in
         };
       };
 
+      httpFileShare = mkOption {
+        description = ''
+          Configures the http_file_share module to handle user uploads.
+        '';
+        type = types.nullOr (types.submodule httpFileShareOpts);
+        default = null;
+        example = {
+          domain = "uploads.my-xmpp-example-host.org";
+        };
+      };
+
       muc = mkOption {
         type = types.listOf (types.submodule mucOpts);
         default = [ ];
@@ -716,6 +745,17 @@ in
         description = "Additional prosody configuration";
       };
 
+      log = mkOption {
+        type = types.lines;
+        default = ''"*syslog"'';
+        description = "Logging configuration. See [](https://prosody.im/doc/logging) for more details";
+        example = ''
+          {
+            { min = "warn"; to = "*syslog"; };
+          }
+        '';
+      };
+
     };
   };
 
@@ -740,11 +780,10 @@ in
             You need to setup at least a MUC domain to comply with
             XEP-0423.
           '' + genericErrMsg;}
-        { assertion = cfg.uploadHttp != null || !cfg.xmppComplianceSuite;
+        { assertion = cfg.uploadHttp != null || cfg.httpFileShare != null || !cfg.xmppComplianceSuite;
           message = ''
-            You need to setup the uploadHttp module through
-            config.services.prosody.uploadHttp to comply with
-            XEP-0423.
+            You need to setup the http_upload or http_file_share modules through config.services.prosody.uploadHttp
+            or config.services.prosody.httpFileShare to comply with XEP-0423.
           '' + genericErrMsg;}
       ];
     in errors;
@@ -753,8 +792,11 @@ in
 
     environment.etc."prosody/prosody.cfg.lua".text =
       let
-        httpDiscoItems = optionals (cfg.uploadHttp != null)
-            [{ url = cfg.uploadHttp.domain; description = "HTTP upload endpoint";}];
+        httpDiscoItems = optional (cfg.uploadHttp != null) {
+          url = cfg.uploadHttp.domain; description = "HTTP upload endpoint";
+        } ++ optional (cfg.httpFileShare != null) {
+          url = cfg.httpFileShare.domain; description = "HTTP file share endpoint";
+        };
         mucDiscoItems = builtins.foldl'
             (acc: muc: [{ url = muc.domain; description = "${muc.domain} MUC endpoint";}] ++ acc)
             []
@@ -764,7 +806,7 @@ in
 
       pidfile = "/run/prosody/prosody.pid"
 
-      log = "*syslog"
+      log = ${cfg.log}
 
       data_path = "${cfg.dataDir}"
       plugin_paths = {
@@ -833,7 +875,6 @@ in
         '') cfg.muc}
 
       ${ lib.optionalString (cfg.uploadHttp != null) ''
-        -- TODO: think about migrating this to mod-http_file_share instead.
         Component ${toLua cfg.uploadHttp.domain} "http_upload"
             http_upload_file_size_limit = ${cfg.uploadHttp.uploadFileSizeLimit}
             http_upload_expire_after = ${cfg.uploadHttp.uploadExpireAfter}
@@ -841,6 +882,11 @@ in
             http_upload_path = ${toLua cfg.uploadHttp.httpUploadPath}
       ''}
 
+      ${lib.optionalString (cfg.httpFileShare != null) ''
+        Component ${toLua cfg.httpFileShare.domain} "http_file_share"
+        ${settingsToLua "  http_file_share_" (cfg.httpFileShare // { domain = null; })}
+      ''}
+
       ${ lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
         VirtualHost "${v.domain}"
           enabled = ${boolToString v.enabled};
diff --git a/nixos/modules/services/networking/realm.nix b/nixos/modules/services/networking/realm.nix
new file mode 100644
index 0000000000000..5b0c34ac825ff
--- /dev/null
+++ b/nixos/modules/services/networking/realm.nix
@@ -0,0 +1,50 @@
+{ config
+, lib
+, pkgs
+, ...
+}:
+let
+  cfg = config.services.realm;
+  configFormat = pkgs.formats.json { };
+  configFile = configFormat.generate "config.json" cfg.config;
+  inherit (lib)
+    mkEnableOption mkPackageOption mkOption mkIf types getExe;
+in
+{
+
+  meta.maintainers = with lib.maintainers; [ ocfox ];
+
+  options = {
+    services.realm = {
+      enable = mkEnableOption "A simple, high performance relay server written in rust";
+      package = mkPackageOption pkgs "realm" { };
+      config = mkOption {
+        type = types.submodule {
+          freeformType = configFormat.type;
+        };
+        default = { };
+        description = ''
+          The realm configuration, see <https://github.com/zhboner/realm#overview> for documentation.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.realm = {
+      serviceConfig = {
+        DynamicUser = true;
+        MemoryDenyWriteExecute = true;
+        PrivateDevices = true;
+        ProtectClock = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectProc = "invisible";
+        ProtectKernelTunables = true;
+        ExecStart = "${getExe cfg.package} --config ${configFile}";
+        AmbientCapabilities = [ "CAP_NET_ADMIN" "CAP_NET_BIND_SERVICE" ];
+      };
+      wantedBy = [ "multi-user.target" ];
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/resilio.nix b/nixos/modules/services/networking/resilio.nix
index 395796d39db8e..c788069fbaa55 100644
--- a/nixos/modules/services/networking/resilio.nix
+++ b/nixos/modules/services/networking/resilio.nix
@@ -291,5 +291,5 @@ in
     };
   };
 
-  meta.maintainers = with maintainers; [ jwoudenberg ];
+  meta.maintainers = with maintainers; [ ];
 }
diff --git a/nixos/modules/services/networking/scion/scion-control.nix b/nixos/modules/services/networking/scion/scion-control.nix
index 95d78a87ac859..0cc190d619b6f 100644
--- a/nixos/modules/services/networking/scion/scion-control.nix
+++ b/nixos/modules/services/networking/scion/scion-control.nix
@@ -3,8 +3,10 @@
 with lib;
 
 let
+  globalCfg = config.services.scion;
   cfg = config.services.scion.scion-control;
   toml = pkgs.formats.toml { };
+  connectionDir = if globalCfg.stateless then "/run" else "/var/lib";
   defaultConfig = {
     general = {
       id = "cs";
@@ -12,13 +14,13 @@ let
       reconnect_to_dispatcher = true;
     };
     beacon_db = {
-      connection = "/run/scion-control/control.beacon.db";
+      connection = "${connectionDir}/scion-control/control.beacon.db";
     };
     path_db = {
-      connection = "/run/scion-control/control.path.db";
+      connection = "${connectionDir}/scion-control/control.path.db";
     };
     trust_db = {
-      connection = "/run/scion-control/control.trust.db";
+      connection = "${connectionDir}/scion-control/control.trust.db";
     };
     log.console = {
       level = "info";
@@ -62,7 +64,7 @@ in
         DynamicUser = true;
         Restart = "on-failure";
         BindPaths = [ "/dev/shm:/run/shm" ];
-        RuntimeDirectory = "scion-control";
+        ${if globalCfg.stateless then "RuntimeDirectory" else "StateDirectory"} = "scion-control";
       };
     };
   };
diff --git a/nixos/modules/services/networking/scion/scion-daemon.nix b/nixos/modules/services/networking/scion/scion-daemon.nix
index 8528bec1d52eb..6ee2a4b505f26 100644
--- a/nixos/modules/services/networking/scion/scion-daemon.nix
+++ b/nixos/modules/services/networking/scion/scion-daemon.nix
@@ -3,8 +3,10 @@
 with lib;
 
 let
+  globalCfg = config.services.scion;
   cfg = config.services.scion.scion-daemon;
   toml = pkgs.formats.toml { };
+  connectionDir = if globalCfg.stateless then "/run" else "/var/lib";
   defaultConfig = {
     general = {
       id = "sd";
@@ -12,10 +14,10 @@ let
       reconnect_to_dispatcher = true;
     };
     path_db = {
-      connection = "/run/scion-daemon/sd.path.db";
+      connection = "${connectionDir}/scion-daemon/sd.path.db";
     };
     trust_db = {
-      connection = "/run/scion-daemon/sd.trust.db";
+      connection = "${connectionDir}/scion-daemon/sd.trust.db";
     };
     log.console = {
       level = "info";
@@ -57,7 +59,7 @@ in
         ExecStart = "${pkgs.scion}/bin/scion-daemon --config ${configFile}";
         Restart = "on-failure";
         DynamicUser = true;
-        RuntimeDirectory = "scion-daemon";
+        ${if globalCfg.stateless then "RuntimeDirectory" else "StateDirectory"} = "scion-daemon";
       };
     };
   };
diff --git a/nixos/modules/services/networking/scion/scion-dispatcher.nix b/nixos/modules/services/networking/scion/scion-dispatcher.nix
index 7c9f5e6a385ee..1f4193fae79e5 100644
--- a/nixos/modules/services/networking/scion/scion-dispatcher.nix
+++ b/nixos/modules/services/networking/scion/scion-dispatcher.nix
@@ -3,6 +3,7 @@
 with lib;
 
 let
+  globalCfg = config.services.scion;
   cfg = config.services.scion.scion-dispatcher;
   toml = pkgs.formats.toml { };
   defaultConfig = {
@@ -66,7 +67,7 @@ in
         ExecStartPre = "${pkgs.coreutils}/bin/rm -rf /run/shm/dispatcher";
         ExecStart = "${pkgs.scion}/bin/scion-dispatcher --config ${configFile}";
         Restart = "on-failure";
-        RuntimeDirectory = "scion-dispatcher";
+        ${if globalCfg.stateless then "RuntimeDirectory" else "StateDirectory"} = "scion-dispatcher";
       };
     };
   };
diff --git a/nixos/modules/services/networking/scion/scion-router.nix b/nixos/modules/services/networking/scion/scion-router.nix
index 2cac44ab767ef..47ff320b6a8ff 100644
--- a/nixos/modules/services/networking/scion/scion-router.nix
+++ b/nixos/modules/services/networking/scion/scion-router.nix
@@ -3,6 +3,7 @@
 with lib;
 
 let
+  globalCfg = config.services.scion;
   cfg = config.services.scion.scion-router;
   toml = pkgs.formats.toml { };
   defaultConfig = {
@@ -42,7 +43,7 @@ in
         ExecStart = "${pkgs.scion}/bin/scion-router --config ${configFile}";
         Restart = "on-failure";
         DynamicUser = true;
-        RuntimeDirectory = "scion-router";
+        ${if globalCfg.stateless then "RuntimeDirectory" else "StateDirectory"} = "scion-router";
       };
     };
   };
diff --git a/nixos/modules/services/networking/scion/scion.nix b/nixos/modules/services/networking/scion/scion.nix
index b8bfef8b93b58..0ae959484d326 100644
--- a/nixos/modules/services/networking/scion/scion.nix
+++ b/nixos/modules/services/networking/scion/scion.nix
@@ -8,6 +8,22 @@ in
 {
   options.services.scion = {
     enable = mkEnableOption "all of the scion components and services";
+    stateless = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Setting this value to false (stateful) can lead to improved caching and
+        performance.
+
+        This option decides whether to persist the SCION path sqlite databases
+        on disk or not. Persisting this data can lead to database corruption in
+        extreme cases such as power outage, meaning SCION fails to work on the
+        next boot. This is being investigated.
+
+        If true, /run/scion-* is used for data
+        If false, use /var/lib/scion-* is used for data
+      '';
+    };
     bypassBootstrapWarning = mkOption {
       type = types.bool;
       default = false;
diff --git a/nixos/modules/services/networking/smokeping.nix b/nixos/modules/services/networking/smokeping.nix
index 3fb3eac45cc82..a07cde847cf69 100644
--- a/nixos/modules/services/networking/smokeping.nix
+++ b/nixos/modules/services/networking/smokeping.nix
@@ -337,7 +337,11 @@ in
     };
 
     # use nginx to serve the smokeping web service
-    services.fcgiwrap.enable = mkIf cfg.webService true;
+    services.fcgiwrap.smokeping = mkIf cfg.webService {
+      process.user = cfg.user;
+      process.group = cfg.user;
+      socket = { inherit (config.services.nginx) user group; };
+    };
     services.nginx = mkIf cfg.webService {
       enable = true;
       virtualHosts."smokeping" = {
@@ -349,7 +353,7 @@ in
         locations."/smokeping.fcgi" = {
           extraConfig = ''
             include ${config.services.nginx.package}/conf/fastcgi_params;
-            fastcgi_pass unix:${config.services.fcgiwrap.socketAddress};
+            fastcgi_pass unix:${config.services.fcgiwrap.smokeping.socket.address};
             fastcgi_param SCRIPT_FILENAME ${smokepingHome}/smokeping.fcgi;
             fastcgi_param DOCUMENT_ROOT ${smokepingHome};
           '';
diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix
index 45503ef89aaa1..94ff838b50e04 100644
--- a/nixos/modules/services/networking/syncthing.nix
+++ b/nixos/modules/services/networking/syncthing.nix
@@ -368,6 +368,15 @@ in {
                     '';
                   };
 
+                  type = mkOption {
+                    type = types.enum [ "sendreceive" "sendonly" "receiveonly" "receiveencrypted" ];
+                    default = "sendreceive";
+                    description = ''
+                      Controls how the folder is handled by Syncthing.
+                      See <https://docs.syncthing.net/users/config.html#config-option-folder.type>.
+                    '';
+                  };
+
                   devices = mkOption {
                     type = types.listOf types.str;
                     default = [];
diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix
index b3598606d8be7..a23c19f685d2d 100644
--- a/nixos/modules/services/security/clamav.nix
+++ b/nixos/modules/services/security/clamav.nix
@@ -5,7 +5,6 @@ let
   stateDir = "/var/lib/clamav";
   clamavGroup = clamavUser;
   cfg = config.services.clamav;
-  pkg = pkgs.clamav;
 
   toKeyValue = generators.toKeyValue {
     mkKeyValue = generators.mkKeyValueDefault { } " ";
@@ -27,6 +26,7 @@ in
 
   options = {
     services.clamav = {
+      package = mkPackageOption pkgs "clamav" { };
       daemon = {
         enable = mkEnableOption "ClamAV clamd daemon";
 
@@ -125,7 +125,7 @@ in
   };
 
   config = mkIf (cfg.updater.enable || cfg.daemon.enable) {
-    environment.systemPackages = [ pkg ];
+    environment.systemPackages = [ cfg.package ];
 
     users.users.${clamavUser} = {
       uid = config.ids.uids.clamav;
@@ -172,7 +172,7 @@ in
       restartTriggers = [ clamdConfigFile ];
 
       serviceConfig = {
-        ExecStart = "${pkg}/bin/clamd";
+        ExecStart = "${cfg.package}/bin/clamd";
         ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
         User = clamavUser;
         Group = clamavGroup;
@@ -201,7 +201,7 @@ in
 
       serviceConfig = {
         Type = "oneshot";
-        ExecStart = "${pkg}/bin/freshclam";
+        ExecStart = "${cfg.package}/bin/freshclam";
         SuccessExitStatus = "1"; # if databases are up to date
         StateDirectory = "clamav";
         User = clamavUser;
@@ -274,7 +274,7 @@ in
 
       serviceConfig = {
         Type = "oneshot";
-        ExecStart = "${pkg}/bin/clamdscan --multiscan --fdpass --infected --allmatch ${lib.concatStringsSep " " cfg.scanner.scanDirectories}";
+        ExecStart = "${cfg.package}/bin/clamdscan --multiscan --fdpass --infected --allmatch ${lib.concatStringsSep " " cfg.scanner.scanDirectories}";
       };
     };
   };
diff --git a/nixos/modules/services/security/sks.nix b/nixos/modules/services/security/sks.nix
index 520da45c94e2f..20d2dadbb7e22 100644
--- a/nixos/modules/services/security/sks.nix
+++ b/nixos/modules/services/security/sks.nix
@@ -10,7 +10,7 @@ let
   '';
 
 in {
-  meta.maintainers = with maintainers; [ primeos calbrecht jcumming ];
+  meta.maintainers = with maintainers; [ calbrecht jcumming ];
 
   options = {
 
diff --git a/nixos/modules/services/security/yubikey-agent.nix b/nixos/modules/services/security/yubikey-agent.nix
index 991f6a5595451..6a4dc7014970a 100644
--- a/nixos/modules/services/security/yubikey-agent.nix
+++ b/nixos/modules/services/security/yubikey-agent.nix
@@ -10,7 +10,7 @@ in
 {
   ###### interface
 
-  meta.maintainers = with maintainers; [ philandstuff rawkode jwoudenberg ];
+  meta.maintainers = with maintainers; [ philandstuff rawkode ];
 
   options = {
 
diff --git a/nixos/modules/services/system/cloud-init.nix b/nixos/modules/services/system/cloud-init.nix
index 5d7258cac7780..7148d62b90842 100644
--- a/nixos/modules/services/system/cloud-init.nix
+++ b/nixos/modules/services/system/cloud-init.nix
@@ -16,6 +16,7 @@ let
   ++ optional cfg.btrfs.enable btrfs-progs
   ++ optional cfg.ext4.enable e2fsprogs
   ++ optional cfg.xfs.enable xfsprogs
+  ++ cfg.extraPackages
   ;
   hasFs = fsName: lib.any (fs: fs.fsType == fsName) (lib.attrValues config.fileSystems);
   settingsFormat = pkgs.formats.yaml { };
@@ -79,6 +80,14 @@ in
         '';
       };
 
+      extraPackages = mkOption {
+        type = types.listOf types.package;
+        default = [ ];
+        description = ''
+          List of additional packages to be available within cloud-init jobs.
+        '';
+      };
+
       settings = mkOption {
         description = ''
           Structured cloud-init configuration.
@@ -163,7 +172,7 @@ in
         { text = cfg.config; }
     ;
 
-    systemd.network.enable = cfg.network.enable;
+    systemd.network.enable = mkIf cfg.network.enable true;
 
     systemd.services.cloud-init-local = {
       description = "Initial cloud-init job (pre-networking)";
diff --git a/nixos/modules/services/torrent/rtorrent.nix b/nixos/modules/services/torrent/rtorrent.nix
index e0ce33d13462e..609b06b5e7066 100644
--- a/nixos/modules/services/torrent/rtorrent.nix
+++ b/nixos/modules/services/torrent/rtorrent.nix
@@ -182,7 +182,7 @@ in {
 
       # XMLRPC
       scgi_local = (cfg.rpcsock)
-      schedule = scgi_group,0,0,"execute.nothrow=chown,\":rtorrent\",(cfg.rpcsock)"
+      schedule = scgi_group,0,0,"execute.nothrow=chown,\":${cfg.group}\",(cfg.rpcsock)"
       schedule = scgi_permission,0,0,"execute.nothrow=chmod,\"g+w,o=\",(cfg.rpcsock)"
     '';
 
diff --git a/nixos/modules/services/ttys/kmscon.nix b/nixos/modules/services/ttys/kmscon.nix
index 4803d577b94b1..6b05886756fe2 100644
--- a/nixos/modules/services/ttys/kmscon.nix
+++ b/nixos/modules/services/ttys/kmscon.nix
@@ -41,6 +41,12 @@ in {
           }; in nullOr (nonEmptyListOf fontType);
       };
 
+      useXkbConfig = mkOption {
+        description = "Configure keymap from xserver keyboard settings.";
+        type = types.bool;
+        default = false;
+      };
+
       extraConfig = mkOption {
         description = "Extra contents of the kmscon.conf file.";
         type = types.lines;
@@ -91,9 +97,15 @@ in {
 
     services.kmscon.extraConfig =
       let
+        xkb = optionals cfg.useXkbConfig
+          (lib.mapAttrsToList (n: v: "xkb-${n}=${v}") (
+            lib.filterAttrs
+              (n: v: builtins.elem n ["layout" "model" "options" "variant"] && v != "")
+              config.services.xserver.xkb
+          ));
         render = optionals cfg.hwRender [ "drm" "hwaccel" ];
         fonts = optional (cfg.fonts != null) "font-name=${lib.concatMapStringsSep ", " (f: f.name) cfg.fonts}";
-      in lib.concatStringsSep "\n" (render ++ fonts);
+      in lib.concatStringsSep "\n" (xkb ++ render ++ fonts);
 
     hardware.graphics.enable = mkIf cfg.hwRender true;
 
diff --git a/nixos/modules/services/web-apps/eintopf.nix b/nixos/modules/services/web-apps/eintopf.nix
new file mode 100644
index 0000000000000..a2b304445597e
--- /dev/null
+++ b/nixos/modules/services/web-apps/eintopf.nix
@@ -0,0 +1,92 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.eintopf;
+
+in {
+  options.services.eintopf = {
+
+    enable = mkEnableOption "Eintopf community event calendar web app";
+
+    settings = mkOption {
+      type = types.attrsOf types.str;
+      default = { };
+      description = ''
+        Settings to configure web service. See
+        <https://codeberg.org/Klasse-Methode/eintopf/src/branch/main/DEPLOYMENT.md>
+        for available options.
+      '';
+      example = literalExpression ''
+        {
+          EINTOPF_ADDR = ":1234";
+          EINTOPF_ADMIN_EMAIL = "admin@example.org";
+          EINTOPF_TIMEZONE = "Europe/Berlin";
+        }
+      '';
+    };
+
+    secrets = lib.mkOption {
+      type = with types; listOf path;
+      description = ''
+        A list of files containing the various secrets. Should be in the
+        format expected by systemd's `EnvironmentFile` directory.
+      '';
+      default = [ ];
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd.services.eintopf = {
+      description = "Community event calendar web app";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-online.target" ];
+      wants = [ "network-online.target" ];
+      environment = cfg.settings;
+      serviceConfig = {
+        ExecStart = "${pkgs.eintopf}/bin/eintopf";
+        WorkingDirectory = "/var/lib/eintopf";
+        StateDirectory = "eintopf" ;
+        EnvironmentFile = [ cfg.secrets ];
+
+        # hardening
+        AmbientCapabilities = "";
+        CapabilityBoundingSet = "" ;
+        DevicePolicy = "closed";
+        DynamicUser = true;
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateTmp = true;
+        PrivateUsers = true;
+        ProcSubset = "pid";
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectProc = "invisible";
+        ProtectSystem = "strict";
+        RemoveIPC = true;
+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        SystemCallArchitectures = "native";
+        SystemCallFilter = [ "@system-service" "~@privileged" ];
+        UMask = "0077";
+      };
+    };
+
+  };
+
+  meta.maintainers = with lib.maintainers; [ onny ];
+
+}
diff --git a/nixos/modules/services/web-apps/freshrss.nix b/nixos/modules/services/web-apps/freshrss.nix
index 021101fecaa48..7a22e15231923 100644
--- a/nixos/modules/services/web-apps/freshrss.nix
+++ b/nixos/modules/services/web-apps/freshrss.nix
@@ -5,6 +5,15 @@ let
   cfg = config.services.freshrss;
 
   poolName = "freshrss";
+
+  extension-env = pkgs.buildEnv {
+    name = "freshrss-extensions";
+    paths = cfg.extensions;
+  };
+  env-vars = {
+    DATA_PATH = cfg.dataDir;
+    THIRDPARTY_EXTENSIONS_PATH = "${extension-env}/share/freshrss/";
+  };
 in
 {
   meta.maintainers = with maintainers; [ etu stunkymonkey mattchrist ];
@@ -14,6 +23,31 @@ in
 
     package = mkPackageOption pkgs "freshrss" { };
 
+    extensions = mkOption {
+      type = types.listOf types.package;
+      default = [ ];
+      defaultText = literalExpression "[]";
+      example = literalExpression ''
+        with freshrss-extensions; [
+          youtube
+        ] ++ [
+          (freshrss-extensions.buildFreshRssExtension {
+            FreshRssExtUniqueId = "ReadingTime";
+            pname = "reading-time";
+            version = "1.5";
+            src = pkgs.fetchFromGitLab {
+              domain = "framagit.org";
+              owner = "Lapineige";
+              repo = "FreshRSS_Extension-ReadingTime";
+              rev = "fb6e9e944ef6c5299fa56ffddbe04c41e5a34ebf";
+             hash = "sha256-C5cRfaphx4Qz2xg2z+v5qRji8WVSIpvzMbethTdSqsk=";
+           };
+          })
+        ]
+      '';
+      description = "Additional extensions to be used.";
+    };
+
     defaultUser = mkOption {
       type = types.str;
       default = "admin";
@@ -214,9 +248,7 @@ in
             "pm.max_spare_servers" = 5;
             "catch_workers_output" = true;
           };
-          phpEnv = {
-            DATA_PATH = "${cfg.dataDir}";
-          };
+          phpEnv = env-vars;
         };
       };
 
@@ -259,9 +291,7 @@ in
             RemainAfterExit = true;
           };
           restartIfChanged = true;
-          environment = {
-            DATA_PATH = cfg.dataDir;
-          };
+          environment = env-vars;
 
           script =
             let
@@ -293,9 +323,7 @@ in
         description = "FreshRSS feed updater";
         after = [ "freshrss-config.service" ];
         startAt = "*:0/5";
-        environment = {
-          DATA_PATH = cfg.dataDir;
-        };
+        environment = env-vars;
         serviceConfig = defaultServiceConfig // {
           ExecStart = "${cfg.package}/app/actualize_script.php";
         };
diff --git a/nixos/modules/services/web-apps/glance.md b/nixos/modules/services/web-apps/glance.md
new file mode 100644
index 0000000000000..f65b32b3ba914
--- /dev/null
+++ b/nixos/modules/services/web-apps/glance.md
@@ -0,0 +1,39 @@
+# Glance {#module-services-glance}
+
+Glance is a self-hosted dashboard that puts all your feeds in one place.
+
+Visit [the Glance project page](https://github.com/glanceapp/glance) to learn
+more about it.
+
+## Quickstart {#module-services-glance-quickstart}
+
+Checkout the [configuration docs](https://github.com/glanceapp/glance/blob/main/docs/configuration.md) to learn more.
+Use the following configuration to start a public instance of Glance locally:
+
+```nix
+{
+  services.glance = {
+    enable = true;
+    settings = {
+      pages = [
+        {
+          name = "Home";
+          columns = [
+            {
+              size = "full";
+              widgets = [
+                { type = "calendar"; }
+                {
+                  type = "weather";
+                  location = "Nivelles, Belgium";
+                }
+              ];
+            }
+          ];
+        }
+      ];
+    };
+    openFirewall = true;
+  };
+}
+```
diff --git a/nixos/modules/services/web-apps/glance.nix b/nixos/modules/services/web-apps/glance.nix
new file mode 100644
index 0000000000000..fbc310daea770
--- /dev/null
+++ b/nixos/modules/services/web-apps/glance.nix
@@ -0,0 +1,141 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+let
+  cfg = config.services.glance;
+
+  inherit (lib)
+    mkEnableOption
+    mkPackageOption
+    mkOption
+    mkIf
+    getExe
+    types
+    ;
+
+  settingsFormat = pkgs.formats.yaml { };
+in
+{
+  options.services.glance = {
+    enable = mkEnableOption "glance";
+    package = mkPackageOption pkgs "glance" { };
+
+    settings = mkOption {
+      type = types.submodule {
+        freeformType = settingsFormat.type;
+        options = {
+          server = {
+            host = mkOption {
+              description = "Glance bind address";
+              default = "127.0.0.1";
+              example = "0.0.0.0";
+              type = types.str;
+            };
+            port = mkOption {
+              description = "Glance port to listen on";
+              default = 8080;
+              example = 5678;
+              type = types.port;
+            };
+          };
+          pages = mkOption {
+            type = settingsFormat.type;
+            description = ''
+              List of pages to be present on the dashboard.
+
+              See <https://github.com/glanceapp/glance/blob/main/docs/configuration.md#pages--columns>
+            '';
+            default = [
+              {
+                name = "Calendar";
+                columns = [
+                  {
+                    size = "full";
+                    widgets = [ { type = "calendar"; } ];
+                  }
+                ];
+              }
+            ];
+            example = [
+              {
+                name = "Home";
+                columns = [
+                  {
+                    size = "full";
+                    widgets = [
+                      { type = "calendar"; }
+                      {
+                        type = "weather";
+                        location = "Nivelles, Belgium";
+                      }
+                    ];
+                  }
+                ];
+              }
+            ];
+          };
+        };
+      };
+      default = { };
+      description = ''
+        Configuration written to a yaml file that is read by glance. See
+        <https://github.com/glanceapp/glance/blob/main/docs/configuration.md>
+        for more.
+      '';
+    };
+
+    openFirewall = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to open the firewall for Glance.
+        This adds `services.glance.settings.server.port` to `networking.firewall.allowedTCPPorts`.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.glance = {
+      description = "Glance feed dashboard server";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      serviceConfig = {
+        ExecStart =
+          let
+            glance-yaml = settingsFormat.generate "glance.yaml" cfg.settings;
+          in
+          "${getExe cfg.package} --config ${glance-yaml}";
+        WorkingDirectory = "/var/lib/glance";
+        StateDirectory = "glance";
+        RuntimeDirectory = "glance";
+        RuntimeDirectoryMode = "0755";
+        PrivateTmp = true;
+        DynamicUser = true;
+        DevicePolicy = "closed";
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        PrivateUsers = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectControlGroups = true;
+        ProcSubset = "pid";
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        SystemCallArchitectures = "native";
+        UMask = "0077";
+      };
+    };
+
+    networking.firewall = mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.settings.server.port ]; };
+  };
+
+  meta.doc = ./glance.md;
+  meta.maintainers = [ lib.maintainers.drupol ];
+}
diff --git a/nixos/modules/services/web-apps/jitsi-meet.nix b/nixos/modules/services/web-apps/jitsi-meet.nix
index 247b65c786636..39aa7379c0edf 100644
--- a/nixos/modules/services/web-apps/jitsi-meet.nix
+++ b/nixos/modules/services/web-apps/jitsi-meet.nix
@@ -398,30 +398,29 @@ in
       before = [ "jicofo.service" "jitsi-videobridge2.service" ] ++ (optional cfg.prosody.enable "prosody.service") ++ (optional cfg.jigasi.enable "jigasi.service");
       serviceConfig = {
         Type = "oneshot";
+        UMask = "027";
+        User = "root";
+        Group = "jitsi-meet";
+        WorkingDirectory = "/var/lib/jitsi-meet";
       };
 
       script = let
         secrets = [ "jicofo-component-secret" "jicofo-user-secret" "jibri-auth-secret" "jibri-recorder-secret" ] ++ (optionals cfg.jigasi.enable [ "jigasi-user-secret" "jigasi-component-secret" ]) ++ (optional (cfg.videobridge.passwordFile == null) "videobridge-secret");
       in
       ''
-        cd /var/lib/jitsi-meet
         ${concatMapStringsSep "\n" (s: ''
           if [ ! -f ${s} ]; then
             tr -dc a-zA-Z0-9 </dev/urandom | head -c 64 > ${s}
-            chown root:jitsi-meet ${s}
-            chmod 640 ${s}
           fi
         '') secrets}
 
         # for easy access in prosody
         echo "JICOFO_COMPONENT_SECRET=$(cat jicofo-component-secret)" > secrets-env
         echo "JIGASI_COMPONENT_SECRET=$(cat jigasi-component-secret)" >> secrets-env
-        chown root:jitsi-meet secrets-env
-        chmod 640 secrets-env
       ''
       + optionalString cfg.prosody.enable ''
         # generate self-signed certificates
-        if [ ! -f /var/lib/jitsi-meet.crt ]; then
+        if [ ! -f /var/lib/jitsi-meet/jitsi-meet.crt ]; then
           ${getBin pkgs.openssl}/bin/openssl req \
             -x509 \
             -newkey rsa:4096 \
@@ -430,8 +429,7 @@ in
             -days 36500 \
             -nodes \
             -subj '/CN=${cfg.hostName}/CN=auth.${cfg.hostName}'
-          chmod 640 /var/lib/jitsi-meet/jitsi-meet.{crt,key}
-          chown root:jitsi-meet /var/lib/jitsi-meet/jitsi-meet.{crt,key}
+          chmod 640 /var/lib/jitsi-meet/jitsi-meet.key
         fi
       '';
     };
diff --git a/nixos/modules/services/web-apps/keycloak.nix b/nixos/modules/services/web-apps/keycloak.nix
index 36bae2575974e..5d429675bafcf 100644
--- a/nixos/modules/services/web-apps/keycloak.nix
+++ b/nixos/modules/services/web-apps/keycloak.nix
@@ -328,7 +328,7 @@ in
             };
 
             hostname = mkOption {
-              type = str;
+              type = nullOr str;
               example = "keycloak.example.com";
               description = ''
                 The hostname part of the public URL used as base for
@@ -478,6 +478,10 @@ in
             message = "Setting up a local PostgreSQL db for Keycloak requires `standard_conforming_strings` turned on to work reliably";
           }
           {
+            assertion = cfg.settings.hostname != null || ! cfg.settings.hostname-strict or true;
+            message = "Setting the Keycloak hostname is required, see `services.keycloak.settings.hostname`";
+          }
+          {
             assertion = cfg.settings.hostname-url or null == null;
             message = ''
               The option `services.keycloak.settings.hostname-url' has been removed.
diff --git a/nixos/modules/services/web-apps/mediawiki.nix b/nixos/modules/services/web-apps/mediawiki.nix
index b11626ec2dc3b..600ad3053605d 100644
--- a/nixos/modules/services/web-apps/mediawiki.nix
+++ b/nixos/modules/services/web-apps/mediawiki.nix
@@ -64,129 +64,135 @@ let
   else
     throw "Unsupported database type: ${cfg.database.type} for socket: ${cfg.database.socket}";
 
-  mediawikiConfig = pkgs.writeText "LocalSettings.php" ''
-    <?php
-      # Protect against web entry
-      if ( !defined( 'MEDIAWIKI' ) ) {
-        exit;
-      }
+  mediawikiConfig = pkgs.writeTextFile {
+    name = "LocalSettings.php";
+    checkPhase = ''
+      ${php}/bin/php --syntax-check "$target"
+    '';
+    text = ''
+      <?php
+        # Protect against web entry
+        if ( !defined( 'MEDIAWIKI' ) ) {
+          exit;
+        }
 
-      $wgSitename = "${cfg.name}";
-      $wgMetaNamespace = false;
-
-      ## The URL base path to the directory containing the wiki;
-      ## defaults for all runtime URL paths are based off of this.
-      ## For more information on customizing the URLs
-      ## (like /w/index.php/Page_title to /wiki/Page_title) please see:
-      ## https://www.mediawiki.org/wiki/Manual:Short_URL
-      $wgScriptPath = "${lib.optionalString (cfg.webserver == "nginx") "/w"}";
+        $wgSitename = "${cfg.name}";
+        $wgMetaNamespace = false;
+
+        ## The URL base path to the directory containing the wiki;
+        ## defaults for all runtime URL paths are based off of this.
+        ## For more information on customizing the URLs
+        ## (like /w/index.php/Page_title to /wiki/Page_title) please see:
+        ## https://www.mediawiki.org/wiki/Manual:Short_URL
+        $wgScriptPath = "${lib.optionalString (cfg.webserver == "nginx") "/w"}";
 
-      ## The protocol and server name to use in fully-qualified URLs
-      $wgServer = "${cfg.url}";
+        ## The protocol and server name to use in fully-qualified URLs
+        $wgServer = "${cfg.url}";
 
-      ## The URL path to static resources (images, scripts, etc.)
-      $wgResourceBasePath = $wgScriptPath;
+        ## The URL path to static resources (images, scripts, etc.)
+        $wgResourceBasePath = $wgScriptPath;
 
-      ${lib.optionalString (cfg.webserver == "nginx") ''
-        $wgArticlePath = "/wiki/$1";
-        $wgUsePathInfo = true;
-      ''}
+        ${lib.optionalString (cfg.webserver == "nginx") ''
+          $wgArticlePath = "/wiki/$1";
+          $wgUsePathInfo = true;
+        ''}
 
-      ## The URL path to the logo.  Make sure you change this from the default,
-      ## or else you'll overwrite your logo when you upgrade!
-      $wgLogo = "$wgResourceBasePath/resources/assets/wiki.png";
+        ## The URL path to the logo.  Make sure you change this from the default,
+        ## or else you'll overwrite your logo when you upgrade!
+        $wgLogo = "$wgResourceBasePath/resources/assets/wiki.png";
 
-      ## UPO means: this is also a user preference option
+        ## UPO means: this is also a user preference option
 
-      $wgEnableEmail = true;
-      $wgEnableUserEmail = true; # UPO
+        $wgEnableEmail = true;
+        $wgEnableUserEmail = true; # UPO
 
-      $wgPasswordSender = "${cfg.passwordSender}";
+        $wgPasswordSender = "${cfg.passwordSender}";
 
-      $wgEnotifUserTalk = false; # UPO
-      $wgEnotifWatchlist = false; # UPO
-      $wgEmailAuthentication = true;
+        $wgEnotifUserTalk = false; # UPO
+        $wgEnotifWatchlist = false; # UPO
+        $wgEmailAuthentication = true;
 
-      ## Database settings
-      $wgDBtype = "${cfg.database.type}";
-      $wgDBserver = "${dbAddr}";
-      $wgDBport = "${toString cfg.database.port}";
-      $wgDBname = "${cfg.database.name}";
-      $wgDBuser = "${cfg.database.user}";
-      ${optionalString (cfg.database.passwordFile != null) "$wgDBpassword = file_get_contents(\"${cfg.database.passwordFile}\");"}
+        ## Database settings
+        $wgDBtype = "${cfg.database.type}";
+        $wgDBserver = "${dbAddr}";
+        $wgDBport = "${toString cfg.database.port}";
+        $wgDBname = "${cfg.database.name}";
+        $wgDBuser = "${cfg.database.user}";
+        ${optionalString (cfg.database.passwordFile != null) "$wgDBpassword = file_get_contents(\"${cfg.database.passwordFile}\");"}
 
-      ${optionalString (cfg.database.type == "mysql" && cfg.database.tablePrefix != null) ''
-        # MySQL specific settings
-        $wgDBprefix = "${cfg.database.tablePrefix}";
-      ''}
+        ${optionalString (cfg.database.type == "mysql" && cfg.database.tablePrefix != null) ''
+          # MySQL specific settings
+          $wgDBprefix = "${cfg.database.tablePrefix}";
+        ''}
 
-      ${optionalString (cfg.database.type == "mysql") ''
-        # MySQL table options to use during installation or update
-        $wgDBTableOptions = "ENGINE=InnoDB, DEFAULT CHARSET=binary";
-      ''}
+        ${optionalString (cfg.database.type == "mysql") ''
+          # MySQL table options to use during installation or update
+          $wgDBTableOptions = "ENGINE=InnoDB, DEFAULT CHARSET=binary";
+        ''}
 
-      ## Shared memory settings
-      $wgMainCacheType = CACHE_NONE;
-      $wgMemCachedServers = [];
+        ## Shared memory settings
+        $wgMainCacheType = CACHE_NONE;
+        $wgMemCachedServers = [];
 
-      ${optionalString (cfg.uploadsDir != null) ''
-        $wgEnableUploads = true;
-        $wgUploadDirectory = "${cfg.uploadsDir}";
-      ''}
+        ${optionalString (cfg.uploadsDir != null) ''
+          $wgEnableUploads = true;
+          $wgUploadDirectory = "${cfg.uploadsDir}";
+        ''}
 
-      $wgUseImageMagick = true;
-      $wgImageMagickConvertCommand = "${pkgs.imagemagick}/bin/convert";
+        $wgUseImageMagick = true;
+        $wgImageMagickConvertCommand = "${pkgs.imagemagick}/bin/convert";
 
-      # InstantCommons allows wiki to use images from https://commons.wikimedia.org
-      $wgUseInstantCommons = false;
+        # InstantCommons allows wiki to use images from https://commons.wikimedia.org
+        $wgUseInstantCommons = false;
 
-      # Periodically send a pingback to https://www.mediawiki.org/ with basic data
-      # about this MediaWiki instance. The Wikimedia Foundation shares this data
-      # with MediaWiki developers to help guide future development efforts.
-      $wgPingback = true;
+        # Periodically send a pingback to https://www.mediawiki.org/ with basic data
+        # about this MediaWiki instance. The Wikimedia Foundation shares this data
+        # with MediaWiki developers to help guide future development efforts.
+        $wgPingback = true;
 
-      ## If you use ImageMagick (or any other shell command) on a
-      ## Linux server, this will need to be set to the name of an
-      ## available UTF-8 locale
-      $wgShellLocale = "C.UTF-8";
+        ## If you use ImageMagick (or any other shell command) on a
+        ## Linux server, this will need to be set to the name of an
+        ## available UTF-8 locale
+        $wgShellLocale = "C.UTF-8";
 
-      ## Set $wgCacheDirectory to a writable directory on the web server
-      ## to make your wiki go slightly faster. The directory should not
-      ## be publicly accessible from the web.
-      $wgCacheDirectory = "${cacheDir}";
+        ## Set $wgCacheDirectory to a writable directory on the web server
+        ## to make your wiki go slightly faster. The directory should not
+        ## be publicly accessible from the web.
+        $wgCacheDirectory = "${cacheDir}";
 
-      # Site language code, should be one of the list in ./languages/data/Names.php
-      $wgLanguageCode = "en";
+        # Site language code, should be one of the list in ./languages/data/Names.php
+        $wgLanguageCode = "en";
 
-      $wgSecretKey = file_get_contents("${stateDir}/secret.key");
+        $wgSecretKey = file_get_contents("${stateDir}/secret.key");
 
-      # Changing this will log out all existing sessions.
-      $wgAuthenticationTokenVersion = "";
+        # Changing this will log out all existing sessions.
+        $wgAuthenticationTokenVersion = "";
 
-      ## For attaching licensing metadata to pages, and displaying an
-      ## appropriate copyright notice / icon. GNU Free Documentation
-      ## License and Creative Commons licenses are supported so far.
-      $wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright
-      $wgRightsUrl = "";
-      $wgRightsText = "";
-      $wgRightsIcon = "";
+        ## For attaching licensing metadata to pages, and displaying an
+        ## appropriate copyright notice / icon. GNU Free Documentation
+        ## License and Creative Commons licenses are supported so far.
+        $wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright
+        $wgRightsUrl = "";
+        $wgRightsText = "";
+        $wgRightsIcon = "";
 
-      # Path to the GNU diff3 utility. Used for conflict resolution.
-      $wgDiff = "${pkgs.diffutils}/bin/diff";
-      $wgDiff3 = "${pkgs.diffutils}/bin/diff3";
+        # Path to the GNU diff3 utility. Used for conflict resolution.
+        $wgDiff = "${pkgs.diffutils}/bin/diff";
+        $wgDiff3 = "${pkgs.diffutils}/bin/diff3";
 
-      # Enabled skins.
-      ${concatStringsSep "\n" (mapAttrsToList (k: v: "wfLoadSkin('${k}');") cfg.skins)}
+        # Enabled skins.
+        ${concatStringsSep "\n" (mapAttrsToList (k: v: "wfLoadSkin('${k}');") cfg.skins)}
 
-      # Enabled extensions.
-      ${concatStringsSep "\n" (mapAttrsToList (k: v: "wfLoadExtension('${k}');") cfg.extensions)}
+        # Enabled extensions.
+        ${concatStringsSep "\n" (mapAttrsToList (k: v: "wfLoadExtension('${k}');") cfg.extensions)}
 
 
-      # End of automatically generated settings.
-      # Add more configuration options below.
+        # End of automatically generated settings.
+        # Add more configuration options below.
 
-      ${cfg.extraConfig}
-  '';
+        ${cfg.extraConfig}
+      '';
+    };
 
   withTrailingSlash = str: if lib.hasSuffix "/" str then str else "${str}/";
 in
diff --git a/nixos/modules/services/web-apps/nextcloud.md b/nixos/modules/services/web-apps/nextcloud.md
index 0b615deae44be..c433be5350b53 100644
--- a/nixos/modules/services/web-apps/nextcloud.md
+++ b/nixos/modules/services/web-apps/nextcloud.md
@@ -121,6 +121,29 @@ Auto updates for Nextcloud apps can be enabled using
     This is not an end-to-end encryption, but can be used to encrypt files that will be persisted
     to external storage such as S3.
 
+  - **Issues with file permissions / unsafe path transitions**
+
+    {manpage}`systemd-tmpfiles(8)` makes sure that the paths for
+
+    * configuration (including declarative config)
+    * data
+    * app store
+    * home directory itself (usually `/var/lib/nextcloud`)
+
+    are properly set up. However, `systemd-tmpfiles` will refuse to do so
+    if it detects an unsafe path transition, i.e. creating files/directories
+    within a directory that is neither owned by `root` nor by `nextcloud`, the
+    owning user of the files/directories to be created.
+
+    Symptoms of that include
+
+    * `config/override.config.php` not being updated (and the config file
+      eventually being garbage-collected).
+    * failure to read from application data.
+
+    To work around that, please make sure that all directories in question
+    are owned by `nextcloud:nextcloud`.
+
 ## Using an alternative webserver as reverse-proxy (e.g. `httpd`) {#module-services-nextcloud-httpd}
 
 By default, `nginx` is used as reverse-proxy for `nextcloud`.
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index bfb3e73e65102..c8c4fe4b4d612 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -91,10 +91,10 @@ let
     cd ${webroot}
     sudo=exec
     if [[ "$USER" != nextcloud ]]; then
-      sudo='exec /run/wrappers/bin/sudo -u nextcloud --preserve-env=NEXTCLOUD_CONFIG_DIR --preserve-env=OC_PASS'
+      sudo='exec /run/wrappers/bin/sudo -u nextcloud'
     fi
-    export NEXTCLOUD_CONFIG_DIR="${datadir}/config"
-    $sudo \
+    $sudo ${pkgs.coreutils}/bin/env \
+      NEXTCLOUD_CONFIG_DIR="${datadir}/config" \
       ${phpCli} \
       occ "$@"
   '';
diff --git a/nixos/modules/services/web-apps/onlyoffice.nix b/nixos/modules/services/web-apps/onlyoffice.nix
index 545ca68ccaac2..0d0e01d4f7bc0 100644
--- a/nixos/modules/services/web-apps/onlyoffice.nix
+++ b/nixos/modules/services/web-apps/onlyoffice.nix
@@ -1,24 +1,22 @@
 { lib, config, pkgs, ... }:
 
-with lib;
-
 let
   cfg = config.services.onlyoffice;
 in
 {
   options.services.onlyoffice = {
-    enable = mkEnableOption "OnlyOffice DocumentServer";
+    enable = lib.mkEnableOption "OnlyOffice DocumentServer";
 
-    enableExampleServer = mkEnableOption "OnlyOffice example server";
+    enableExampleServer = lib.mkEnableOption "OnlyOffice example server";
 
-    hostname = mkOption {
-      type = types.str;
+    hostname = lib.mkOption {
+      type = lib.types.str;
       default = "localhost";
-      description = "FQDN for the onlyoffice instance.";
+      description = "FQDN for the OnlyOffice instance.";
     };
 
-    jwtSecretFile = mkOption {
-      type = types.nullOr types.str;
+    jwtSecretFile = lib.mkOption {
+      type = lib.types.nullOr lib.types.str;
       default = null;
       description = ''
         Path to a file that contains the secret to sign web requests using JSON Web Tokens.
@@ -26,34 +24,34 @@ in
       '';
     };
 
-    package = mkPackageOption pkgs "onlyoffice-documentserver" { };
+    package = lib.mkPackageOption pkgs "onlyoffice-documentserver" { };
 
-    port = mkOption {
-      type = types.port;
+    port = lib.mkOption {
+      type = lib.types.port;
       default = 8000;
-      description = "Port the OnlyOffice DocumentServer should listens on.";
+      description = "Port the OnlyOffice document server should listen on.";
     };
 
-    examplePort = mkOption {
-      type = types.port;
+    examplePort = lib.mkOption {
+      type = lib.types.port;
       default = null;
-      description = "Port the OnlyOffice Example server should listens on.";
+      description = "Port the OnlyOffice example server should listen on.";
     };
 
-    postgresHost = mkOption {
-      type = types.str;
+    postgresHost = lib.mkOption {
+      type = lib.types.str;
       default = "/run/postgresql";
       description = "The Postgresql hostname or socket path OnlyOffice should connect to.";
     };
 
-    postgresName = mkOption {
-      type = types.str;
+    postgresName = lib.mkOption {
+      type = lib.types.str;
       default = "onlyoffice";
-      description = "The name of database OnlyOffice should user.";
+      description = "The name of database OnlyOffice should use.";
     };
 
-    postgresPasswordFile = mkOption {
-      type = types.nullOr types.str;
+    postgresPasswordFile = lib.mkOption {
+      type = lib.types.nullOr lib.types.str;
       default = null;
       description = ''
         Path to a file that contains the password OnlyOffice should use to connect to Postgresql.
@@ -61,8 +59,8 @@ in
       '';
     };
 
-    postgresUser = mkOption {
-      type = types.str;
+    postgresUser = lib.mkOption {
+      type = lib.types.str;
       default = "onlyoffice";
       description = ''
         The username OnlyOffice should use to connect to Postgresql.
@@ -70,8 +68,8 @@ in
       '';
     };
 
-    rabbitmqUrl = mkOption {
-      type = types.str;
+    rabbitmqUrl = lib.mkOption {
+      type = lib.types.str;
       default = "amqp://guest:guest@localhost:5672";
       description = "The Rabbitmq in amqp URI style OnlyOffice should connect to.";
     };
@@ -80,10 +78,10 @@ in
   config = lib.mkIf cfg.enable {
     services = {
       nginx = {
-        enable = mkDefault true;
+        enable = lib.mkDefault true;
         # misses text/csv, font/ttf, application/x-font-ttf, application/rtf, application/wasm
-        recommendedGzipSettings = mkDefault true;
-        recommendedProxySettings = mkDefault true;
+        recommendedGzipSettings = lib.mkDefault true;
+        recommendedProxySettings = lib.mkDefault true;
 
         upstreams = {
           # /etc/nginx/includes/http-common.conf
diff --git a/nixos/modules/services/web-apps/pixelfed.nix b/nixos/modules/services/web-apps/pixelfed.nix
index cd0e8f62b65c8..46d671f8504b6 100644
--- a/nixos/modules/services/web-apps/pixelfed.nix
+++ b/nixos/modules/services/web-apps/pixelfed.nix
@@ -40,7 +40,7 @@ in {
     pixelfed = {
       enable = mkEnableOption "a Pixelfed instance";
       package = mkPackageOption pkgs "pixelfed" { };
-      phpPackage = mkPackageOption pkgs "php81" { };
+      phpPackage = mkPackageOption pkgs "php82" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/web-apps/shiori.nix b/nixos/modules/services/web-apps/shiori.nix
index 022bb5e438812..df3eeaef16183 100644
--- a/nixos/modules/services/web-apps/shiori.nix
+++ b/nixos/modules/services/web-apps/shiori.nix
@@ -1,17 +1,15 @@
 { config, lib, pkgs, ... }:
 
-with lib;
-let
-  cfg = config.services.shiori;
+let cfg = config.services.shiori;
 in {
   options = {
     services.shiori = {
-      enable = mkEnableOption "Shiori simple bookmarks manager";
+      enable = lib.mkEnableOption "Shiori simple bookmarks manager";
 
-      package = mkPackageOption pkgs "shiori" { };
+      package = lib.mkPackageOption pkgs "shiori" { };
 
-      address = mkOption {
-        type = types.str;
+      address = lib.mkOption {
+        type = lib.types.str;
         default = "";
         description = ''
           The IP address on which Shiori will listen.
@@ -19,30 +17,55 @@ in {
         '';
       };
 
-      port = mkOption {
-        type = types.port;
+      port = lib.mkOption {
+        type = lib.types.port;
         default = 8080;
         description = "The port of the Shiori web application";
       };
 
-      webRoot = mkOption {
-        type = types.str;
+      webRoot = lib.mkOption {
+        type = lib.types.str;
         default = "/";
         example = "/shiori";
         description = "The root of the Shiori web application";
       };
+
+      environmentFile = lib.mkOption {
+        type = lib.types.nullOr lib.types.path;
+        default = null;
+        example = "/path/to/environmentFile";
+        description = ''
+          Path to file containing environment variables.
+          Useful for passing down secrets.
+          <https://github.com/go-shiori/shiori/blob/master/docs/Configuration.md#overall-configuration>
+        '';
+      };
+
+      databaseUrl = lib.mkOption {
+        type = lib.types.nullOr lib.types.str;
+        default = null;
+        example = "postgres:///shiori?host=/run/postgresql";
+        description = "The connection URL to connect to MySQL or PostgreSQL";
+      };
     };
   };
 
-  config = mkIf cfg.enable {
-    systemd.services.shiori = with cfg; {
+  config = lib.mkIf cfg.enable {
+    systemd.services.shiori = {
       description = "Shiori simple bookmarks manager";
       wantedBy = [ "multi-user.target" ];
-
-      environment.SHIORI_DIR = "/var/lib/shiori";
+      after = [ "postgresql.service" "mysql.service" ];
+      environment = {
+        SHIORI_DIR = "/var/lib/shiori";
+      } // lib.optionalAttrs (cfg.databaseUrl != null) {
+        SHIORI_DATABASE_URL = cfg.databaseUrl;
+      };
 
       serviceConfig = {
-        ExecStart = "${package}/bin/shiori serve --address '${address}' --port '${toString port}' --webroot '${webRoot}'";
+        ExecStart =
+          "${cfg.package}/bin/shiori server --address '${cfg.address}' --port '${
+            toString cfg.port
+          }' --webroot '${cfg.webRoot}'";
 
         DynamicUser = true;
         StateDirectory = "shiori";
@@ -50,15 +73,24 @@ in {
         RuntimeDirectory = "shiori";
 
         # Security options
-
+        EnvironmentFile =
+          lib.optional (cfg.environmentFile != null) cfg.environmentFile;
         BindReadOnlyPaths = [
           "/nix/store"
 
           # For SSL certificates, and the resolv.conf
           "/etc"
-        ];
+        ] ++ lib.optional (config.services.postgresql.enable &&
+                           cfg.databaseUrl != null &&
+                           lib.strings.hasPrefix "postgres://" cfg.databaseUrl)
+            "/run/postgresql"
+          ++ lib.optional (config.services.mysql.enable &&
+                           cfg.databaseUrl != null &&
+                           lib.strings.hasPrefix "mysql://" cfg.databaseUrl)
+            "/var/run/mysqld";
 
         CapabilityBoundingSet = "";
+        AmbientCapabilities = "CAP_NET_BIND_SERVICE";
 
         DeviceAllow = "";
 
@@ -78,7 +110,7 @@ in {
         ProtectKernelTunables = true;
 
         RestrictNamespaces = true;
-        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
         RestrictRealtime = true;
         RestrictSUIDSGID = true;
 
@@ -88,11 +120,17 @@ in {
         SystemCallErrorNumber = "EPERM";
         SystemCallFilter = [
           "@system-service"
-          "~@cpu-emulation" "~@debug" "~@keyring" "~@memlock" "~@obsolete" "~@privileged" "~@setuid"
+          "~@cpu-emulation"
+          "~@debug"
+          "~@keyring"
+          "~@memlock"
+          "~@obsolete"
+          "~@privileged"
+          "~@setuid"
         ];
       };
     };
   };
 
-  meta.maintainers = with maintainers; [ minijackson ];
+  meta.maintainers = with lib.maintainers; [ minijackson CaptainJawZ ];
 }
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 4d49b29efff69..46cb099595794 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -435,7 +435,7 @@ in
         example = literalExpression ''
           [
             "proxy_connect"
-            { name = "jk"; path = "''${pkgs.tomcat_connectors}/modules/mod_jk.so"; }
+            { name = "jk"; path = "''${pkgs.apacheHttpdPackages.mod_jk}/modules/mod_jk.so"; }
           ]
         '';
         description = ''
@@ -538,25 +538,13 @@ in
         '';
       };
 
-      enableMellon = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to enable the mod_auth_mellon module.";
-      };
+      enableMellon = mkEnableOption "the mod_auth_mellon module";
 
-      enablePHP = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to enable the PHP module.";
-      };
+      enablePHP = mkEnableOption "the PHP module";
 
       phpPackage = mkPackageOption pkgs "php" { };
 
-      enablePerl = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to enable the Perl module (mod_perl).";
-      };
+      enablePerl = mkEnableOption "the Perl module (mod_perl)";
 
       phpOptions = mkOption {
         type = types.lines;
diff --git a/nixos/modules/services/web-servers/fcgiwrap.nix b/nixos/modules/services/web-servers/fcgiwrap.nix
index 3250e9c05ed66..29ddd39942c60 100644
--- a/nixos/modules/services/web-servers/fcgiwrap.nix
+++ b/nixos/modules/services/web-servers/fcgiwrap.nix
@@ -3,70 +3,128 @@
 with lib;
 
 let
-  cfg = config.services.fcgiwrap;
+  forEachInstance = f: flip mapAttrs' config.services.fcgiwrap (name: cfg:
+    nameValuePair "fcgiwrap-${name}" (f cfg)
+  );
+
 in {
+  options.services.fcgiwrap = mkOption {
+    description = "Configuration for fcgiwrap instances.";
+    default = { };
+    type = types.attrsOf (types.submodule ({ config, ... }: { options = {
+      process.prefork = mkOption {
+        type = types.ints.positive;
+        default = 1;
+        description = "Number of processes to prefork.";
+      };
 
-  options = {
-    services.fcgiwrap = {
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to enable fcgiwrap, a server for running CGI applications over FastCGI.";
+      process.user = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          User as which this instance of fcgiwrap will be run.
+          Set to `null` (the default) to use a dynamically allocated user.
+        '';
       };
 
-      preforkProcesses = mkOption {
-        type = types.int;
-        default = 1;
-        description = "Number of processes to prefork.";
+      process.group = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "Group as which this instance of fcgiwrap will be run.";
       };
 
-      socketType = mkOption {
+      socket.type = mkOption {
         type = types.enum [ "unix" "tcp" "tcp6" ];
         default = "unix";
         description = "Socket type: 'unix', 'tcp' or 'tcp6'.";
       };
 
-      socketAddress = mkOption {
+      socket.address = mkOption {
         type = types.str;
-        default = "/run/fcgiwrap.sock";
+        default = "/run/fcgiwrap-${config._module.args.name}.sock";
         example = "1.2.3.4:5678";
-        description = "Socket address. In case of a UNIX socket, this should be its filesystem path.";
+        description = ''
+          Socket address.
+          In case of a UNIX socket, this should be its filesystem path.
+        '';
       };
 
-      user = mkOption {
+      socket.user = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = "User permissions for the socket.";
+        description = ''
+          User to be set as owner of the UNIX socket.
+          Defaults to the process running user.
+        '';
       };
 
-      group = mkOption {
+      socket.group = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = "Group permissions for the socket.";
+        description = ''
+          Group to be set as owner of the UNIX socket.
+          Defaults to the process running group.
+        '';
       };
-    };
+
+      socket.mode = mkOption {
+        type = types.nullOr types.str;
+        default = if config.socket.type == "unix" then "0600" else null;
+        defaultText = literalExpression ''
+          if config.socket.type == "unix" then "0600" else null
+        '';
+        description = ''
+          Mode to be set on the UNIX socket.
+          Defaults to private to the socket's owner.
+        '';
+      };
+    }; }));
   };
 
-  config = mkIf cfg.enable {
-    systemd.services.fcgiwrap = {
+  config = {
+    assertions = concatLists (mapAttrsToList (name: cfg: [
+      {
+        assertion = cfg.socket.user != null -> cfg.socket.type == "unix";
+        message = "Socket owner can only be set for the UNIX socket type.";
+      }
+      {
+        assertion = cfg.socket.group != null -> cfg.socket.type == "unix";
+        message = "Socket owner can only be set for the UNIX socket type.";
+      }
+      {
+        assertion = cfg.socket.mode != null -> cfg.socket.type == "unix";
+        message = "Socket mode can only be set for the UNIX socket type.";
+      }
+    ]) config.services.fcgiwrap);
+
+    systemd.services = forEachInstance (cfg: {
       after = [ "nss-user-lookup.target" ];
-      wantedBy = optional (cfg.socketType != "unix") "multi-user.target";
+      wantedBy = optional (cfg.socket.type != "unix") "multi-user.target";
 
       serviceConfig = {
-        ExecStart = "${pkgs.fcgiwrap}/sbin/fcgiwrap -c ${builtins.toString cfg.preforkProcesses} ${
-          optionalString (cfg.socketType != "unix") "-s ${cfg.socketType}:${cfg.socketAddress}"
-        }";
-      } // (if cfg.user != null && cfg.group != null then {
-        User = cfg.user;
-        Group = cfg.group;
-      } else { } );
-    };
+        ExecStart = ''
+          ${pkgs.fcgiwrap}/sbin/fcgiwrap ${cli.toGNUCommandLineShell {} ({
+            c = cfg.process.prefork;
+          } // (optionalAttrs (cfg.socket.type != "unix") {
+            s = "${cfg.socket.type}:${cfg.socket.address}";
+          }))}
+        '';
+      } // (if cfg.process.user != null then {
+        User = cfg.process.user;
+        Group = cfg.process.group;
+      } else {
+        DynamicUser = true;
+      });
+    });
 
-    systemd.sockets = if (cfg.socketType == "unix") then {
-      fcgiwrap = {
-        wantedBy = [ "sockets.target" ];
-        socketConfig.ListenStream = cfg.socketAddress;
+    systemd.sockets = forEachInstance (cfg: mkIf (cfg.socket.type == "unix") {
+      wantedBy = [ "sockets.target" ];
+      socketConfig = {
+        ListenStream = cfg.socket.address;
+        SocketUser = cfg.socket.user;
+        SocketGroup = cfg.socket.group;
+        SocketMode = cfg.socket.mode;
       };
-    } else { };
+    });
   };
 }
diff --git a/nixos/modules/services/x11/desktop-managers/budgie.nix b/nixos/modules/services/x11/desktop-managers/budgie.nix
index b4e7390293351..7f43a939970b8 100644
--- a/nixos/modules/services/x11/desktop-managers/budgie.nix
+++ b/nixos/modules/services/x11/desktop-managers/budgie.nix
@@ -61,7 +61,7 @@ in {
         '';
         type = types.listOf types.package;
         default = [];
-        example = literalExpression "[ pkgs.gnome.gpaste ]";
+        example = literalExpression "[ pkgs.gpaste ]";
       };
 
       extraGSettingsOverrides = mkOption {
@@ -132,7 +132,7 @@ in {
         gnome-menus
 
         # Required by Budgie Control Center.
-        gnome.zenity
+        zenity
 
         # Provides `gsettings`.
         glib
@@ -162,7 +162,7 @@ in {
       ++ cfg.sessionPath;
 
     # Both budgie-desktop-view and nemo defaults to this emulator.
-    programs.gnome-terminal.enable = mkDefault (notExcluded pkgs.gnome.gnome-terminal);
+    programs.gnome-terminal.enable = mkDefault (notExcluded pkgs.gnome-terminal);
 
     # Fonts.
     fonts.packages = [
diff --git a/nixos/modules/services/x11/desktop-managers/cinnamon.nix b/nixos/modules/services/x11/desktop-managers/cinnamon.nix
index fa67441e7ac49..0dc21862d8348 100644
--- a/nixos/modules/services/x11/desktop-managers/cinnamon.nix
+++ b/nixos/modules/services/x11/desktop-managers/cinnamon.nix
@@ -27,7 +27,7 @@ in
       sessionPath = mkOption {
         default = [];
         type = types.listOf types.package;
-        example = literalExpression "[ pkgs.gnome.gpaste ]";
+        example = literalExpression "[ pkgs.gpaste ]";
         description = ''
           Additional list of packages to be added to the session search path.
           Useful for GSettings-conditional autostart.
@@ -163,8 +163,8 @@ in
         libgnomekbd
 
         # theme
-        gnome.adwaita-icon-theme
-        gnome.gnome-themes-extra
+        adwaita-icon-theme
+        gnome-themes-extra
         gtk3.out
 
         # other
@@ -229,11 +229,11 @@ in
     })
 
     (mkIf serviceCfg.apps.enable {
-      programs.gnome-disks.enable = mkDefault (notExcluded pkgs.gnome.gnome-disk-utility);
-      programs.gnome-terminal.enable = mkDefault (notExcluded pkgs.gnome.gnome-terminal);
-      programs.file-roller.enable = mkDefault (notExcluded pkgs.gnome.file-roller);
+      programs.gnome-disks.enable = mkDefault (notExcluded pkgs.gnome-disk-utility);
+      programs.gnome-terminal.enable = mkDefault (notExcluded pkgs.gnome-terminal);
+      programs.file-roller.enable = mkDefault (notExcluded pkgs.file-roller);
 
-      environment.systemPackages = with pkgs // pkgs.gnome // pkgs.cinnamon; utils.removePackagesByName [
+      environment.systemPackages = with pkgs // pkgs.cinnamon; utils.removePackagesByName [
         # cinnamon team apps
         bulky
         warpinator
diff --git a/nixos/modules/services/x11/desktop-managers/gnome.md b/nixos/modules/services/x11/desktop-managers/gnome.md
index 2b4bd06df04f2..9943f138dc60c 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome.md
+++ b/nixos/modules/services/x11/desktop-managers/gnome.md
@@ -114,7 +114,7 @@ in `dconf-editor`
 ## Shell Extensions {#sec-gnome-shell-extensions}
 
 Most Shell extensions are packaged under the `gnomeExtensions` attribute.
-Some packages that include Shell extensions, like `gnome.gpaste`, don’t have their extension decoupled under this attribute.
+Some packages that include Shell extensions, like `gpaste`, don’t have their extension decoupled under this attribute.
 
 You can install them like any other package:
 
diff --git a/nixos/modules/services/x11/desktop-managers/gnome.nix b/nixos/modules/services/x11/desktop-managers/gnome.nix
index fe50d930b5af0..11d5fcbfee23d 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome.nix
@@ -89,7 +89,7 @@ in
       sessionPath = mkOption {
         default = [];
         type = types.listOf types.package;
-        example = literalExpression "[ pkgs.gnome.gpaste ]";
+        example = literalExpression "[ pkgs.gpaste ]";
         description = ''
           Additional list of packages to be added to the session search path.
           Useful for GNOME Shell extensions or GSettings-conditional autostart.
@@ -176,7 +176,7 @@ in
 
     environment.gnome.excludePackages = mkOption {
       default = [];
-      example = literalExpression "[ pkgs.gnome.totem ]";
+      example = literalExpression "[ pkgs.totem ]";
       type = types.listOf types.package;
       description = "Which packages gnome should exclude from the default environment";
     };
@@ -373,7 +373,7 @@ in
             gnome-shell
           ];
           optionalPackages = with pkgs.gnome; [
-            adwaita-icon-theme
+            pkgs.adwaita-icon-theme
             nixos-background-info
             gnome-backgrounds
             gnome-bluetooth
@@ -399,28 +399,28 @@ in
         with pkgs.gnome;
         utils.removePackagesByName
           ([
-            baobab
-            epiphany
+            pkgs.baobab
+            pkgs.epiphany
             pkgs.gnome-text-editor
-            gnome-calculator
-            gnome-calendar
+            pkgs.gnome-calculator
+            pkgs.gnome-calendar
             gnome-characters
             gnome-clocks
             pkgs.gnome-console
             gnome-contacts
-            gnome-font-viewer
+            pkgs.gnome-font-viewer
             gnome-logs
             gnome-maps
             gnome-music
-            gnome-system-monitor
+            pkgs.gnome-system-monitor
             gnome-weather
             pkgs.loupe
-            nautilus
+            pkgs.nautilus
             pkgs.gnome-connections
-            simple-scan
+            pkgs.simple-scan
             pkgs.snapshot
-            totem
-            yelp
+            pkgs.totem
+            pkgs.yelp
           ] ++ lib.optionals config.services.flatpak.enable [
             # Since PackageKit Nix support is not there yet,
             # only install gnome-software if flatpak is enabled.
@@ -432,12 +432,12 @@ in
       # Since some of these have a corresponding package, we only
       # enable that program module if the package hasn't been excluded
       # through `environment.gnome.excludePackages`
-      programs.evince.enable = notExcluded pkgs.gnome.evince;
-      programs.file-roller.enable = notExcluded pkgs.gnome.file-roller;
-      programs.geary.enable = notExcluded pkgs.gnome.geary;
-      programs.gnome-disks.enable = notExcluded pkgs.gnome.gnome-disk-utility;
-      programs.seahorse.enable = notExcluded pkgs.gnome.seahorse;
-      services.gnome.sushi.enable = notExcluded pkgs.gnome.sushi;
+      programs.evince.enable = notExcluded pkgs.evince;
+      programs.file-roller.enable = notExcluded pkgs.file-roller;
+      programs.geary.enable = notExcluded pkgs.geary;
+      programs.gnome-disks.enable = notExcluded pkgs.gnome-disk-utility;
+      programs.seahorse.enable = notExcluded pkgs.seahorse;
+      services.gnome.sushi.enable = notExcluded pkgs.sushi;
 
       # VTE shell integration for gnome-console
       programs.bash.vteIntegration = mkDefault true;
@@ -482,9 +482,9 @@ in
 
     # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/3.38.0/elements/core/meta-gnome-core-developer-tools.bst
     (lib.mkIf serviceCfg.core-developer-tools.enable {
-      environment.systemPackages = with pkgs.gnome; utils.removePackagesByName [
-        dconf-editor
-        devhelp
+      environment.systemPackages = utils.removePackagesByName [
+        pkgs.dconf-editor
+        pkgs.devhelp
         pkgs.gnome-builder
         # boxes would make sense in this option, however
         # it doesn't function well enough to be included
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index 0e9a06706d4f6..01bf3aad202ad 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -44,7 +44,7 @@ in
       sessionPath = mkOption {
         default = [];
         type = types.listOf types.package;
-        example = literalExpression "[ pkgs.gnome.gpaste ]";
+        example = literalExpression "[ pkgs.gpaste ]";
         description = ''
           Additional list of packages to be added to the session search path.
           Useful for GSettings-conditional autostart.
@@ -207,7 +207,7 @@ in
         desktop-file-utils
         glib # for gsettings program
         gnome-menus
-        gnome.adwaita-icon-theme
+        adwaita-icon-theme
         gtk3.out # for gtk-launch program
         onboard
         orca # elementary/greeter#668
@@ -284,11 +284,11 @@ in
     })
 
     (mkIf serviceCfg.apps.enable {
-      programs.evince.enable = mkDefault (notExcluded pkgs.gnome.evince);
-      programs.file-roller.enable = mkDefault (notExcluded pkgs.gnome.file-roller);
+      programs.evince.enable = mkDefault (notExcluded pkgs.evince);
+      programs.file-roller.enable = mkDefault (notExcluded pkgs.file-roller);
 
       environment.systemPackages = utils.removePackagesByName ([
-        pkgs.gnome.gnome-font-viewer
+        pkgs.gnome-font-viewer
       ] ++ (with pkgs.pantheon; [
         elementary-calculator
         elementary-calendar
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index aee2f5b35db2e..98d3555ccbc5e 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -84,8 +84,8 @@ in
       glib # for gsettings
       gtk3.out # gtk-update-icon-cache
 
-      gnome.gnome-themes-extra
-      gnome.adwaita-icon-theme
+      gnome-themes-extra
+      adwaita-icon-theme
       hicolor-icon-theme
       tango-icon-theme
       xfce4-icon-theme
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index 51ab08e74f864..1a39b365db5f3 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -6,6 +6,7 @@ let
 
   cfg = config.services.xserver.displayManager;
   gdm = pkgs.gnome.gdm;
+  pamCfg = config.security.pam.services;
   settingsFormat = pkgs.formats.ini { };
   configFile = settingsFormat.generate "custom.conf" cfg.gdm.settings;
 
@@ -155,7 +156,7 @@ in
             gdm # for gnome-login.session
             config.services.displayManager.sessionData.desktops
             pkgs.gnome.gnome-control-center # for accessibility icon
-            pkgs.gnome.adwaita-icon-theme
+            pkgs.adwaita-icon-theme
             pkgs.hicolor-icon-theme # empty icon theme as a base
           ];
         } // optionalAttrs (xSessionWrapper != null) {
@@ -183,7 +184,7 @@ in
 
     # Otherwise GDM will not be able to start correctly and display Wayland sessions
     systemd.packages = with pkgs.gnome; [ gdm gnome-session gnome-shell ];
-    environment.systemPackages = [ pkgs.gnome.adwaita-icon-theme ];
+    environment.systemPackages = [ pkgs.adwaita-icon-theme ];
 
     # We dont use the upstream gdm service
     # it has to be disabled since the gdm package has it
@@ -321,15 +322,20 @@ in
         session   include       login
       '';
 
+      # This would block password prompt when included by gdm-password.
+      # GDM will instead run gdm-fingerprint in parallel.
       login.fprintAuth = mkIf config.services.fprintd.enable false;
+
       gdm-fingerprint.text = mkIf config.services.fprintd.enable ''
         auth       required                    pam_shells.so
         auth       requisite                   pam_nologin.so
         auth       requisite                   pam_faillock.so      preauth
         auth       required                    ${pkgs.fprintd}/lib/security/pam_fprintd.so
-        auth       optional                    pam_permit.so
         auth       required                    pam_env.so
-        auth       [success=ok default=1]      ${pkgs.gnome.gdm}/lib/security/pam_gdm.so
+        ${lib.optionalString pamCfg.login.enableGnomeKeyring ''
+          auth       [success=ok default=1]      ${pkgs.gnome.gdm}/lib/security/pam_gdm.so
+          auth       optional                    ${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so
+        ''}
 
         account    include                     login
 
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix
index 930ee96b384d5..8975d6fb9f0f7 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix
@@ -34,8 +34,8 @@ in {
       theme = {
         package = mkOption {
           type = types.package;
-          default = pkgs.gnome.gnome-themes-extra;
-          defaultText = literalExpression "pkgs.gnome.gnome-themes-extra";
+          default = pkgs.gnome-themes-extra;
+          defaultText = literalExpression "pkgs.gnome-themes-extra";
           description = ''
             The package path that contains the theme given in the name option.
           '';
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
index 30940da103a96..0907aeb839ba3 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
@@ -47,8 +47,8 @@ in
 
         package = mkOption {
           type = types.package;
-          default = pkgs.gnome.gnome-themes-extra;
-          defaultText = literalExpression "pkgs.gnome.gnome-themes-extra";
+          default = pkgs.gnome-themes-extra;
+          defaultText = literalExpression "pkgs.gnome-themes-extra";
           description = ''
             The package path that contains the theme given in the name option.
           '';
@@ -68,8 +68,8 @@ in
 
         package = mkOption {
           type = types.package;
-          default = pkgs.gnome.adwaita-icon-theme;
-          defaultText = literalExpression "pkgs.gnome.adwaita-icon-theme";
+          default = pkgs.adwaita-icon-theme;
+          defaultText = literalExpression "pkgs.adwaita-icon-theme";
           description = ''
             The package path that contains the icon theme given in the name option.
           '';
@@ -89,8 +89,8 @@ in
 
         package = mkOption {
           type = types.package;
-          default = pkgs.gnome.adwaita-icon-theme;
-          defaultText = literalExpression "pkgs.gnome.adwaita-icon-theme";
+          default = pkgs.adwaita-icon-theme;
+          defaultText = literalExpression "pkgs.adwaita-icon-theme";
           description = ''
             The package path that contains the cursor theme given in the name option.
           '';
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/slick.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/slick.nix
index 299d3bae5f06f..d20b26491aee1 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/slick.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/slick.nix
@@ -33,8 +33,8 @@ in
       theme = {
         package = mkOption {
           type = types.package;
-          default = pkgs.gnome.gnome-themes-extra;
-          defaultText = literalExpression "pkgs.gnome.gnome-themes-extra";
+          default = pkgs.gnome-themes-extra;
+          defaultText = literalExpression "pkgs.gnome-themes-extra";
           description = ''
             The package path that contains the theme given in the name option.
           '';
@@ -52,8 +52,8 @@ in
       iconTheme = {
         package = mkOption {
           type = types.package;
-          default = pkgs.gnome.adwaita-icon-theme;
-          defaultText = literalExpression "pkgs.gnome.adwaita-icon-theme";
+          default = pkgs.adwaita-icon-theme;
+          defaultText = literalExpression "pkgs.adwaita-icon-theme";
           description = ''
             The package path that contains the icon theme given in the name option.
           '';
@@ -90,8 +90,8 @@ in
       cursorTheme = {
         package = mkOption {
           type = types.package;
-          default = pkgs.gnome.adwaita-icon-theme;
-          defaultText = literalExpression "pkgs.gnome.adwaita-icon-theme";
+          default = pkgs.adwaita-icon-theme;
+          defaultText = literalExpression "pkgs.adwaita-icon-theme";
           description = ''
             The package path that contains the cursor theme given in the name option.
           '';
diff --git a/nixos/modules/services/x11/window-managers/herbstluftwm.nix b/nixos/modules/services/x11/window-managers/herbstluftwm.nix
index 7edaf4e980ec4..94c9f4aa91c8f 100644
--- a/nixos/modules/services/x11/window-managers/herbstluftwm.nix
+++ b/nixos/modules/services/x11/window-managers/herbstluftwm.nix
@@ -33,7 +33,10 @@ in
             (cfg.configFile != null)
             ''-c "${cfg.configFile}"''
             ;
-        in "${cfg.package}/bin/herbstluftwm ${configFileClause} &";
+        in ''
+          ${cfg.package}/bin/herbstluftwm ${configFileClause} &
+          waitPID=$!
+        '';
     };
     environment.systemPackages = [ cfg.package ];
   };
diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix
index cbeec4588f593..650ce593e945b 100644
--- a/nixos/modules/system/boot/initrd-ssh.nix
+++ b/nixos/modules/system/boot/initrd-ssh.nix
@@ -166,6 +166,10 @@ in
         UseDNS no
       ''}
 
+      ${optionalString (!config.boot.initrd.systemd.enable) ''
+        SshdSessionPath /bin/sshd-session
+      ''}
+
       ${cfg.extraConfig}
     '';
   in mkIf enabled {
@@ -191,6 +195,7 @@ in
 
     boot.initrd.extraUtilsCommands = mkIf (!config.boot.initrd.systemd.enable) ''
       copy_bin_and_libs ${package}/bin/sshd
+      copy_bin_and_libs ${package}/libexec/sshd-session
       cp -pv ${pkgs.glibc.out}/lib/libnss_files.so.* $out/lib
     '';
 
@@ -265,7 +270,10 @@ in
             config.boot.initrd.network.ssh.authorizedKeys ++
             (map (file: lib.fileContents file) config.boot.initrd.network.ssh.authorizedKeyFiles));
       };
-      storePaths = ["${package}/bin/sshd"];
+      storePaths = [
+        "${package}/bin/sshd"
+        "${package}/libexec/sshd-session"
+      ];
 
       services.sshd = {
         description = "SSH Daemon";
diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
index 694d34d1c059a..71ef8695c2d86 100644
--- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
+++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
@@ -12,7 +12,7 @@ import subprocess
 import sys
 import warnings
 import json
-from typing import NamedTuple, Dict, List
+from typing import NamedTuple, Any
 from dataclasses import dataclass
 
 # These values will be replaced with actual values during the package build
@@ -21,7 +21,7 @@ BOOT_MOUNT_POINT = "@bootMountPoint@"
 LOADER_CONF = f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf"  # Always stored on the ESP
 NIXOS_DIR = "@nixosDir@"
 TIMEOUT = "@timeout@"
-EDITOR = "@editor@" == "1"
+EDITOR = "@editor@" == "1" # noqa: PLR0133
 CONSOLE_MODE = "@consoleMode@"
 BOOTSPEC_TOOLS = "@bootspecTools@"
 DISTRO_NAME = "@distroName@"
@@ -38,17 +38,22 @@ class BootSpec:
     init: str
     initrd: str
     kernel: str
-    kernelParams: List[str]
+    kernelParams: list[str]  # noqa: N815
     label: str
     system: str
     toplevel: str
-    specialisations: Dict[str, "BootSpec"]
-    sortKey: str
-    initrdSecrets: str | None = None
+    specialisations: dict[str, "BootSpec"]
+    sortKey: str  # noqa: N815
+    initrdSecrets: str | None = None  # noqa: N815
 
 
 libc = ctypes.CDLL("libc.so.6")
 
+FILE = None | int
+
+def run(cmd: list[str], stdout: FILE = None) -> subprocess.CompletedProcess[str]:
+    return subprocess.run(cmd, check=True, text=True, stdout=stdout)
+
 class SystemIdentifier(NamedTuple):
     profile: str | None
     generation: int
@@ -112,17 +117,20 @@ def get_bootspec(profile: str | None, generation: int) -> BootSpec:
         boot_json_f = open(boot_json_path, 'r')
         bootspec_json = json.load(boot_json_f)
     else:
-        boot_json_str = subprocess.check_output([
-        f"{BOOTSPEC_TOOLS}/bin/synthesize",
-        "--version",
-        "1",
-        system_directory,
-        "/dev/stdout"],
-        universal_newlines=True)
+        boot_json_str = run(
+            [
+                f"{BOOTSPEC_TOOLS}/bin/synthesize",
+                "--version",
+                "1",
+                system_directory,
+                "/dev/stdout",
+            ],
+            stdout=subprocess.PIPE,
+        ).stdout
         bootspec_json = json.loads(boot_json_str)
     return bootspec_from_json(bootspec_json)
 
-def bootspec_from_json(bootspec_json: Dict) -> BootSpec:
+def bootspec_from_json(bootspec_json: dict[str, Any]) -> BootSpec:
     specialisations = bootspec_json['org.nixos.specialisation.v1']
     specialisations = {k: bootspec_from_json(v) for k, v in specialisations.items()}
     systemdBootExtension = bootspec_json.get('org.nixos.systemd-boot', {})
@@ -157,7 +165,7 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None
 
     try:
         if bootspec.initrdSecrets is not None:
-            subprocess.check_call([bootspec.initrdSecrets, f"{BOOT_MOUNT_POINT}%s" % (initrd)])
+            run([bootspec.initrdSecrets, f"{BOOT_MOUNT_POINT}%s" % (initrd)])
     except subprocess.CalledProcessError:
         if current:
             print("failed to create initrd secrets!", file=sys.stderr)
@@ -192,13 +200,17 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None
 
 
 def get_generations(profile: str | None = None) -> list[SystemIdentifier]:
-    gen_list = subprocess.check_output([
-        f"{NIX}/bin/nix-env",
-        "--list-generations",
-        "-p",
-        "/nix/var/nix/profiles/%s" % ("system-profiles/" + profile if profile else "system")],
-        universal_newlines=True)
-    gen_lines = gen_list.split('\n')
+    gen_list = run(
+        [
+            f"{NIX}/bin/nix-env",
+            "--list-generations",
+            "-p",
+            "/nix/var/nix/profiles/%s"
+            % ("system-profiles/" + profile if profile else "system"),
+        ],
+        stdout=subprocess.PIPE,
+    ).stdout
+    gen_lines = gen_list.split("\n")
     gen_lines.pop()
 
     configurationLimit = CONFIGURATION_LIMIT
@@ -214,8 +226,8 @@ def get_generations(profile: str | None = None) -> list[SystemIdentifier]:
 
 
 def remove_old_entries(gens: list[SystemIdentifier]) -> None:
-    rex_profile = re.compile(r"^" + re.escape(BOOT_MOUNT_POINT) + "/loader/entries/nixos-(.*)-generation-.*\.conf$")
-    rex_generation = re.compile(r"^" + re.escape(BOOT_MOUNT_POINT) + "/loader/entries/nixos.*-generation-([0-9]+)(-specialisation-.*)?\.conf$")
+    rex_profile = re.compile(r"^" + re.escape(BOOT_MOUNT_POINT) + r"/loader/entries/nixos-(.*)-generation-.*\.conf$")
+    rex_generation = re.compile(r"^" + re.escape(BOOT_MOUNT_POINT) + r"/loader/entries/nixos.*-generation-([0-9]+)(-specialisation-.*)?\.conf$")
     known_paths = []
     for gen in gens:
         bootspec = get_bootspec(gen.profile, gen.generation)
@@ -230,10 +242,10 @@ def remove_old_entries(gens: list[SystemIdentifier]) -> None:
             gen_number = int(rex_generation.sub(r"\1", path))
         except ValueError:
             continue
-        if not (prof, gen_number, None) in gens:
+        if (prof, gen_number, None) not in gens:
             os.unlink(path)
     for path in glob.iglob(f"{BOOT_MOUNT_POINT}/{NIXOS_DIR}/*"):
-        if not path in known_paths and not os.path.isdir(path):
+        if path not in known_paths and not os.path.isdir(path):
             os.unlink(path)
 
 
@@ -263,9 +275,7 @@ def install_bootloader(args: argparse.Namespace) -> None:
         # be there on newly installed systems, so let's generate one so that
         # bootctl can find it and we can also pass it to write_entry() later.
         cmd = [f"{SYSTEMD}/bin/systemd-machine-id-setup", "--print"]
-        machine_id = subprocess.run(
-          cmd, text=True, check=True, stdout=subprocess.PIPE
-        ).stdout.rstrip()
+        machine_id = run(cmd, stdout=subprocess.PIPE).stdout.rstrip()
 
     if os.getenv("NIXOS_INSTALL_GRUB") == "1":
         warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning)
@@ -288,11 +298,20 @@ def install_bootloader(args: argparse.Namespace) -> None:
         if os.path.exists(LOADER_CONF):
             os.unlink(LOADER_CONF)
 
-        subprocess.check_call([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"] + bootctl_flags + ["install"])
+        run(
+            [f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"]
+            + bootctl_flags
+            + ["install"]
+        )
     else:
         # Update bootloader to latest if needed
-        available_out = subprocess.check_output([f"{SYSTEMD}/bin/bootctl", "--version"], universal_newlines=True).split()[2]
-        installed_out = subprocess.check_output([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}", "status"], universal_newlines=True)
+        available_out = run(
+            [f"{SYSTEMD}/bin/bootctl", "--version"], stdout=subprocess.PIPE
+        ).stdout.split()[2]
+        installed_out = run(
+            [f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}", "status"],
+            stdout=subprocess.PIPE,
+        ).stdout
 
         # See status_binaries() in systemd bootctl.c for code which generates this
         installed_match = re.search(r"^\W+File:.*/EFI/(?:BOOT|systemd)/.*\.efi \(systemd-boot ([\d.]+[^)]*)\)$",
@@ -311,7 +330,11 @@ def install_bootloader(args: argparse.Namespace) -> None:
 
         if installed_version < available_version:
             print("updating systemd-boot from %s to %s" % (installed_version, available_version))
-            subprocess.check_call([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"] + bootctl_flags + ["update"])
+            run(
+                [f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"]
+                + bootctl_flags
+                + ["update"]
+            )
 
     os.makedirs(f"{BOOT_MOUNT_POINT}/{NIXOS_DIR}", exist_ok=True)
     os.makedirs(f"{BOOT_MOUNT_POINT}/loader/entries", exist_ok=True)
@@ -362,7 +385,7 @@ def install_bootloader(args: argparse.Namespace) -> None:
 
     os.makedirs(f"{BOOT_MOUNT_POINT}/{NIXOS_DIR}/.extra-files", exist_ok=True)
 
-    subprocess.check_call(COPY_EXTRA_FILES)
+    run([COPY_EXTRA_FILES])
 
 
 def main() -> None:
@@ -370,7 +393,7 @@ def main() -> None:
     parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help=f"The default {DISTRO_NAME} config to boot")
     args = parser.parse_args()
 
-    subprocess.check_call(CHECK_MOUNTPOINTS)
+    run([CHECK_MOUNTPOINTS])
 
     try:
         install_bootloader(args)
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index 761bbe6e03d4a..8ecc6cfe8b4bb 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -119,10 +119,12 @@ let
           "VNetHeader"
           "User"
           "Group"
+          "KeepCarrier"
         ])
         (assertValueOneOf "MultiQueue" boolValues)
         (assertValueOneOf "PacketInfo" boolValues)
         (assertValueOneOf "VNetHeader" boolValues)
+        (assertValueOneOf "KeepCarrier" boolValues)
       ];
 
       # See https://www.freedesktop.org/software/systemd/man/latest/systemd.netdev.html#%5BIPVTAP%5D%20Section%20Options
@@ -632,6 +634,7 @@ let
           "LinkLocalAddressing"
           "IPv6LinkLocalAddressGenerationMode"
           "IPv6StableSecretAddress"
+          "IPv4LLStartAddress"
           "IPv4LLRoute"
           "DefaultRouteOnDevice"
           "LLMNR"
@@ -654,12 +657,16 @@ let
           "IPv6AcceptRA"
           "IPv6DuplicateAddressDetection"
           "IPv6HopLimit"
+          "IPv4ReversePathFilter"
+          "IPv4AcceptLocal"
+          "IPv4RouteLocalnet"
           "IPv4ProxyARP"
           "IPv6ProxyNDP"
           "IPv6ProxyNDPAddress"
           "IPv6SendRA"
           "DHCPPrefixDelegation"
           "IPv6MTUBytes"
+          "KeepMaster"
           "Bridge"
           "Bond"
           "VRF"
@@ -701,11 +708,15 @@ let
         (assertMinimum "IPv6DuplicateAddressDetection" 0)
         (assertInt "IPv6HopLimit")
         (assertMinimum "IPv6HopLimit" 0)
+        (assertValueOneOf "IPv4ReversePathFilter" ["no" "strict" "loose"])
+        (assertValueOneOf "IPv4AcceptLocal" boolValues)
+        (assertValueOneOf "IPv4RouteLocalnet" boolValues)
         (assertValueOneOf "IPv4ProxyARP" boolValues)
         (assertValueOneOf "IPv6ProxyNDP" boolValues)
         (assertValueOneOf "IPv6SendRA" boolValues)
         (assertValueOneOf "DHCPPrefixDelegation" boolValues)
         (assertByteFormat "IPv6MTUBytes")
+        (assertValueOneOf "KeepMaster" boolValues)
         (assertValueOneOf "ActiveSlave" boolValues)
         (assertValueOneOf "PrimarySlave" boolValues)
         (assertValueOneOf "ConfigureWithoutCarrier" boolValues)
diff --git a/nixos/modules/system/boot/systemd/journald.nix b/nixos/modules/system/boot/systemd/journald.nix
index f9f05d2b08f41..586de87dbc8ea 100644
--- a/nixos/modules/system/boot/systemd/journald.nix
+++ b/nixos/modules/system/boot/systemd/journald.nix
@@ -72,7 +72,7 @@ in {
       type = types.lines;
       example = "Storage=volatile";
       description = ''
-        Extra config options for systemd-journald. See man journald.conf
+        Extra config options for systemd-journald. See {manpage}`journald.conf(5)`
         for available options.
       '';
     };
diff --git a/nixos/modules/virtualisation/ec2-data.nix b/nixos/modules/virtualisation/ec2-data.nix
index 0cc6d9938e220..3414c5a1fc9de 100644
--- a/nixos/modules/virtualisation/ec2-data.nix
+++ b/nixos/modules/virtualisation/ec2-data.nix
@@ -35,9 +35,8 @@ with lib;
                 echo "obtaining SSH key..."
                 mkdir -m 0700 -p /root/.ssh
                 if [ -s /etc/ec2-metadata/public-keys-0-openssh-key ]; then
-                    cat /etc/ec2-metadata/public-keys-0-openssh-key >> /root/.ssh/authorized_keys
+                    (umask 177; cat /etc/ec2-metadata/public-keys-0-openssh-key >> /root/.ssh/authorized_keys)
                     echo "new key added to authorized_keys"
-                    chmod 600 /root/.ssh/authorized_keys
                 fi
             fi
 
diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix
index a34fe132ba7e1..4808652a542ad 100644
--- a/nixos/modules/virtualisation/virtualbox-host.nix
+++ b/nixos/modules/virtualisation/virtualbox-host.nix
@@ -89,7 +89,7 @@ in
         Enable KVM support for VirtualBox. This increases compatibility with Linux kernel versions, because the VirtualBox kernel modules
         are not required.
 
-        This option is incompatible with `enableHardening` and `addNetworkInterface`.
+        This option is incompatible with `addNetworkInterface`.
 
         Note: This is experimental. Please check https://github.com/cyberus-technology/virtualbox-kvm/issues.
       '';
@@ -136,18 +136,6 @@ in
         assertion = !cfg.addNetworkInterface;
         message = "VirtualBox KVM only supports standard NAT networking for VMs. Please turn off virtualisation.virtualbox.host.addNetworkInterface.";
       }
-
-      {
-        assertion = !cfg.enableHardening;
-        message = "VirtualBox KVM is not compatible with hardening: Please turn off virtualisation.virtualbox.host.enableHardening.";
-      }
-    ];
-
-    warnings = [
-      ''
-        KVM support in VirtualBox is experimental. Not all security features are available yet.
-        See: https://github.com/cyberus-technology/virtualbox-kvm/issues/12
-      ''
     ];
   }) (mkIf (!cfg.enableKvm) {
     boot.kernelModules = [ "vboxdrv" "vboxnetadp" "vboxnetflt" ];