about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/configuration/file-systems.chapter.md1
-rw-r--r--nixos/doc/manual/configuration/overlayfs.section.md27
-rw-r--r--nixos/doc/manual/development/option-types.section.md2
-rw-r--r--nixos/doc/manual/installation/building-images-via-systemd-repart.chapter.md17
-rw-r--r--nixos/doc/manual/release-notes/rl-2405.section.md29
-rw-r--r--nixos/maintainers/scripts/ec2/README.md7
-rw-r--r--nixos/maintainers/scripts/ec2/amazon-image.nix2
-rw-r--r--nixos/modules/config/no-x-libs.nix1
-rw-r--r--nixos/modules/misc/version.nix146
-rw-r--r--nixos/modules/module-list.nix7
-rw-r--r--nixos/modules/programs/tsm-client.nix2
-rw-r--r--nixos/modules/security/acme/default.nix12
-rw-r--r--nixos/modules/security/pam.nix15
-rw-r--r--nixos/modules/security/pam_usb.nix51
-rw-r--r--nixos/modules/services/amqp/rabbitmq.nix21
-rw-r--r--nixos/modules/services/backup/tsm.nix2
-rw-r--r--nixos/modules/services/cluster/kubernetes/pki.nix9
-rw-r--r--nixos/modules/services/continuous-integration/github-runner/service.nix3
-rw-r--r--nixos/modules/services/databases/etcd.nix (renamed from nixos/modules/services/misc/etcd.nix)25
-rw-r--r--nixos/modules/services/databases/neo4j.nix77
-rw-r--r--nixos/modules/services/games/archisteamfarm.nix11
-rw-r--r--nixos/modules/services/hardware/fwupd.nix23
-rw-r--r--nixos/modules/services/hardware/pcscd.nix6
-rw-r--r--nixos/modules/services/home-automation/govee2mqtt.nix90
-rw-r--r--nixos/modules/services/home-automation/zigbee2mqtt.nix1
-rw-r--r--nixos/modules/services/matrix/synapse.md5
-rw-r--r--nixos/modules/services/matrix/synapse.nix166
-rw-r--r--nixos/modules/services/misc/gitlab.nix14
-rw-r--r--nixos/modules/services/misc/nix-gc.nix3
-rw-r--r--nixos/modules/services/networking/cloudflared.nix7
-rw-r--r--nixos/modules/services/networking/dhcpcd.nix2
-rw-r--r--nixos/modules/services/networking/hostapd.nix2
-rw-r--r--nixos/modules/services/networking/jibri/default.nix15
-rw-r--r--nixos/modules/services/networking/jicofo.nix15
-rw-r--r--nixos/modules/services/networking/jitsi-videobridge.nix15
-rw-r--r--nixos/modules/services/networking/murmur.nix23
-rw-r--r--nixos/modules/services/networking/nftables.nix7
-rw-r--r--nixos/modules/services/security/intune.nix32
-rw-r--r--nixos/modules/services/security/kanidm.nix15
-rw-r--r--nixos/modules/services/video/frigate.nix135
-rw-r--r--nixos/modules/services/web-apps/photoprism.nix2
-rw-r--r--nixos/modules/services/web-apps/suwayomi-server.nix55
-rw-r--r--nixos/modules/services/web-apps/tt-rss.nix19
-rw-r--r--nixos/modules/services/web-apps/youtrack.nix4
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/phosh.nix15
-rw-r--r--nixos/modules/system/boot/systemd/journald.nix4
-rw-r--r--nixos/modules/system/boot/systemd/sysupdate.nix4
-rw-r--r--nixos/modules/system/boot/uki.nix16
-rw-r--r--nixos/modules/tasks/filesystems/overlayfs.nix144
-rw-r--r--nixos/modules/virtualisation/amazon-image.nix1
-rw-r--r--nixos/modules/virtualisation/amazon-init.nix1
-rw-r--r--nixos/modules/virtualisation/libvirtd.nix1
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix22
-rw-r--r--nixos/tests/all-tests.nix3
-rw-r--r--nixos/tests/ayatana-indicators.nix1
-rw-r--r--nixos/tests/filesystems-overlayfs.nix89
-rw-r--r--nixos/tests/freetube.nix2
-rw-r--r--nixos/tests/frigate.nix9
-rw-r--r--nixos/tests/gitlab.nix2
-rw-r--r--nixos/tests/incus/lxd-to-incus.nix2
-rw-r--r--nixos/tests/installed-tests/fwupd.nix9
-rw-r--r--nixos/tests/intune.nix56
-rw-r--r--nixos/tests/kernel-generic.nix2
-rw-r--r--nixos/tests/systemd-sysupdate.nix14
-rw-r--r--nixos/tests/tsm-client-gui.nix2
-rw-r--r--nixos/tests/urn-timer.nix26
67 files changed, 1119 insertions, 431 deletions
diff --git a/nixos/doc/manual/configuration/file-systems.chapter.md b/nixos/doc/manual/configuration/file-systems.chapter.md
index aca978be064d..3dfdd20ac33e 100644
--- a/nixos/doc/manual/configuration/file-systems.chapter.md
+++ b/nixos/doc/manual/configuration/file-systems.chapter.md
@@ -39,4 +39,5 @@ and non-critical by adding `options = [ "nofail" ];`.
 ```{=include=} sections
 luks-file-systems.section.md
 sshfs-file-systems.section.md
+overlayfs.section.md
 ```
diff --git a/nixos/doc/manual/configuration/overlayfs.section.md b/nixos/doc/manual/configuration/overlayfs.section.md
new file mode 100644
index 000000000000..592fb7c2e6f7
--- /dev/null
+++ b/nixos/doc/manual/configuration/overlayfs.section.md
@@ -0,0 +1,27 @@
+# Overlayfs {#sec-overlayfs}
+
+NixOS offers a convenient abstraction to create both read-only as well writable
+overlays.
+
+```nix
+fileSystems = {
+  "/writable-overlay" = {
+    overlay = {
+      lowerdir = [ writableOverlayLowerdir ];
+      upperdir = "/.rw-writable-overlay/upper";
+      workdir = "/.rw-writable-overlay/work";
+    };
+    # Mount the writable overlay in the initrd.
+    neededForBoot = true;
+  };
+  "/readonly-overlay".overlay.lowerdir = [
+    writableOverlayLowerdir
+    writableOverlayLowerdir2
+  ];
+};
+```
+
+If `upperdir` and `workdir` are not null, they will be created before the
+overlay is mounted.
+
+To mount an overlay as read-only, you need to provide at least two `lowerdir`s.
diff --git a/nixos/doc/manual/development/option-types.section.md b/nixos/doc/manual/development/option-types.section.md
index f9c7ac80018e..04edf99e70b0 100644
--- a/nixos/doc/manual/development/option-types.section.md
+++ b/nixos/doc/manual/development/option-types.section.md
@@ -326,7 +326,7 @@ Composed types are types that take a type as parameter. `listOf
 `types.uniq` *`t`*
 
 :   Ensures that type *`t`* cannot be merged. It is used to ensure option
-    definitions are declared only once.
+    definitions are provided only once.
 
 `types.unique` `{ message = m }` *`t`*
 
diff --git a/nixos/doc/manual/installation/building-images-via-systemd-repart.chapter.md b/nixos/doc/manual/installation/building-images-via-systemd-repart.chapter.md
index 6d0675f21a03..10bee156d113 100644
--- a/nixos/doc/manual/installation/building-images-via-systemd-repart.chapter.md
+++ b/nixos/doc/manual/installation/building-images-via-systemd-repart.chapter.md
@@ -75,9 +75,10 @@ image with a new one or by updating partitions via an A/B scheme. See the
 [Chrome OS update process][chrome-os-update] for an example of how to achieve
 this. The appliance image built in the following example does not contain a
 `configuration.nix` and thus you will not be able to call `nixos-rebuild` from
-this system.
+this system. Furthermore, it uses a [Unified Kernel Image][unified-kernel-image].
 
 [chrome-os-update]: https://chromium.googlesource.com/aosp/platform/system/update_engine/+/HEAD/README.md
+[unified-kernel-image]: https://uapi-group.org/specifications/specs/unified_kernel_image/
 
 ```nix
 let
@@ -101,18 +102,8 @@ in
             "/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source =
               "${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
 
-            "/loader/entries/nixos.conf".source = pkgs.writeText "nixos.conf" ''
-              title NixOS
-              linux /EFI/nixos/kernel.efi
-              initrd /EFI/nixos/initrd.efi
-              options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}
-            '';
-
-            "/EFI/nixos/kernel.efi".source =
-              "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}";
-
-            "/EFI/nixos/initrd.efi".source =
-              "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
+            "/EFI/Linux/${config.system.boot.loader.ukiFile}".source =
+              "${config.system.build.uki}/${config.system.boot.loader.ukiFile}";
           };
           repartConfig = {
             Type = "esp";
diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md
index 06c3e1949b70..05c06ebcac1b 100644
--- a/nixos/doc/manual/release-notes/rl-2405.section.md
+++ b/nixos/doc/manual/release-notes/rl-2405.section.md
@@ -8,6 +8,10 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
 
+- `cryptsetup` has been upgraded from 2.6.1 to 2.7.0. Cryptsetup is a critical component enabling LUKS-based (but not only) full disk encryption.
+  Take the time to review [the release notes](https://gitlab.com/cryptsetup/cryptsetup/-/raw/v2.7.0/docs/v2.7.0-ReleaseNotes).
+  One of the highlight is that it is now possible to use hardware OPAL-based encryption of your disk with `cryptsetup`, it has a lot of caveats, see the above notes for the full details.
+
 - `screen`'s module has been cleaned, and will now require you to set `programs.screen.enable` in order to populate `screenrc` and add the program to the environment.
 
 - `linuxPackages_testing_bcachefs` is now fully deprecated by `linuxPackages_latest`, and is therefore no longer available.
@@ -93,6 +97,10 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - `idris2` was updated to v0.7.0. This version introduces breaking changes. Check out the [changelog](https://github.com/idris-lang/Idris2/blob/v0.7.0/CHANGELOG.md#v070) for details.
 
+- `neo4j` has been updated to 5, you may want to read the [release notes for Neo4j 5](https://neo4j.com/release-notes/database/neo4j-5/)
+
+- `services.neo4j.allowUpgrade` was removed and no longer has any effect. Neo4j 5 supports automatic rolling upgrades.
+
 - `nitter` requires a `guest_accounts.jsonl` to be provided as a path or loaded into the default location at `/var/lib/nitter/guest_accounts.jsonl`. See [Guest Account Branch Deployment](https://github.com/zedeus/nitter/wiki/Guest-Account-Branch-Deployment) for details.
 
 - `services.aria2.rpcSecret` has been replaced with `services.aria2.rpcSecretFile`.
@@ -134,6 +142,9 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
     '';
 
   ```
+
+- The package `optparse-bash` is now dropped due to upstream inactivity. Alternatives available in Nixpkgs include [`argc`](https://github.com/sigoden/argc), [`argbash`](https://github.com/matejak/argbash), [`bashly`](https://github.com/DannyBen/bashly) and [`gum`](https://github.com/charmbracelet/gum), to name a few.
+
 - The `kanata` package has been updated to v1.5.0, which includes [breaking changes](https://github.com/jtroo/kanata/releases/tag/v1.5.0).
 
 - The `craftos-pc` package has been updated to v2.8, which includes [breaking changes](https://github.com/MCJack123/craftos2/releases/tag/v2.8).
@@ -239,6 +250,9 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 - `services.postgresql.extraPlugins` changed its type from just a list of packages to also a function that returns such a list.
   For example a config line like ``services.postgresql.extraPlugins = with pkgs.postgresql_11.pkgs; [ postgis ];`` is recommended to be changed to ``services.postgresql.extraPlugins = ps: with ps; [ postgis ];``;
 
+- The Matrix homeserver [Synapse](https://element-hq.github.io/synapse/) module now supports configuring UNIX domain socket [listeners](#opt-services.matrix-synapse.settings.listeners) through the `path` option.
+  The default replication worker on the main instance has been migrated away from TCP sockets to UNIX domain sockets.
+
 - Programs written in [Nim](https://nim-lang.org/) are built with libraries selected by lockfiles.
   The `nimPackages` and `nim2Packages` sets have been removed.
   See https://nixos.org/manual/nixpkgs/unstable#nim for more information.
@@ -248,6 +262,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
   After upgrading, follow the instructions on the [upstream release notes](https://github.com/majewsky/portunus/releases/tag/v2.0.0) to upgrade all user accounts to strong password hashes.
   Support for weak password hashes will be removed in NixOS 24.11.
 
+- A stdenv's default set of hardening flags can now be set via its `bintools-wrapper`'s `defaultHardeningFlags` argument. A convenient stdenv adapter, `withDefaultHardeningFlags`, can be used to override an existing stdenv's `defaultHardeningFlags`.
+
 - `libass` now uses the native CoreText backend on Darwin, which may fix subtitle rendering issues with `mpv`, `ffmpeg`, etc.
 
 - [Lilypond](https://lilypond.org/index.html) and [Denemo](https://www.denemo.org) are now compiled with Guile 3.0.
@@ -265,11 +281,20 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 - The option [`services.nextcloud.config.dbport`] of the Nextcloud module was removed to match upstream.
   The port can be specified in [`services.nextcloud.config.dbhost`](#opt-services.nextcloud.config.dbhost).
 
+- A new abstraction to create both read-only as well as writable overlay file
+  systems was added. Available via
+  [fileSystems.overlay](#opt-fileSystems._name_.overlay.lowerdir). See also the
+  [NixOS docs](#sec-overlayfs).
+
 - `stdenv`: The `--replace` flag in `substitute`, `substituteInPlace`, `substituteAll`, `substituteAllStream`, and `substituteStream` is now deprecated if favor of the new `--replace-fail`, `--replace-warn` and `--replace-quiet`. The deprecated `--replace` equates to `--replace-warn`.
 
+- A new hardening flag, `zerocallusedregs` was made available, corresponding to the gcc/clang option `-fzero-call-used-regs=used-gpr`.
+
 - New options were added to the dnsdist module to enable and configure a DNSCrypt endpoint (see `services.dnsdist.dnscrypt.enable`, etc.).
   The module can generate the DNSCrypt provider key pair, certificates and also performs their rotation automatically with no downtime.
 
+- With a bump to `sonarr` v4, existing config database files will be upgraded automatically, but note that some old apparently-working configs [might actually be corrupt and fail to upgrade cleanly](https://forums.sonarr.tv/t/sonarr-v4-released/33089).
+
 - The Yama LSM is now enabled by default in the kernel, which prevents ptracing
   non-child processes. This means you will not be able to attach gdb to an
   existing process, but will need to start that process from gdb (so it is a
@@ -281,6 +306,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
   `globalRedirect` can now have redirect codes other than 301 through
   `redirectCode`.
 
+- `libjxl` 0.9.0 [dropped support for the butteraugli API](https://github.com/libjxl/libjxl/pull/2576). You will no longer be able to set `enableButteraugli` on `libaom`.
+
 - The source of the `mockgen` package has changed to the [go.uber.org/mock](https://github.com/uber-go/mock) fork because [the original repository is no longer maintained](https://github.com/golang/mock#gomock).
 
 - `security.pam.enableSSHAgentAuth` was renamed to `security.pam.sshAgentAuth.enable` and an `authorizedKeysFiles`
@@ -289,6 +316,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - [](#opt-boot.kernel.sysctl._net.core.wmem_max_) changed from a string to an integer because of the addition of a custom merge option (taking the highest value defined to avoid conflicts between 2 services trying to set that value), just as [](#opt-boot.kernel.sysctl._net.core.rmem_max_) since 22.11.
 
+- A new top-level package set, `pkgsExtraHardening` is added. This is a set of packages built with stricter hardening flags - those that have not yet received enough testing to be applied universally, those that are more likely to cause build failures or those that have drawbacks to their use (e.g. performance or required hardware features).
+
 - `services.zfs.zed.enableMail` now uses the global `sendmail` wrapper defined by an email module
   (such as msmtp or Postfix). It no longer requires using a special ZFS build with email support.
 
diff --git a/nixos/maintainers/scripts/ec2/README.md b/nixos/maintainers/scripts/ec2/README.md
new file mode 100644
index 000000000000..1328109d464a
--- /dev/null
+++ b/nixos/maintainers/scripts/ec2/README.md
@@ -0,0 +1,7 @@
+# Amazon images
+
+* The `create-amis.sh` script will be replaced by https://github.com/NixOS/amis which will regularly upload AMIs per NixOS channel bump.
+
+* @arianvp is planning to drop zfs support
+* @arianvp is planning to rewrite the image builder to use the repart-based image builder.
+
diff --git a/nixos/maintainers/scripts/ec2/amazon-image.nix b/nixos/maintainers/scripts/ec2/amazon-image.nix
index d12339bca1f8..055d44ba6576 100644
--- a/nixos/maintainers/scripts/ec2/amazon-image.nix
+++ b/nixos/maintainers/scripts/ec2/amazon-image.nix
@@ -157,4 +157,6 @@ in {
       '';
     };
   in if config.ec2.zfs.enable then zfsBuilder else extBuilder;
+
+  meta.maintainers = with maintainers; [ arianvp ];
 }
diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix
index a50a03ce52d4..2f763290e32d 100644
--- a/nixos/modules/config/no-x-libs.nix
+++ b/nixos/modules/config/no-x-libs.nix
@@ -30,6 +30,7 @@ with lib;
       beam = super.beam_nox;
       cairo = super.cairo.override { x11Support = false; };
       dbus = super.dbus.override { x11Support = false; };
+      fastfetch = super.fastfetch.override { vulkanSupport = false; waylandSupport = false; x11Support = false; };
       ffmpeg_4 = super.ffmpeg_4.override { ffmpegVariant = "headless"; };
       ffmpeg_5 = super.ffmpeg_5.override { ffmpegVariant = "headless"; };
       # dep of graphviz, libXpm is optional for Xpm support
diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix
index c929c3b37285..79b95ac654d5 100644
--- a/nixos/modules/misc/version.nix
+++ b/nixos/modules/misc/version.nix
@@ -5,34 +5,39 @@ let
   opt = options.system.nixos;
 
   inherit (lib)
-    concatStringsSep mapAttrsToList toLower
+    concatStringsSep mapAttrsToList toLower optionalString
     literalExpression mkRenamedOptionModule mkDefault mkOption trivial types;
 
   needsEscaping = s: null != builtins.match "[a-zA-Z0-9]+" s;
   escapeIfNecessary = s: if needsEscaping s then s else ''"${lib.escape [ "\$" "\"" "\\" "\`" ] s}"'';
   attrsToText = attrs:
-    concatStringsSep "\n" (
-      mapAttrsToList (n: v: ''${n}=${escapeIfNecessary (toString v)}'') attrs
-    ) + "\n";
-
-  osReleaseContents = {
-    NAME = "${cfg.distroName}";
-    ID = "${cfg.distroId}";
-    VERSION = "${cfg.release} (${cfg.codeName})";
-    VERSION_CODENAME = toLower cfg.codeName;
-    VERSION_ID = cfg.release;
-    BUILD_ID = cfg.version;
-    PRETTY_NAME = "${cfg.distroName} ${cfg.release} (${cfg.codeName})";
-    LOGO = "nix-snowflake";
-    HOME_URL = lib.optionalString (cfg.distroId == "nixos") "https://nixos.org/";
-    DOCUMENTATION_URL = lib.optionalString (cfg.distroId == "nixos") "https://nixos.org/learn.html";
-    SUPPORT_URL = lib.optionalString (cfg.distroId == "nixos") "https://nixos.org/community.html";
-    BUG_REPORT_URL = lib.optionalString (cfg.distroId == "nixos") "https://github.com/NixOS/nixpkgs/issues";
-    IMAGE_ID = lib.optionalString (config.system.image.id != null) config.system.image.id;
-    IMAGE_VERSION = lib.optionalString (config.system.image.version != null) config.system.image.version;
-  } // lib.optionalAttrs (cfg.variant_id != null) {
-    VARIANT_ID = cfg.variant_id;
-  };
+    concatStringsSep "\n"
+      (mapAttrsToList (n: v: ''${n}=${escapeIfNecessary (toString v)}'') attrs)
+    + "\n";
+
+  osReleaseContents =
+    let
+      isNixos = cfg.distroId == "nixos";
+    in
+    {
+      NAME = "${cfg.distroName}";
+      ID = "${cfg.distroId}";
+      VERSION = "${cfg.release} (${cfg.codeName})";
+      VERSION_CODENAME = toLower cfg.codeName;
+      VERSION_ID = cfg.release;
+      BUILD_ID = cfg.version;
+      PRETTY_NAME = "${cfg.distroName} ${cfg.release} (${cfg.codeName})";
+      LOGO = "nix-snowflake";
+      HOME_URL = optionalString isNixos "https://nixos.org/";
+      DOCUMENTATION_URL = optionalString isNixos "https://nixos.org/learn.html";
+      SUPPORT_URL = optionalString isNixos "https://nixos.org/community.html";
+      BUG_REPORT_URL = optionalString isNixos "https://github.com/NixOS/nixpkgs/issues";
+      ANSI_COLOR = optionalString isNixos "1;34";
+      IMAGE_ID = optionalString (config.system.image.id != null) config.system.image.id;
+      IMAGE_VERSION = optionalString (config.system.image.version != null) config.system.image.version;
+    } // lib.optionalAttrs (cfg.variant_id != null) {
+      VARIANT_ID = cfg.variant_id;
+    };
 
   initrdReleaseContents = (removeAttrs osReleaseContents [ "BUILD_ID" ]) // {
     PRETTY_NAME = "${osReleaseContents.PRETTY_NAME} (Initrd)";
@@ -56,60 +61,61 @@ in
   };
 
   options.system = {
+    nixos = {
+      version = mkOption {
+        internal = true;
+        type = types.str;
+        description = lib.mdDoc "The full NixOS version (e.g. `16.03.1160.f2d4ee1`).";
+      };
 
-    nixos.version = mkOption {
-      internal = true;
-      type = types.str;
-      description = lib.mdDoc "The full NixOS version (e.g. `16.03.1160.f2d4ee1`).";
-    };
-
-    nixos.release = mkOption {
-      readOnly = true;
-      type = types.str;
-      default = trivial.release;
-      description = lib.mdDoc "The NixOS release (e.g. `16.03`).";
-    };
+      release = mkOption {
+        readOnly = true;
+        type = types.str;
+        default = trivial.release;
+        description = lib.mdDoc "The NixOS release (e.g. `16.03`).";
+      };
 
-    nixos.versionSuffix = mkOption {
-      internal = true;
-      type = types.str;
-      default = trivial.versionSuffix;
-      description = lib.mdDoc "The NixOS version suffix (e.g. `1160.f2d4ee1`).";
-    };
+      versionSuffix = mkOption {
+        internal = true;
+        type = types.str;
+        default = trivial.versionSuffix;
+        description = lib.mdDoc "The NixOS version suffix (e.g. `1160.f2d4ee1`).";
+      };
 
-    nixos.revision = mkOption {
-      internal = true;
-      type = types.nullOr types.str;
-      default = trivial.revisionWithDefault null;
-      description = lib.mdDoc "The Git revision from which this NixOS configuration was built.";
-    };
+      revision = mkOption {
+        internal = true;
+        type = types.nullOr types.str;
+        default = trivial.revisionWithDefault null;
+        description = lib.mdDoc "The Git revision from which this NixOS configuration was built.";
+      };
 
-    nixos.codeName = mkOption {
-      readOnly = true;
-      type = types.str;
-      default = trivial.codeName;
-      description = lib.mdDoc "The NixOS release code name (e.g. `Emu`).";
-    };
+      codeName = mkOption {
+        readOnly = true;
+        type = types.str;
+        default = trivial.codeName;
+        description = lib.mdDoc "The NixOS release code name (e.g. `Emu`).";
+      };
 
-    nixos.distroId = mkOption {
-      internal = true;
-      type = types.str;
-      default = "nixos";
-      description = lib.mdDoc "The id of the operating system";
-    };
+      distroId = mkOption {
+        internal = true;
+        type = types.str;
+        default = "nixos";
+        description = lib.mdDoc "The id of the operating system";
+      };
 
-    nixos.distroName = mkOption {
-      internal = true;
-      type = types.str;
-      default = "NixOS";
-      description = lib.mdDoc "The name of the operating system";
-    };
+      distroName = mkOption {
+        internal = true;
+        type = types.str;
+        default = "NixOS";
+        description = lib.mdDoc "The name of the operating system";
+      };
 
-    nixos.variant_id = mkOption {
-      type = types.nullOr (types.strMatching "^[a-z0-9._-]+$");
-      default = null;
-      description = lib.mdDoc "A lower-case string identifying a specific variant or edition of the operating system";
-      example = "installer";
+      variant_id = mkOption {
+        type = types.nullOr (types.strMatching "^[a-z0-9._-]+$");
+        default = null;
+        description = lib.mdDoc "A lower-case string identifying a specific variant or edition of the operating system";
+        example = "installer";
+      };
     };
 
     image = {
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 37f822721f48..72b6d42591da 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -219,6 +219,7 @@
   ./programs/msmtp.nix
   ./programs/mtr.nix
   ./programs/nano.nix
+  ./programs/nautilus-open-any-terminal.nix
   ./programs/nbd.nix
   ./programs/neovim.nix
   ./programs/nethoscope.nix
@@ -316,7 +317,6 @@
   ./security/oath.nix
   ./security/pam.nix
   ./security/pam_mount.nix
-  ./security/pam_usb.nix
   ./security/please.nix
   ./security/polkit.nix
   ./security/rngd.nix
@@ -429,6 +429,7 @@
   ./services/databases/couchdb.nix
   ./services/databases/dgraph.nix
   ./services/databases/dragonflydb.nix
+  ./services/databases/etcd.nix
   ./services/databases/ferretdb.nix
   ./services/databases/firebird.nix
   ./services/databases/foundationdb.nix
@@ -577,6 +578,7 @@
   ./services/home-automation/ebusd.nix
   ./services/home-automation/esphome.nix
   ./services/home-automation/evcc.nix
+  ./services/home-automation/govee2mqtt.nix
   ./services/home-automation/home-assistant.nix
   ./services/home-automation/homeassistant-satellite.nix
   ./services/home-automation/zigbee2mqtt.nix
@@ -679,7 +681,6 @@
   ./services/misc/dwm-status.nix
   ./services/misc/dysnomia.nix
   ./services/misc/errbot.nix
-  ./services/misc/etcd.nix
   ./services/misc/etebase-server.nix
   ./services/misc/etesync-dav.nix
   ./services/misc/evdevremapkeys.nix
@@ -1202,6 +1203,7 @@
   ./services/security/hologram-agent.nix
   ./services/security/hologram-server.nix
   ./services/security/infnoise.nix
+  ./services/security/intune.nix
   ./services/security/jitterentropy-rngd.nix
   ./services/security/kanidm.nix
   ./services/security/munge.nix
@@ -1525,6 +1527,7 @@
   ./tasks/filesystems/jfs.nix
   ./tasks/filesystems/nfs.nix
   ./tasks/filesystems/ntfs.nix
+  ./tasks/filesystems/overlayfs.nix
   ./tasks/filesystems/reiserfs.nix
   ./tasks/filesystems/sshfs.nix
   ./tasks/filesystems/squashfs.nix
diff --git a/nixos/modules/programs/tsm-client.nix b/nixos/modules/programs/tsm-client.nix
index 45d436221ee3..d31a1fb3f375 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.20?topic=commands-processing-options
+    # https://www.ibm.com/docs/en/storage-protect/8.1.21?topic=commands-processing-options
     options.servername = mkOption {
       type = servernameType;
       default = name;
diff --git a/nixos/modules/security/acme/default.nix b/nixos/modules/security/acme/default.nix
index 40d9c487996b..19297d267851 100644
--- a/nixos/modules/security/acme/default.nix
+++ b/nixos/modules/security/acme/default.nix
@@ -545,12 +545,14 @@ let
       };
 
       server = mkOption {
-        type = types.nullOr types.str;
-        inherit (defaultAndText "server" null) default defaultText;
+        type = types.str;
+        inherit (defaultAndText "server" "https://acme-v02.api.letsencrypt.org/directory") default defaultText;
+        example = "https://acme-staging-v02.api.letsencrypt.org/directory";
         description = lib.mdDoc ''
-          ACME Directory Resource URI. Defaults to Let's Encrypt's
-          production endpoint,
-          <https://acme-v02.api.letsencrypt.org/directory>, if unset.
+          ACME Directory Resource URI.
+          Defaults to Let's Encrypt's production endpoint.
+          For testing Let's Encrypt's [staging endpoint](https://letsencrypt.org/docs/staging-environment/)
+          should be used to avoid the rather tight rate limit on the production endpoint.
         '';
       };
 
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index ffbb558549f6..ed03254cb5ee 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -205,17 +205,6 @@ let
         };
       };
 
-      usbAuth = mkOption {
-        default = config.security.pam.usb.enable;
-        defaultText = literalExpression "config.security.pam.usb.enable";
-        type = types.bool;
-        description = lib.mdDoc ''
-          If set, users listed in
-          {file}`/etc/pamusb.conf` are able to log in
-          with the associated USB key.
-        '';
-      };
-
       otpwAuth = mkOption {
         default = config.security.pam.enableOTPW;
         defaultText = literalExpression "config.security.pam.enableOTPW";
@@ -665,7 +654,6 @@ let
             authfile = u2f.authFile;
             appid = u2f.appId;
           }; })
-          { name = "usb"; enable = cfg.usbAuth; control = "sufficient"; modulePath = "${pkgs.pam_usb}/lib/security/pam_usb.so"; }
           (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;
@@ -700,6 +688,7 @@ let
               || cfg.pamMount
               || cfg.enableKwallet
               || cfg.enableGnomeKeyring
+              || config.services.intune.enable
               || cfg.googleAuthenticator.enable
               || cfg.gnupg.enable
               || cfg.failDelay.enable
@@ -726,6 +715,7 @@ let
                 kwalletd = "${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5";
               }; }
               { name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome.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;
               }; }
@@ -867,6 +857,7 @@ let
           { name = "gnupg"; enable = cfg.gnupg.enable; control = "optional"; modulePath = "${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"; settings = {
             no-autostart = cfg.gnupg.noAutostart;
           }; }
+          { name = "intune"; enable = config.services.intune.enable; control = "optional"; modulePath = "${pkgs.intune-portal}/lib/security/pam_intune.so"; }
         ];
       };
     };
diff --git a/nixos/modules/security/pam_usb.nix b/nixos/modules/security/pam_usb.nix
deleted file mode 100644
index 4275c26c6bda..000000000000
--- a/nixos/modules/security/pam_usb.nix
+++ /dev/null
@@ -1,51 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  cfg = config.security.pam.usb;
-
-  anyUsbAuth = any (attrByPath ["usbAuth"] false) (attrValues config.security.pam.services);
-
-in
-
-{
-  options = {
-
-    security.pam.usb = {
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc ''
-          Enable USB login for all login systems that support it.  For
-          more information, visit <https://github.com/aluzzardi/pam_usb/wiki/Getting-Started#setting-up-devices-and-users>.
-        '';
-      };
-
-    };
-
-  };
-
-  config = mkIf (cfg.enable || anyUsbAuth) {
-
-    # Make sure pmount and pumount are setuid wrapped.
-    security.wrappers = {
-      pmount =
-        { setuid = true;
-          owner = "root";
-          group = "root";
-          source = "${pkgs.pmount.out}/bin/pmount";
-        };
-      pumount =
-        { setuid = true;
-          owner = "root";
-          group = "root";
-          source = "${pkgs.pmount.out}/bin/pumount";
-        };
-    };
-
-    environment.systemPackages = [ pkgs.pmount ];
-
-  };
-}
diff --git a/nixos/modules/services/amqp/rabbitmq.nix b/nixos/modules/services/amqp/rabbitmq.nix
index 7dce9d242916..f2dee07c91ab 100644
--- a/nixos/modules/services/amqp/rabbitmq.nix
+++ b/nixos/modules/services/amqp/rabbitmq.nix
@@ -14,6 +14,15 @@ let
 
 in
 {
+
+  imports = [
+    (mkRemovedOptionModule [ "services" "rabbitmq" "cookie" ] ''
+      This option wrote the Erlang cookie to the store, while it should be kept secret.
+      Please remove it from your NixOS configuration and deploy a cookie securely instead.
+      The renamed `unsafeCookie` must ONLY be used in isolated non-production environments such as NixOS VM tests.
+    '')
+  ];
+
   ###### interface
   options = {
     services.rabbitmq = {
@@ -62,13 +71,18 @@ in
         '';
       };
 
-      cookie = mkOption {
+      unsafeCookie = mkOption {
         default = "";
         type = types.str;
         description = lib.mdDoc ''
           Erlang cookie is a string of arbitrary length which must
           be the same for several nodes to be allowed to communicate.
           Leave empty to generate automatically.
+
+          Setting the cookie via this option exposes the cookie to the store, which
+          is not recommended for security reasons.
+          Only use this option in an isolated non-production environment such as
+          NixOS VM tests.
         '';
       };
 
@@ -209,9 +223,8 @@ in
       };
 
       preStart = ''
-        ${optionalString (cfg.cookie != "") ''
-            echo -n ${cfg.cookie} > ${cfg.dataDir}/.erlang.cookie
-            chmod 600 ${cfg.dataDir}/.erlang.cookie
+        ${optionalString (cfg.unsafeCookie != "") ''
+          install -m 600 <(echo -n ${cfg.unsafeCookie}) ${cfg.dataDir}/.erlang.cookie
         ''}
       '';
     };
diff --git a/nixos/modules/services/backup/tsm.nix b/nixos/modules/services/backup/tsm.nix
index 6798b18b3af7..2d727dccdece 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.20?topic=clients-client-return-codes
+        # https://www.ibm.com/docs/en/storage-protect/8.1.21?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/kubernetes/pki.nix b/nixos/modules/services/cluster/kubernetes/pki.nix
index 35151ebd6bd7..c47ceb218e66 100644
--- a/nixos/modules/services/cluster/kubernetes/pki.nix
+++ b/nixos/modules/services/cluster/kubernetes/pki.nix
@@ -174,9 +174,8 @@ in
       '')
       (optionalString cfg.genCfsslAPIToken ''
         if [ ! -f "${cfsslAPITokenPath}" ]; then
-          head -c ${toString (cfsslAPITokenLength / 2)} /dev/urandom | od -An -t x | tr -d ' ' >"${cfsslAPITokenPath}"
+          install -u cfssl -m 400 <(head -c ${toString (cfsslAPITokenLength / 2)} /dev/urandom | od -An -t x | tr -d ' ') "${cfsslAPITokenPath}"
         fi
-        chown cfssl "${cfsslAPITokenPath}" && chmod 400 "${cfsslAPITokenPath}"
       '')]);
 
     systemd.services.kube-certmgr-bootstrap = {
@@ -194,7 +193,7 @@ in
         if [ -f "${cfsslAPITokenPath}" ]; then
           ln -fs "${cfsslAPITokenPath}" "${certmgrAPITokenPath}"
         else
-          touch "${certmgrAPITokenPath}" && chmod 600 "${certmgrAPITokenPath}"
+          install -m 600 /dev/null "${certmgrAPITokenPath}"
         fi
       ''
       (optionalString (cfg.pkiTrustOnBootstrap) ''
@@ -220,7 +219,6 @@ in
             inherit (cert) action;
             authority = {
               inherit remote;
-              file.path = cert.caCert;
               root_ca = cert.caCert;
               profile = "default";
               auth_key_file = certmgrAPITokenPath;
@@ -297,8 +295,7 @@ in
           exit 1
         fi
 
-        echo $token > ${certmgrAPITokenPath}
-        chmod 600 ${certmgrAPITokenPath}
+        install -m 0600 <(echo $token) ${certmgrAPITokenPath}
 
         echo "Restarting certmgr..." >&1
         systemctl restart certmgr
diff --git a/nixos/modules/services/continuous-integration/github-runner/service.nix b/nixos/modules/services/continuous-integration/github-runner/service.nix
index 535df7f68e07..784aea0edea7 100644
--- a/nixos/modules/services/continuous-integration/github-runner/service.nix
+++ b/nixos/modules/services/continuous-integration/github-runner/service.nix
@@ -22,7 +22,8 @@ with lib;
 
 let
   workDir = if cfg.workDir == null then runtimeDir else cfg.workDir;
-  package = cfg.package.override { inherit (cfg) nodeRuntimes; };
+  # Support old github-runner versions which don't have the `nodeRuntimes` arg yet.
+  package = cfg.package.override (old: optionalAttrs (hasAttr "nodeRuntimes" old) { inherit (cfg) nodeRuntimes; });
 in
 {
   description = "GitHub Actions runner";
diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/databases/etcd.nix
index ee6a56db31d3..a5b3abdbcb59 100644
--- a/nixos/modules/services/misc/etcd.nix
+++ b/nixos/modules/services/databases/etcd.nix
@@ -99,6 +99,17 @@ in {
       type = types.nullOr types.path;
     };
 
+    openFirewall = mkOption {
+      type = types.bool;
+      default = false;
+      description = lib.mdDoc ''
+        Open etcd ports in the firewall.
+        Ports opened:
+        - 2379/tcp for client requests
+        - 2380/tcp for peer communication
+      '';
+    };
+
     peerCertFile = mkOption {
       description = lib.mdDoc "Cert file to use for peer to peer communication";
       default = cfg.certFile;
@@ -160,7 +171,10 @@ in {
     systemd.services.etcd = {
       description = "etcd key-value store";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
+      after = [ "network-online.target" ]
+        ++ lib.optional config.networking.firewall.enable "firewall.service";
+      wants = [ "network-online.target" ]
+        ++ lib.optional config.networking.firewall.enable "firewall.service";
 
       environment = (filterAttrs (n: v: v != null) {
         ETCD_NAME = cfg.name;
@@ -190,6 +204,8 @@ in {
 
       serviceConfig = {
         Type = "notify";
+        Restart = "always";
+        RestartSec = "30s";
         ExecStart = "${cfg.package}/bin/etcd";
         User = "etcd";
         LimitNOFILE = 40000;
@@ -198,6 +214,13 @@ in {
 
     environment.systemPackages = [ cfg.package ];
 
+    networking.firewall = lib.mkIf cfg.openFirewall {
+      allowedTCPPorts = [
+        2379 # for client requests
+        2380 # for peer communication
+      ];
+    };
+
     users.users.etcd = {
       isSystemUser = true;
       group = "etcd";
diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix
index 56b916ee3758..45630e2d4488 100644
--- a/nixos/modules/services/databases/neo4j.nix
+++ b/nixos/modules/services/databases/neo4j.nix
@@ -35,65 +35,64 @@ let
 
   serverConfig = pkgs.writeText "neo4j.conf" ''
     # General
-    dbms.allow_upgrade=${boolToString cfg.allowUpgrade}
-    dbms.default_listen_address=${cfg.defaultListenAddress}
-    dbms.databases.default_to_read_only=${boolToString cfg.readOnly}
+    server.default_listen_address=${cfg.defaultListenAddress}
+    server.databases.default_to_read_only=${boolToString cfg.readOnly}
     ${optionalString (cfg.workerCount > 0) ''
       dbms.threads.worker_count=${toString cfg.workerCount}
     ''}
 
     # Directories (readonly)
-    dbms.directories.certificates=${cfg.directories.certificates}
-    dbms.directories.plugins=${cfg.directories.plugins}
-    dbms.directories.lib=${cfg.package}/share/neo4j/lib
+    # dbms.directories.certificates=${cfg.directories.certificates}
+    server.directories.plugins=${cfg.directories.plugins}
+    server.directories.lib=${cfg.package}/share/neo4j/lib
     ${optionalString (cfg.constrainLoadCsv) ''
-      dbms.directories.import=${cfg.directories.imports}
+      server.directories.import=${cfg.directories.imports}
    ''}
 
     # Directories (read and write)
-    dbms.directories.data=${cfg.directories.data}
-    dbms.directories.logs=${cfg.directories.home}/logs
-    dbms.directories.run=${cfg.directories.home}/run
+    server.directories.data=${cfg.directories.data}
+    server.directories.logs=${cfg.directories.home}/logs
+    server.directories.run=${cfg.directories.home}/run
 
     # HTTP Connector
     ${optionalString (cfg.http.enable) ''
-      dbms.connector.http.enabled=${boolToString cfg.http.enable}
-      dbms.connector.http.listen_address=${cfg.http.listenAddress}
-      dbms.connector.http.advertised_address=${cfg.http.listenAddress}
+      server.http.enabled=${boolToString cfg.http.enable}
+      server.http.listen_address=${cfg.http.listenAddress}
+      server.http.advertised_address=${cfg.http.listenAddress}
     ''}
 
     # HTTPS Connector
-    dbms.connector.https.enabled=${boolToString cfg.https.enable}
-    dbms.connector.https.listen_address=${cfg.https.listenAddress}
-    dbms.connector.https.advertised_address=${cfg.https.listenAddress}
+    server.https.enabled=${boolToString cfg.https.enable}
+    server.https.listen_address=${cfg.https.listenAddress}
+    server.https.advertised_address=${cfg.https.listenAddress}
 
     # BOLT Connector
-    dbms.connector.bolt.enabled=${boolToString cfg.bolt.enable}
-    dbms.connector.bolt.listen_address=${cfg.bolt.listenAddress}
-    dbms.connector.bolt.advertised_address=${cfg.bolt.listenAddress}
-    dbms.connector.bolt.tls_level=${cfg.bolt.tlsLevel}
+    server.bolt.enabled=${boolToString cfg.bolt.enable}
+    server.bolt.listen_address=${cfg.bolt.listenAddress}
+    server.bolt.advertised_address=${cfg.bolt.listenAddress}
+    server.bolt.tls_level=${cfg.bolt.tlsLevel}
 
     # SSL Policies
     ${concatStringsSep "\n" sslPolicies}
 
     # Default retention policy from neo4j.conf
-    dbms.tx_log.rotation.retention_policy=1 days
+    db.tx_log.rotation.retention_policy=1 days
 
     # Default JVM parameters from neo4j.conf
-    dbms.jvm.additional=-XX:+UseG1GC
-    dbms.jvm.additional=-XX:-OmitStackTraceInFastThrow
-    dbms.jvm.additional=-XX:+AlwaysPreTouch
-    dbms.jvm.additional=-XX:+UnlockExperimentalVMOptions
-    dbms.jvm.additional=-XX:+TrustFinalNonStaticFields
-    dbms.jvm.additional=-XX:+DisableExplicitGC
-    dbms.jvm.additional=-Djdk.tls.ephemeralDHKeySize=2048
-    dbms.jvm.additional=-Djdk.tls.rejectClientInitiatedRenegotiation=true
-    dbms.jvm.additional=-Dunsupported.dbms.udc.source=tarball
-
-    #dbms.memory.heap.initial_size=12000m
-    #dbms.memory.heap.max_size=12000m
-    #dbms.memory.pagecache.size=4g
-    #dbms.tx_state.max_off_heap_memory=8000m
+    server.jvm.additional=-XX:+UseG1GC
+    server.jvm.additional=-XX:-OmitStackTraceInFastThrow
+    server.jvm.additional=-XX:+AlwaysPreTouch
+    server.jvm.additional=-XX:+UnlockExperimentalVMOptions
+    server.jvm.additional=-XX:+TrustFinalNonStaticFields
+    server.jvm.additional=-XX:+DisableExplicitGC
+    server.jvm.additional=-Djdk.tls.ephemeralDHKeySize=2048
+    server.jvm.additional=-Djdk.tls.rejectClientInitiatedRenegotiation=true
+    server.jvm.additional=-Dunsupported.dbms.udc.source=tarball
+
+    #server.memory.off_heap.transaction_max_size=12000m
+    #server.memory.heap.max_size=12000m
+    #server.memory.pagecache.size=4g
+    #server.tx_state.max_off_heap_memory=8000m
 
     # Extra Configuration
     ${cfg.extraServerConfig}
@@ -127,14 +126,6 @@ in {
       '';
     };
 
-    allowUpgrade = mkOption {
-      type = types.bool;
-      default = false;
-      description = lib.mdDoc ''
-        Allow upgrade of Neo4j database files from an older version.
-      '';
-    };
-
     constrainLoadCsv = mkOption {
       type = types.bool;
       default = true;
diff --git a/nixos/modules/services/games/archisteamfarm.nix b/nixos/modules/services/games/archisteamfarm.nix
index 293e341bef38..c00ae8116b39 100644
--- a/nixos/modules/services/games/archisteamfarm.nix
+++ b/nixos/modules/services/games/archisteamfarm.nix
@@ -20,10 +20,11 @@ let
   mkBot = n: c:
     format.generate "${n}.json" (c.settings // {
       SteamLogin = if c.username == "" then n else c.username;
+      Enabled = c.enabled;
+    } // lib.optionalAttrs (c.passwordFile != null) {
       SteamPassword = c.passwordFile;
       # sets the password format to file (https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Security#file)
       PasswordFormat = 4;
-      Enabled = c.enabled;
     });
 in
 {
@@ -127,8 +128,12 @@ in
             default = "";
           };
           passwordFile = lib.mkOption {
-            type = lib.types.path;
-            description = lib.mdDoc "Path to a file containing the password. The file must be readable by the `archisteamfarm` user/group.";
+            type = with lib.types; nullOr path;
+            default = null;
+            description = lib.mdDoc ''
+              Path to a file containing the password. The file must be readable by the `archisteamfarm` user/group.
+              Omit or set to null to provide the password a different way, such as through the web-ui.
+            '';
           };
           enabled = lib.mkOption {
             type = lib.types.bool;
diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix
index 6fbcbe676460..ebb6fa09aadb 100644
--- a/nixos/modules/services/hardware/fwupd.nix
+++ b/nixos/modules/services/hardware/fwupd.nix
@@ -51,7 +51,9 @@ let
     # to install it because it would create a cyclic dependency between
     # the outputs. We also need to enable the remote,
     # which should not be done by default.
-    lib.optionalAttrs cfg.enableTestRemote (enableRemote cfg.package.installedTests "fwupd-tests")
+    lib.optionalAttrs
+      (cfg.daemonSettings.TestDevices or false)
+      (enableRemote cfg.package.installedTests "fwupd-tests")
   );
 
 in {
@@ -86,15 +88,6 @@ in {
         '';
       };
 
-      enableTestRemote = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc ''
-          Whether to enable test remote. This is used by
-          [installed tests](https://github.com/fwupd/fwupd/blob/master/data/installed-tests/README.md).
-        '';
-      };
-
       package = mkPackageOption pkgs "fwupd" { };
 
       daemonSettings = mkOption {
@@ -128,6 +121,15 @@ in {
                 or if this partition is not mounted at /boot/efi, /boot, or /efi
               '';
             };
+
+            TestDevices = mkOption {
+              type = types.bool;
+              default = false;
+              description = lib.mdDoc ''
+                Create virtual test devices and remote for validating daemon flows.
+                This is only intended for CI testing and development purposes.
+              '';
+            };
           };
         };
         default = {};
@@ -159,7 +161,6 @@ in {
   config = mkIf cfg.enable {
     # Disable test related plug-ins implicitly so that users do not have to care about them.
     services.fwupd.daemonSettings = {
-      DisabledPlugins = cfg.package.defaultDisabledPlugins;
       EspLocation = config.boot.loader.efi.efiSysMountPoint;
     };
 
diff --git a/nixos/modules/services/hardware/pcscd.nix b/nixos/modules/services/hardware/pcscd.nix
index 85accd8335f7..b5963e1d29a3 100644
--- a/nixos/modules/services/hardware/pcscd.nix
+++ b/nixos/modules/services/hardware/pcscd.nix
@@ -46,8 +46,8 @@ in
   config = mkIf config.services.pcscd.enable {
     environment.etc."reader.conf".source = cfgFile;
 
-    environment.systemPackages = [ package.out ];
-    systemd.packages = [ (getBin package) ];
+    environment.systemPackages = [ package ];
+    systemd.packages = [ package ];
 
     services.pcscd.plugins = [ pkgs.ccid ];
 
@@ -64,7 +64,7 @@ in
       # around it, we force the path to the cfgFile.
       #
       # https://github.com/NixOS/nixpkgs/issues/121088
-      serviceConfig.ExecStart = [ "" "${getBin package}/bin/pcscd -f -x -c ${cfgFile}" ];
+      serviceConfig.ExecStart = [ "" "${package}/bin/pcscd -f -x -c ${cfgFile}" ];
     };
   };
 }
diff --git a/nixos/modules/services/home-automation/govee2mqtt.nix b/nixos/modules/services/home-automation/govee2mqtt.nix
new file mode 100644
index 000000000000..1dee5999fa3b
--- /dev/null
+++ b/nixos/modules/services/home-automation/govee2mqtt.nix
@@ -0,0 +1,90 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.govee2mqtt;
+in {
+  meta.maintainers = with lib.maintainers; [ SuperSandro2000 ];
+
+  options.services.govee2mqtt = {
+    enable = lib.mkEnableOption "Govee2MQTT";
+
+    package = lib.mkPackageOption pkgs "govee2mqtt" { };
+
+    user = lib.mkOption {
+      type = lib.types.str;
+      default = "govee2mqtt";
+      description = "User under which Govee2MQTT should run.";
+    };
+
+    group = lib.mkOption {
+      type = lib.types.str;
+      default = "govee2mqtt";
+      description = "Group under which Govee2MQTT should run.";
+    };
+
+    environmentFile = lib.mkOption {
+      type = lib.types.path;
+      example = "/var/lib/govee2mqtt/govee2mqtt.env";
+      description = ''
+        Environment file as defined in {manpage}`systemd.exec(5)`.
+
+        See upstream documentation <https://github.com/wez/govee2mqtt/blob/main/docs/CONFIG.md>.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    users = {
+      groups.${cfg.group} = { };
+      users.${cfg.user} = {
+        description = "Govee2MQTT service user";
+        inherit (cfg) group;
+        isSystemUser = true;
+      };
+    };
+
+    systemd.services.govee2mqtt = {
+      description = "Govee2MQTT Service";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "networking.target" ];
+      serviceConfig = {
+        CacheDirectory = "govee2mqtt";
+        Environment = [
+          "GOVEE_CACHE_DIR=/var/cache/govee2mqtt"
+        ];
+        EnvironmentFile = cfg.environmentFile;
+        ExecStart = "${lib.getExe cfg.package} serve --govee-iot-key=/var/lib/govee2mqtt/iot.key --govee-iot-cert=/var/lib/govee2mqtt/iot.cert"
+          + " --amazon-root-ca=${pkgs.cacert.unbundled}/etc/ssl/certs/Amazon_Root_CA_1:66c9fcf99bf8c0a39e2f0788a43e696365bca.crt";
+        Group = cfg.group;
+        Restart = "on-failure";
+        StateDirectory = "govee2mqtt";
+        User = cfg.user;
+
+        # Hardening
+        AmbientCapabilities = "";
+        CapabilityBoundingSet = "";
+        LockPersonality = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateMounts = 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;
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        SystemCallArchitectures = "native";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/home-automation/zigbee2mqtt.nix b/nixos/modules/services/home-automation/zigbee2mqtt.nix
index 570ce41aa6d4..a653e49a09f6 100644
--- a/nixos/modules/services/home-automation/zigbee2mqtt.nix
+++ b/nixos/modules/services/home-automation/zigbee2mqtt.nix
@@ -71,7 +71,6 @@ in
       after = [ "network.target" ];
       environment.ZIGBEE2MQTT_DATA = cfg.dataDir;
       serviceConfig = {
-        Type = "notify";
         ExecStart = "${cfg.package}/bin/zigbee2mqtt";
         User = "zigbee2mqtt";
         Group = "zigbee2mqtt";
diff --git a/nixos/modules/services/matrix/synapse.md b/nixos/modules/services/matrix/synapse.md
index f270be8c8d78..9c9c025fc5f5 100644
--- a/nixos/modules/services/matrix/synapse.md
+++ b/nixos/modules/services/matrix/synapse.md
@@ -126,8 +126,9 @@ then enable `services.matrix-synapse.settings.enable_registration = true;`.
 Otherwise, or you can generate a registration secret with
 {command}`pwgen -s 64 1` and set it with
 [](#opt-services.matrix-synapse.settings.registration_shared_secret).
-To create a new user or admin, run the following after you have set the secret
-and have rebuilt NixOS:
+To create a new user or admin from the terminal your client listener
+must be configured to use TCP sockets. Then you can run the following
+after you have set the secret and have rebuilt NixOS:
 ```ShellSession
 $ nix-shell -p matrix-synapse
 $ register_new_matrix_user -k your-registration-shared-secret http://localhost:8008
diff --git a/nixos/modules/services/matrix/synapse.nix b/nixos/modules/services/matrix/synapse.nix
index 4c1c396eac05..e3f9c7742cc7 100644
--- a/nixos/modules/services/matrix/synapse.nix
+++ b/nixos/modules/services/matrix/synapse.nix
@@ -6,8 +6,16 @@ let
   cfg = config.services.matrix-synapse;
   format = pkgs.formats.yaml { };
 
+  filterRecursiveNull = o:
+    if isAttrs o then
+      mapAttrs (_: v: filterRecursiveNull v) (filterAttrs (_: v: v != null) o)
+    else if isList o then
+      map filterRecursiveNull (filter (v: v != null) o)
+    else
+      o;
+
   # remove null values from the final configuration
-  finalSettings = lib.filterAttrsRecursive (_: v: v != null) cfg.settings;
+  finalSettings = filterRecursiveNull cfg.settings;
   configFile = format.generate "homeserver.yaml" finalSettings;
 
   usePostgresql = cfg.settings.database.name == "psycopg2";
@@ -105,6 +113,19 @@ let
         SYSLOG_IDENTIFIER = logName;
       };
     });
+
+  toIntBase8 = str:
+    lib.pipe str [
+      lib.stringToCharacters
+      (map lib.toInt)
+      (lib.foldl (acc: digit: acc * 8 + digit) 0)
+    ];
+
+  toDecimalFilePermission = value:
+    if value == null then
+      null
+    else
+      toIntBase8 value;
 in {
 
   imports = [
@@ -192,10 +213,11 @@ in {
   ];
 
   options = let
-    listenerType = workerContext: types.submodule {
+    listenerType = workerContext: types.submodule ({ config, ... }: {
       options = {
         port = mkOption {
-          type = types.port;
+          type = types.nullOr types.port;
+          default = null;
           example = 8448;
           description = lib.mdDoc ''
             The port to listen for HTTP(S) requests on.
@@ -203,11 +225,20 @@ in {
         };
 
         bind_addresses = mkOption {
-          type = types.listOf types.str;
-          default = [
+          type = types.nullOr (types.listOf types.str);
+          default = if config.path != null then null else [
             "::1"
             "127.0.0.1"
           ];
+          defaultText = literalExpression ''
+            if path != null then
+              null
+            else
+              [
+                "::1"
+                "127.0.0.1"
+              ]
+          '';
           example = literalExpression ''
             [
               "::"
@@ -219,6 +250,35 @@ in {
           '';
         };
 
+        path = mkOption {
+          type = types.nullOr types.path;
+          default = null;
+          description = ''
+            Unix domain socket path to bind this listener to.
+
+            ::: {.note}
+              This option is incompatible with {option}`bind_addresses`, {option}`port`, {option}`tls`
+              and also does not support the `metrics` and `manhole` listener {option}`type`.
+            :::
+          '';
+        };
+
+        mode = mkOption {
+          type = types.nullOr (types.strMatching "^[0,2-7]{3,4}$");
+          default = if config.path != null then "660" else null;
+          defaultText = literalExpression ''
+            if path != null then
+              "660"
+            else
+              null
+          '';
+          example = "660";
+          description = ''
+            File permissions on the UNIX domain socket.
+          '';
+          apply = toDecimalFilePermission;
+        };
+
         type = mkOption {
           type = types.enum [
             "http"
@@ -234,17 +294,30 @@ in {
         };
 
         tls = mkOption {
-          type = types.bool;
-          default = !workerContext;
+          type = types.nullOr types.bool;
+          default = if config.path != null then
+            null
+          else
+            !workerContext;
+          defaultText = ''
+            Enabled for the main instance listener, unless it is configured with a UNIX domain socket path.
+          '';
           example = false;
           description = lib.mdDoc ''
             Whether to enable TLS on the listener socket.
+
+            ::: {.note}
+              This option will be ignored for UNIX domain sockets.
+            :::
           '';
         };
 
         x_forwarded = mkOption {
           type = types.bool;
-          default = false;
+          default = config.path != null;
+          defaultText = ''
+            Enabled if the listener is configured with a UNIX domain socket path
+          '';
           example = true;
           description = lib.mdDoc ''
             Use the X-Forwarded-For (XFF) header as the client IP and not the
@@ -291,11 +364,28 @@ in {
           '';
         };
       };
-    };
+    });
   in {
     services.matrix-synapse = {
       enable = mkEnableOption (lib.mdDoc "matrix.org synapse");
 
+      enableRegistrationScript = mkOption {
+        type = types.bool;
+        default = clientListener.bind_addresses != [];
+        example = false;
+        defaultText = ''
+          Enabled if the client listener uses TCP sockets
+        '';
+        description = ''
+          Whether to install the `register_new_matrix_user` script, that
+          allows account creation on the terminal.
+
+          ::: {.note}
+            This script does not work when the client listener uses UNIX domain sockets
+          :::
+        '';
+      };
+
       serviceUnit = lib.mkOption {
         type = lib.types.str;
         readOnly = true;
@@ -616,11 +706,8 @@ in {
                   compress = false;
                 }];
               }] ++ lib.optional hasWorkers {
-                port = 9093;
-                bind_addresses = [ "127.0.0.1" ];
+                path = "/run/matrix-synapse/main_replication.sock";
                 type = "http";
-                tls = false;
-                x_forwarded = false;
                 resources = [{
                   names = [ "replication" ];
                   compress = false;
@@ -630,7 +717,7 @@ in {
                 List of ports that Synapse should listen on, their purpose and their configuration.
 
                 By default, synapse will be configured for client and federation traffic on port 8008, and
-                for worker replication traffic on port 9093. See [`services.matrix-synapse.workers`](#opt-services.matrix-synapse.workers)
+                use a UNIX domain socket for worker replication. See [`services.matrix-synapse.workers`](#opt-services.matrix-synapse.workers)
                 for more details.
               '';
             };
@@ -1006,9 +1093,15 @@ in {
             listener = lib.findFirst
               (
                 listener:
-                  listener.port == main.port
+                  (
+                    lib.hasAttr "port" main && listener.port or null == main.port
+                    || lib.hasAttr "path" main && listener.path or null == main.path
+                  )
                   && listenerSupportsResource "replication" listener
-                  && (lib.any (bind: bind == main.host || bind == "0.0.0.0" || bind == "::") listener.bind_addresses)
+                  && (
+                    lib.hasAttr "host" main &&  lib.any (bind: bind == main.host || bind == "0.0.0.0" || bind == "::") listener.bind_addresses
+                    || lib.hasAttr "path" main
+                  )
               )
               null
               cfg.settings.listeners;
@@ -1022,15 +1115,44 @@ in {
           This is done by default unless you manually configure either of those settings.
         '';
       }
-    ];
+      {
+        assertion = cfg.enableRegistrationScript -> clientListener.path == null;
+        message = ''
+          The client listener on matrix-synapse is configured to use UNIX domain sockets.
+          This configuration is incompatible with the `register_new_matrix_user` script.
+
+          Disable  `services.mastrix-synapse.enableRegistrationScript` to continue.
+        '';
+      }
+    ]
+    ++ (map (listener: {
+      assertion = (listener.path == null) != (listener.bind_addresses == null);
+      message = ''
+        Listeners require either a UNIX domain socket `path` or `bind_addresses` for a TCP socket.
+      '';
+    }) cfg.settings.listeners)
+    ++ (map (listener: {
+      assertion = listener.path != null -> (listener.bind_addresses == null && listener.port == null && listener.tls == null);
+      message = let
+        formatKeyValue = key: value: lib.optionalString (value != null) "  - ${key}=${toString value}\n";
+      in ''
+        Listener configured with UNIX domain socket (${toString listener.path}) ignores the following options:
+        ${formatKeyValue "bind_addresses" listener.bind_addresses}${formatKeyValue "port" listener.port}${formatKeyValue "tls" listener.tls}
+      '';
+    }) cfg.settings.listeners)
+    ++ (map (listener: {
+      assertion = listener.path == null || listener.type == "http";
+      message = ''
+        Listener configured with UNIX domain socket (${toString listener.path}) only supports the "http" listener type.
+      '';
+    }) cfg.settings.listeners);
 
     services.matrix-synapse.settings.redis = lib.mkIf cfg.configureRedisLocally {
       enabled = true;
       path = config.services.redis.servers.matrix-synapse.unixSocket;
     };
     services.matrix-synapse.settings.instance_map.main = lib.mkIf hasWorkers (lib.mkDefault {
-      host = "127.0.0.1";
-      port = 9093;
+      path = "/run/matrix-synapse/main_replication.sock";
     });
 
     services.matrix-synapse.serviceUnit = if hasWorkers then "matrix-synapse.target" else "matrix-synapse.service";
@@ -1086,6 +1208,8 @@ in {
             User = "matrix-synapse";
             Group = "matrix-synapse";
             WorkingDirectory = cfg.dataDir;
+            RuntimeDirectory = "matrix-synapse";
+            RuntimeDirectoryPreserve = true;
             ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID";
             Restart = "on-failure";
             UMask = "0077";
@@ -1178,7 +1302,9 @@ in {
       user = "matrix-synapse";
     };
 
-    environment.systemPackages = [ registerNewMatrixUser ];
+    environment.systemPackages = lib.optionals cfg.enableRegistrationScript [
+      registerNewMatrixUser
+    ];
   };
 
   meta = {
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 6756d59cf367..ec347a75f063 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -1386,10 +1386,8 @@ in {
 
     systemd.services.gitlab-db-config = {
       after = [ "gitlab-config.service" "gitlab-postgresql.service" "postgresql.service" ];
-      bindsTo = [
-        "gitlab-config.service"
-      ] ++ optional (cfg.databaseHost == "") "postgresql.service"
-        ++ optional databaseActuallyCreateLocally "gitlab-postgresql.service";
+      wants = optional (cfg.databaseHost == "") "postgresql.service" ++ optional databaseActuallyCreateLocally "gitlab-postgresql.service";
+      bindsTo = [ "gitlab-config.service" ];
       wantedBy = [ "gitlab.target" ];
       partOf = [ "gitlab.target" ];
       serviceConfig = {
@@ -1422,10 +1420,10 @@ in {
         "gitlab-db-config.service"
       ];
       bindsTo = [
-        "redis-gitlab.service"
         "gitlab-config.service"
         "gitlab-db-config.service"
-      ] ++ optional (cfg.databaseHost == "") "postgresql.service";
+      ];
+      wants = [ "redis-gitlab.service" ] ++ optional (cfg.databaseHost == "") "postgresql.service";
       wantedBy = [ "gitlab.target" ];
       partOf = [ "gitlab.target" ];
       environment = gitlabEnv // (optionalAttrs cfg.sidekiq.memoryKiller.enable {
@@ -1612,10 +1610,10 @@ in {
         "gitlab-db-config.service"
       ];
       bindsTo = [
-        "redis-gitlab.service"
         "gitlab-config.service"
         "gitlab-db-config.service"
-      ] ++ optional (cfg.databaseHost == "") "postgresql.service";
+      ];
+      wants = [ "redis-gitlab.service" ] ++ optional (cfg.databaseHost == "") "postgresql.service";
       requiredBy = [ "gitlab.target" ];
       partOf = [ "gitlab.target" ];
       environment = gitlabEnv;
diff --git a/nixos/modules/services/misc/nix-gc.nix b/nixos/modules/services/misc/nix-gc.nix
index de6bd76c7eb9..656cbad81373 100644
--- a/nixos/modules/services/misc/nix-gc.nix
+++ b/nixos/modules/services/misc/nix-gc.nix
@@ -64,8 +64,7 @@ in
         example = "--max-freed $((64 * 1024**3))";
         type = lib.types.singleLineStr;
         description = lib.mdDoc ''
-          Options given to {file}`nix-collect-garbage` when the
-          garbage collector is run automatically.
+          Options given to [`nix-collect-garbage`](https://nixos.org/manual/nix/stable/command-ref/nix-collect-garbage) when the garbage collector is run automatically.
         '';
       };
 
diff --git a/nixos/modules/services/networking/cloudflared.nix b/nixos/modules/services/networking/cloudflared.nix
index 80c60fdb8013..b9556bfa60d0 100644
--- a/nixos/modules/services/networking/cloudflared.nix
+++ b/nixos/modules/services/networking/cloudflared.nix
@@ -276,9 +276,11 @@ in
             ingressesSet = filterIngressSet tunnel.ingress;
             ingressesStr = filterIngressStr tunnel.ingress;
 
-            fullConfig = {
+            fullConfig = filterConfig {
               tunnel = name;
               "credentials-file" = tunnel.credentialsFile;
+              warp-routing = filterConfig tunnel.warp-routing;
+              originRequest = filterConfig tunnel.originRequest;
               ingress =
                 (map
                   (key: {
@@ -294,6 +296,7 @@ in
                   (attrNames ingressesStr))
                 ++ [{ service = tunnel.default; }];
             };
+
             mkConfigFile = pkgs.writeText "cloudflared.yml" (builtins.toJSON fullConfig);
           in
           nameValuePair "cloudflared-tunnel-${name}" ({
@@ -322,5 +325,5 @@ in
     };
   };
 
-  meta.maintainers = with maintainers; [ bbigras ];
+  meta.maintainers = with maintainers; [ bbigras anpin ];
 }
diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix
index 2b59352ac616..266a7ea1435e 100644
--- a/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixos/modules/services/networking/dhcpcd.nix
@@ -219,6 +219,8 @@ in
       '';
     } ];
 
+    environment.etc."dhcpcd.conf".source = dhcpcdConf;
+
     systemd.services.dhcpcd = let
       cfgN = config.networking;
       hasDefaultGatewaySet = (cfgN.defaultGateway != null && cfgN.defaultGateway.address != "")
diff --git a/nixos/modules/services/networking/hostapd.nix b/nixos/modules/services/networking/hostapd.nix
index 5bd8e1d4d7a0..00482e59acf3 100644
--- a/nixos/modules/services/networking/hostapd.nix
+++ b/nixos/modules/services/networking/hostapd.nix
@@ -1197,8 +1197,6 @@ in {
 
     environment.systemPackages = [cfg.package];
 
-    services.udev.packages = with pkgs; [crda];
-
     systemd.services.hostapd = {
       description = "IEEE 802.11 Host Access-Point Daemon";
 
diff --git a/nixos/modules/services/networking/jibri/default.nix b/nixos/modules/services/networking/jibri/default.nix
index 73d11bdbee5a..dfba38896a91 100644
--- a/nixos/modules/services/networking/jibri/default.nix
+++ b/nixos/modules/services/networking/jibri/default.nix
@@ -5,12 +5,7 @@ with lib;
 let
   cfg = config.services.jibri;
 
-  # Copied from the jitsi-videobridge.nix file.
-  toHOCON = x:
-    if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
-    else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
-    else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
-    else builtins.toJSON x;
+  format = pkgs.formats.hocon { };
 
   # We're passing passwords in environment variables that have names generated
   # from an attribute name, which may not be a valid bash identifier.
@@ -38,13 +33,13 @@ let
         control-login = {
           domain = env.control.login.domain;
           username = env.control.login.username;
-          password.__hocon_envvar = toVarName "${name}_control";
+          password = format.lib.mkSubstitution (toVarName "${name}_control");
         };
 
         call-login = {
           domain = env.call.login.domain;
           username = env.call.login.username;
-          password.__hocon_envvar = toVarName "${name}_call";
+          password = format.lib.mkSubstitution (toVarName "${name}_call");
         };
 
         strip-from-room-domain = env.stripFromRoomDomain;
@@ -85,13 +80,13 @@ let
   };
   # Allow overriding leaves of the default config despite types.attrs not doing any merging.
   jibriConfig = recursiveUpdate defaultJibriConfig cfg.config;
-  configFile = pkgs.writeText "jibri.conf" (toHOCON { jibri = jibriConfig; });
+  configFile = format.generate "jibri.conf" { jibri = jibriConfig; };
 in
 {
   options.services.jibri = with types; {
     enable = mkEnableOption (lib.mdDoc "Jitsi BRoadcasting Infrastructure. Currently Jibri must be run on a host that is also running {option}`services.jitsi-meet.enable`, so for most use cases it will be simpler to run {option}`services.jitsi-meet.jibri.enable`");
     config = mkOption {
-      type = attrs;
+      type = format.type;
       default = { };
       description = lib.mdDoc ''
         Jibri configuration.
diff --git a/nixos/modules/services/networking/jicofo.nix b/nixos/modules/services/networking/jicofo.nix
index 0886bbe004c4..380344c8eaa1 100644
--- a/nixos/modules/services/networking/jicofo.nix
+++ b/nixos/modules/services/networking/jicofo.nix
@@ -5,14 +5,9 @@ with lib;
 let
   cfg = config.services.jicofo;
 
-  # HOCON is a JSON superset that some jitsi-meet components use for configuration
-  toHOCON = x: if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
-    else if isAttrs x && x ? __hocon_unquoted_string then x.__hocon_unquoted_string
-    else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
-    else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
-    else builtins.toJSON x;
-
-  configFile = pkgs.writeText "jicofo.conf" (toHOCON cfg.config);
+  format = pkgs.formats.hocon { };
+
+  configFile = format.generate "jicofo.conf" cfg.config;
 in
 {
   options.services.jicofo = with types; {
@@ -77,7 +72,7 @@ in
     };
 
     config = mkOption {
-      type = (pkgs.formats.json {}).type;
+      type = format.type;
       default = { };
       example = literalExpression ''
         {
@@ -99,7 +94,7 @@ in
             hostname = cfg.xmppHost;
             username = cfg.userName;
             domain = cfg.userDomain;
-            password = { __hocon_envvar = "JICOFO_AUTH_PASS"; };
+            password = format.lib.mkSubstitution "JICOFO_AUTH_PASS";
             xmpp-domain = if cfg.xmppDomain == null then cfg.xmppHost else cfg.xmppDomain;
           };
           service = client;
diff --git a/nixos/modules/services/networking/jitsi-videobridge.nix b/nixos/modules/services/networking/jitsi-videobridge.nix
index 37b0b1e5bf50..00ea5b9da546 100644
--- a/nixos/modules/services/networking/jitsi-videobridge.nix
+++ b/nixos/modules/services/networking/jitsi-videobridge.nix
@@ -6,16 +6,7 @@ let
   cfg = config.services.jitsi-videobridge;
   attrsToArgs = a: concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") a);
 
-  # HOCON is a JSON superset that videobridge2 uses for configuration.
-  # It can substitute environment variables which we use for passwords here.
-  # https://github.com/lightbend/config/blob/master/README.md
-  #
-  # Substitution for environment variable FOO is represented as attribute set
-  # { __hocon_envvar = "FOO"; }
-  toHOCON = x: if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
-    else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
-    else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
-    else builtins.toJSON x;
+  format = pkgs.formats.hocon { };
 
   # We're passing passwords in environment variables that have names generated
   # from an attribute name, which may not be a valid bash identifier.
@@ -38,7 +29,7 @@ let
         hostname = xmppConfig.hostName;
         domain = xmppConfig.domain;
         username = xmppConfig.userName;
-        password = { __hocon_envvar = toVarName name; };
+        password = format.lib.mkSubstitution (toVarName name);
         muc_jids = xmppConfig.mucJids;
         muc_nickname = xmppConfig.mucNickname;
         disable_certificate_verification = xmppConfig.disableCertificateVerification;
@@ -221,7 +212,7 @@ in
         "-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi";
         "-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "videobridge";
         "-Djava.util.logging.config.file" = "/etc/jitsi/videobridge/logging.properties";
-        "-Dconfig.file" = pkgs.writeText "jvb.conf" (toHOCON jvbConfig);
+        "-Dconfig.file" = format.generate "jvb.conf" jvbConfig;
         # Mitigate CVE-2021-44228
         "-Dlog4j2.formatMsgNoLookups" = true;
       } // (mapAttrs' (k: v: nameValuePair "-D${k}" v) cfg.extraProperties);
diff --git a/nixos/modules/services/networking/murmur.nix b/nixos/modules/services/networking/murmur.nix
index 0cd80e134ace..5805f332a66f 100644
--- a/nixos/modules/services/networking/murmur.nix
+++ b/nixos/modules/services/networking/murmur.nix
@@ -326,6 +326,29 @@ in
         RuntimeDirectoryMode = "0700";
         User = "murmur";
         Group = "murmur";
+
+        # service hardening
+        AmbientCapabilities = "CAP_NET_BIND_SERVICE";
+        CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateTmp = true;
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectSystem = "full";
+        RestrictAddressFamilies = "~AF_PACKET AF_NETLINK";
+        RestrictNamespaces = true;
+        RestrictSUIDSGID = true;
+        RestrictRealtime = true;
+        SystemCallArchitectures = "native";
+        SystemCallFilter = "@system-service";
       };
     };
 
diff --git a/nixos/modules/services/networking/nftables.nix b/nixos/modules/services/networking/nftables.nix
index 424d005dc0b5..46fa9d2de046 100644
--- a/nixos/modules/services/networking/nftables.nix
+++ b/nixos/modules/services/networking/nftables.nix
@@ -252,8 +252,10 @@ in
     networking.nftables.flushRuleset = mkDefault (versionOlder config.system.stateVersion "23.11" || (cfg.rulesetFile != null || cfg.ruleset != ""));
     systemd.services.nftables = {
       description = "nftables firewall";
-      before = [ "network-pre.target" ];
-      wants = [ "network-pre.target" ];
+      after = [ "sysinit.target" ];
+      before = [ "network-pre.target" "shutdown.target" ];
+      conflicts = [ "shutdown.target" ];
+      wants = [ "network-pre.target" "sysinit.target" ];
       wantedBy = [ "multi-user.target" ];
       reloadIfChanged = true;
       serviceConfig = let
@@ -315,6 +317,7 @@ in
         ExecStop = [ deletionsScriptVar cleanupDeletionsScript ];
         StateDirectory = "nftables";
       };
+      unitConfig.DefaultDependencies = false;
     };
   };
 }
diff --git a/nixos/modules/services/security/intune.nix b/nixos/modules/services/security/intune.nix
new file mode 100644
index 000000000000..93cecaca5f43
--- /dev/null
+++ b/nixos/modules/services/security/intune.nix
@@ -0,0 +1,32 @@
+{ config
+, pkgs
+, lib
+, ...
+}:
+let
+  cfg = config.services.intune;
+in
+{
+  options.services.intune = {
+    enable = lib.mkEnableOption (lib.mdDoc "Microsoft Intune");
+  };
+
+
+  config = lib.mkIf cfg.enable {
+    users.users.microsoft-identity-broker = {
+      group = "microsoft-identity-broker";
+      isSystemUser = true;
+    };
+
+    users.groups.microsoft-identity-broker = { };
+    environment.systemPackages = [ pkgs.microsoft-identity-broker pkgs.intune-portal ];
+    systemd.packages = [ pkgs.microsoft-identity-broker pkgs.intune-portal ];
+
+    systemd.tmpfiles.packages = [ pkgs.intune-portal ];
+    services.dbus.packages = [ pkgs.microsoft-identity-broker ];
+  };
+
+  meta = {
+    maintainers = with lib.maintainers; [ rhysmdnz ];
+  };
+}
diff --git a/nixos/modules/services/security/kanidm.nix b/nixos/modules/services/security/kanidm.nix
index c8d8f69729e9..c659d93b4087 100644
--- a/nixos/modules/services/security/kanidm.nix
+++ b/nixos/modules/services/security/kanidm.nix
@@ -165,10 +165,17 @@ in
       type = lib.types.submodule {
         freeformType = settingsFormat.type;
 
-        options.pam_allowed_login_groups = lib.mkOption {
-          description = lib.mdDoc "Kanidm groups that are allowed to login using PAM.";
-          example = "my_pam_group";
-          type = lib.types.listOf lib.types.str;
+        options = {
+          pam_allowed_login_groups = lib.mkOption {
+            description = lib.mdDoc "Kanidm groups that are allowed to login using PAM.";
+            example = "my_pam_group";
+            type = lib.types.listOf lib.types.str;
+          };
+          hsm_pin_path = lib.mkOption {
+            description = lib.mdDoc "Path to a HSM pin.";
+            default = "/var/cache/kanidm-unixd/hsm-pin";
+            type = lib.types.path;
+          };
         };
       };
       description = lib.mdDoc ''
diff --git a/nixos/modules/services/video/frigate.nix b/nixos/modules/services/video/frigate.nix
index b7945282ba09..0c923a20c40c 100644
--- a/nixos/modules/services/video/frigate.nix
+++ b/nixos/modules/services/video/frigate.nix
@@ -17,7 +17,7 @@ let
 
   cfg = config.services.frigate;
 
-  format = pkgs.formats.yaml {};
+  format = pkgs.formats.yaml { };
 
   filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! lib.elem v [ null ])) cfg.settings;
 
@@ -112,7 +112,7 @@ in
           };
         };
       };
-      default = {};
+      default = { };
       description = mdDoc ''
         Frigate configuration as a nix attribute set.
 
@@ -125,7 +125,7 @@ in
 
   config = mkIf cfg.enable {
     services.nginx = {
-      enable =true;
+      enable = true;
       additionalModules = with pkgs.nginxModules; [
         secure-token
         rtmp
@@ -133,31 +133,64 @@ in
       ];
       recommendedProxySettings = mkDefault true;
       recommendedGzipSettings = mkDefault true;
+      mapHashBucketSize = mkDefault 128;
       upstreams = {
         frigate-api.servers = {
-          "127.0.0.1:5001" = {};
+          "127.0.0.1:5001" = { };
         };
         frigate-mqtt-ws.servers = {
-          "127.0.0.1:5002" = {};
+          "127.0.0.1:5002" = { };
         };
         frigate-jsmpeg.servers = {
-          "127.0.0.1:8082" = {};
+          "127.0.0.1:8082" = { };
         };
         frigate-go2rtc.servers = {
-          "127.0.0.1:1984" = {};
+          "127.0.0.1:1984" = { };
         };
       };
-      # Based on https://github.com/blakeblackshear/frigate/blob/v0.12.0/docker/rootfs/usr/local/nginx/conf/nginx.conf
+      proxyCachePath."frigate" = {
+        enable = true;
+        keysZoneSize = "10m";
+        keysZoneName = "frigate_api_cache";
+        maxSize = "10m";
+        inactive = "1m";
+        levels = "1:2";
+      };
+      # Based on https://github.com/blakeblackshear/frigate/blob/v0.13.1/docker/main/rootfs/usr/local/nginx/conf/nginx.conf
       virtualHosts."${cfg.hostname}" = {
         locations = {
           "/api/" = {
             proxyPass = "http://frigate-api/";
+            extraConfig = ''
+              proxy_cache frigate_api_cache;
+              proxy_cache_lock on;
+              proxy_cache_use_stale updating;
+              proxy_cache_valid 200 5s;
+              proxy_cache_bypass $http_x_cache_bypass;
+              proxy_no_cache $should_not_cache;
+              add_header X-Cache-Status $upstream_cache_status;
+
+              location /api/vod/ {
+                  proxy_pass http://frigate-api/vod/;
+                  proxy_cache off;
+              }
+
+              location /api/stats {
+                  access_log off;
+                  rewrite ^/api/(.*)$ $1 break;
+                  proxy_pass http://frigate-api;
+              }
+
+              location /api/version {
+                  access_log off;
+                  rewrite ^/api/(.*)$ $1 break;
+                  proxy_pass http://frigate-api;
+              }
+            '';
           };
           "~* /api/.*\.(jpg|jpeg|png)$" = {
             proxyPass = "http://frigate-api";
             extraConfig = ''
-              add_header 'Access-Control-Allow-Origin' '*';
-              add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
               rewrite ^/api/(.*)$ $1 break;
             '';
           };
@@ -169,10 +202,6 @@ in
               secure_token $args;
               secure_token_types application/vnd.apple.mpegurl;
 
-              add_header Access-Control-Allow-Headers '*';
-              add_header Access-Control-Expose-Headers 'Server,range,Content-Length,Content-Range';
-              add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS';
-              add_header Access-Control-Allow-Origin '*';
               add_header Cache-Control "no-store";
               expires off;
             '';
@@ -192,27 +221,64 @@ in
             proxyPass = "http://frigate-go2rtc/";
             proxyWebsockets = true;
           };
+          # frigate lovelace card uses this path
+          "/live/mse/api/ws" = {
+            proxyPass = "http://frigate-go2rtc/api/ws";
+            proxyWebsockets = true;
+            extraConfig = ''
+              limit_except GET {
+                  deny  all;
+              }
+            '';
+          };
           "/live/webrtc/" = {
             proxyPass = "http://frigate-go2rtc/";
             proxyWebsockets = true;
           };
+          "/live/webrtc/api/ws" = {
+            proxyPass = "http://frigate-go2rtc/api/ws";
+            proxyWebsockets = true;
+            extraConfig = ''
+              limit_except GET {
+                  deny  all;
+              }
+            '';
+          };
+          # pass through go2rtc player
+          "/live/webrtc/webrtc.html" = {
+            proxyPass = "http://frigate-go2rtc/webrtc.html";
+            proxyWebsockets = true;
+            extraConfig = ''
+              limit_except GET {
+                  deny  all;
+              }
+            '';
+          };
+          "/api/go2rtc/api" = {
+            proxyPass = "http://frigate-go2rtc/api";
+            proxyWebsockets = true;
+            extraConfig = ''
+              limit_except GET {
+                  deny  all;
+              }
+            '';
+          };
+          # integrationn uses this to add webrtc candidate
+          "/api/go2rtc/webrtc" = {
+            proxyPass = "http://frigate-go2rtc/api/webrtc";
+            proxyWebsockets = true;
+            extraConfig = ''
+              limit_except GET {
+                  deny  all;
+              }
+            '';
+          };
           "/cache/" = {
             alias = "/var/cache/frigate/";
           };
           "/clips/" = {
             root = "/var/lib/frigate";
             extraConfig = ''
-              add_header 'Access-Control-Allow-Origin' "$http_origin" always;
-              add_header 'Access-Control-Allow-Credentials' 'true';
-              add_header 'Access-Control-Expose-Headers' 'Content-Length';
-              if ($request_method = 'OPTIONS') {
-                  add_header 'Access-Control-Allow-Origin' "$http_origin";
-                  add_header 'Access-Control-Max-Age' 1728000;
-                  add_header 'Content-Type' 'text/plain charset=UTF-8';
-                  add_header 'Content-Length' 0;
-                  return 204;
-              }
-
               types {
                   video/mp4 mp4;
                   image/jpeg jpg;
@@ -224,17 +290,6 @@ in
           "/recordings/" = {
             root = "/var/lib/frigate";
             extraConfig = ''
-              add_header 'Access-Control-Allow-Origin' "$http_origin" always;
-              add_header 'Access-Control-Allow-Credentials' 'true';
-              add_header 'Access-Control-Expose-Headers' 'Content-Length';
-              if ($request_method = 'OPTIONS') {
-                  add_header 'Access-Control-Allow-Origin' "$http_origin";
-                  add_header 'Access-Control-Max-Age' 1728000;
-                  add_header 'Content-Type' 'text/plain charset=UTF-8';
-                  add_header 'Content-Length' 0;
-                  return 204;
-              }
-
               types {
                   video/mp4 mp4;
               }
@@ -315,6 +370,12 @@ in
             }
         }
       '';
+      appendHttpConfig = ''
+        map $sent_http_content_type $should_not_cache {
+          'application/json' 0;
+          default 1;
+        }
+      '';
     };
 
     systemd.services.nginx.serviceConfig.SupplementaryGroups = [
@@ -325,7 +386,7 @@ in
       isSystemUser = true;
       group = "frigate";
     };
-    users.groups.frigate = {};
+    users.groups.frigate = { };
 
     systemd.services.frigate = {
       after = [
diff --git a/nixos/modules/services/web-apps/photoprism.nix b/nixos/modules/services/web-apps/photoprism.nix
index 1716840e84e5..d3773cc9cf78 100644
--- a/nixos/modules/services/web-apps/photoprism.nix
+++ b/nixos/modules/services/web-apps/photoprism.nix
@@ -21,7 +21,7 @@ let
       eval "$(${config.systemd.package}/bin/systemctl show -pUID,MainPID photoprism.service | ${pkgs.gnused}/bin/sed "s/UID/ServiceUID/")"
       exec ${pkgs.util-linux}/bin/nsenter \
         -t $MainPID -m -S $ServiceUID -G $ServiceUID --wdns=${cfg.storagePath} \
-      exec ${cfg.package}/bin/photoprism "$@"
+        ${cfg.package}/bin/photoprism "$@"
     '';
 in
 {
diff --git a/nixos/modules/services/web-apps/suwayomi-server.nix b/nixos/modules/services/web-apps/suwayomi-server.nix
index c4c1540edbee..94dbe6f99356 100644
--- a/nixos/modules/services/web-apps/suwayomi-server.nix
+++ b/nixos/modules/services/web-apps/suwayomi-server.nix
@@ -3,6 +3,8 @@
 let
   cfg = config.services.suwayomi-server;
   inherit (lib) mkOption mdDoc mkEnableOption mkIf types;
+
+  format = pkgs.formats.hocon { };
 in
 {
   options = {
@@ -48,19 +50,7 @@ in
 
       settings = mkOption {
         type = types.submodule {
-          freeformType =
-            let
-              recursiveAttrsType = with types; attrsOf (nullOr (oneOf [
-                str
-                path
-                int
-                float
-                bool
-                (listOf str)
-                (recursiveAttrsType // { description = "instances of this type recursively"; })
-              ]));
-            in
-            recursiveAttrsType;
+          freeformType = format.type;
           options = {
             server = {
               ip = mkOption {
@@ -180,38 +170,7 @@ in
 
     systemd.services.suwayomi-server =
       let
-        flattenConfig = prefix: config:
-          lib.foldl'
-            lib.mergeAttrs
-            { }
-            (lib.attrValues
-              (lib.mapAttrs
-                (k: v:
-                  if !(lib.isAttrs v)
-                  then { "${prefix}${k}" = v; }
-                  else flattenConfig "${prefix}${k}." v
-                )
-                config
-              )
-            );
-
-        #  HOCON is a JSON superset that suwayomi-server use for configuration
-        toHOCON = attr:
-          let
-            attrType = builtins.typeOf attr;
-          in
-          if builtins.elem attrType [ "string" "path" "int" "float" ]
-          then ''"${toString attr}"''
-          else if attrType == "bool"
-          then lib.boolToString attr
-          else if attrType == "list"
-          then "[\n${lib.concatMapStringsSep ",\n" toHOCON attr}\n]"
-          else # attrs, lambda, null
-            throw ''
-              [suwayomi-server]: invalid config value type '${attrType}'.
-            '';
-
-        configFile = pkgs.writeText "server.conf" (lib.pipe cfg.settings [
+        configFile = format.generate "server.conf" (lib.pipe cfg.settings [
           (settings: lib.recursiveUpdate settings {
             server.basicAuthPasswordFile = null;
             server.basicAuthPassword =
@@ -219,12 +178,8 @@ in
               then "$TACHIDESK_SERVER_BASIC_AUTH_PASSWORD"
               else null;
           })
-          (flattenConfig "")
-          (lib.filterAttrs (_: x: x != null))
-          (lib.mapAttrsToList (name: value: ''${name} = ${toHOCON value}''))
-          lib.concatLines
+          (lib.filterAttrsRecursive (_: x: x != null))
         ]);
-
       in
       {
         description = "A free and open source manga reader server that runs extensions built for Tachiyomi.";
diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix
index a8fb37d2c5ec..84342165c9c0 100644
--- a/nixos/modules/services/web-apps/tt-rss.nix
+++ b/nixos/modules/services/web-apps/tt-rss.nix
@@ -4,6 +4,8 @@ with lib;
 let
   cfg = config.services.tt-rss;
 
+  inherit (cfg) phpPackage;
+
   configVersion = 26;
 
   dbPort = if cfg.database.port == null
@@ -26,7 +28,7 @@ let
       ;
   in pkgs.writeText "config.php" ''
     <?php
-      putenv('TTRSS_PHP_EXECUTABLE=${pkgs.php}/bin/php');
+      putenv('TTRSS_PHP_EXECUTABLE=${phpPackage}/bin/php');
 
       putenv('TTRSS_LOCK_DIRECTORY=${cfg.root}/lock');
       putenv('TTRSS_CACHE_DIR=${cfg.root}/cache');
@@ -456,6 +458,15 @@ let
         '';
       };
 
+      phpPackage = lib.mkOption {
+        type = lib.types.package;
+        default = pkgs.php;
+        defaultText = "pkgs.php";
+        description = lib.mdDoc ''
+          php package to use for php fpm and update daemon.
+        '';
+      };
+
       plugins = mkOption {
         type = types.listOf types.str;
         default = ["auth_internal" "note"];
@@ -543,7 +554,7 @@ let
     services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
       ${poolName} = {
         inherit (cfg) user;
-        phpPackage = pkgs.php81;
+        inherit phpPackage;
         settings = mapAttrs (name: mkDefault) {
           "listen.owner" = "nginx";
           "listen.group" = "nginx";
@@ -605,13 +616,13 @@ let
         description = "Tiny Tiny RSS feeds update daemon";
 
         preStart = ''
-          ${pkgs.php81}/bin/php ${cfg.root}/www/update.php --update-schema
+          ${phpPackage}/bin/php ${cfg.root}/www/update.php --update-schema --force-yes
         '';
 
         serviceConfig = {
           User = "${cfg.user}";
           Group = "tt_rss";
-          ExecStart = "${pkgs.php}/bin/php ${cfg.root}/www/update.php --daemon --quiet";
+          ExecStart = "${phpPackage}/bin/php ${cfg.root}/www/update.php --daemon --quiet";
           Restart = "on-failure";
           RestartSec = "60";
           SyslogIdentifier = "tt-rss";
diff --git a/nixos/modules/services/web-apps/youtrack.nix b/nixos/modules/services/web-apps/youtrack.nix
index abb4292113b6..08e180b520f0 100644
--- a/nixos/modules/services/web-apps/youtrack.nix
+++ b/nixos/modules/services/web-apps/youtrack.nix
@@ -137,7 +137,7 @@ in
   config = lib.mkIf cfg.enable {
     warnings = lib.optional (lib.versions.major cfg.package.version <= "2022")
       "YouTrack 2022.x is deprecated. See https://nixos.org/manual/nixos/unstable/index.html#module-services-youtrack for details on how to upgrade."
-    ++ lib.optional (cfg.extraParams != "" && (lib.versions.major cfg.package.version >= "2023"))
+    ++ lib.optional (cfg.extraParams != {} && (lib.versions.major cfg.package.version >= "2023"))
       "'services.youtrack.extraParams' is deprecated and has no effect on YouTrack 2023.x and newer. Please migrate to 'services.youtrack.generalParameters'"
     ++ lib.optional (cfg.jvmOpts != "" && (lib.versions.major cfg.package.version >= "2023"))
       "'services.youtrack.jvmOpts' is deprecated and has no effect on YouTrack 2023.x and newer. Please migrate to 'services.youtrack.generalParameters'";
@@ -231,7 +231,7 @@ in
     users.groups.youtrack = {};
 
     services.nginx = lib.mkIf (cfg.virtualHost != null) {
-      upstreams.youtrack.servers."${cfg.address}:${toString cfg.port}" = {};
+      upstreams.youtrack.servers."${cfg.address}:${toString cfg.environmentalParameters.listen-port}" = {};
       virtualHosts.${cfg.virtualHost}.locations = {
         "/" = {
           proxyPass = "http://youtrack";
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 6799de6c7d96..93b1a3fdfadd 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -361,10 +361,12 @@ let
             ${optionalString (vhost.acmeFallbackHost != null) "try_files $uri @acme-fallback;"}
             ${optionalString (vhost.acmeRoot != null) "root ${vhost.acmeRoot};"}
             auth_basic off;
+            auth_request off;
           }
           ${optionalString (vhost.acmeFallbackHost != null) ''
             location @acme-fallback {
               auth_basic off;
+              auth_request off;
               proxy_pass http://${vhost.acmeFallbackHost};
             }
           ''}
diff --git a/nixos/modules/services/x11/desktop-managers/phosh.nix b/nixos/modules/services/x11/desktop-managers/phosh.nix
index 5392ab73aeb8..75e02130addc 100644
--- a/nixos/modules/services/x11/desktop-managers/phosh.nix
+++ b/nixos/modules/services/x11/desktop-managers/phosh.nix
@@ -186,6 +186,21 @@ in
         UtmpIdentifier = "tty7";
         UtmpMode = "user";
       };
+      environment = {
+        # We are running without a display manager, so need to provide
+        # a value for XDG_CURRENT_DESKTOP.
+        #
+        # Among other things, this variable influences:
+        #  - visibility of desktop entries with "OnlyShowIn=Phosh;"
+        #    https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.5.html#key-onlyshowin
+        #  - the chosen xdg-desktop-portal configuration.
+        #    https://flatpak.github.io/xdg-desktop-portal/docs/portals.conf.html
+        XDG_CURRENT_DESKTOP = "Phosh:GNOME";
+        # pam_systemd uses these to identify the session in logind.
+        # https://www.freedesktop.org/software/systemd/man/latest/pam_systemd.html#desktop=
+        XDG_SESSION_DESKTOP = "phosh";
+        XDG_SESSION_TYPE = "wayland";
+      };
     };
 
     environment.systemPackages = [
diff --git a/nixos/modules/system/boot/systemd/journald.nix b/nixos/modules/system/boot/systemd/journald.nix
index 9a8e7d592603..62e24a305dde 100644
--- a/nixos/modules/system/boot/systemd/journald.nix
+++ b/nixos/modules/system/boot/systemd/journald.nix
@@ -56,7 +56,9 @@ in {
         journald.conf(5)](https://www.freedesktop.org/software/systemd/man/journald.conf.html).
 
         Note that the total amount of logs stored is limited by journald settings
-        such as `SystemMaxUse`, which defaults to a 4 GB cap.
+        such as `SystemMaxUse`, which defaults to 10% the file system size
+        (capped at max 4GB), and `SystemKeepFree`, which defaults to 15% of the
+        file system size.
 
         It is thus recommended to compute what period of time that you will be
         able to store logs for when an application logs at full burst rate.
diff --git a/nixos/modules/system/boot/systemd/sysupdate.nix b/nixos/modules/system/boot/systemd/sysupdate.nix
index cab35ddf270c..1f4088ddf825 100644
--- a/nixos/modules/system/boot/systemd/sysupdate.nix
+++ b/nixos/modules/system/boot/systemd/sysupdate.nix
@@ -3,7 +3,7 @@
 let
   cfg = config.systemd.sysupdate;
 
-  format = pkgs.formats.ini { };
+  format = pkgs.formats.ini { listToValue = toString; };
 
   definitionsDirectory = utils.systemdUtils.lib.definitions
     "sysupdate.d"
@@ -79,7 +79,7 @@ in
           Source = {
             Type = "url-file";
             Path = "https://download.example.com/";
-            MatchPattern = "nixos_@v.efi.xz";
+            MatchPattern = [ "nixos_@v+@l-@d.efi" "nixos_@v+@l.efi" "nixos_@v.efi" ];
           };
 
           Target = {
diff --git a/nixos/modules/system/boot/uki.nix b/nixos/modules/system/boot/uki.nix
index 63c4e0c0e391..63a7cbc5967b 100644
--- a/nixos/modules/system/boot/uki.nix
+++ b/nixos/modules/system/boot/uki.nix
@@ -51,16 +51,16 @@ in
     else
       "nixos");
 
-    boot.uki.settings = lib.mkOptionDefault {
+    boot.uki.settings = {
       UKI = {
-        Linux = "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}";
-        Initrd = "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
-        Cmdline = "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}";
-        Stub = "${pkgs.systemd}/lib/systemd/boot/efi/linux${efiArch}.efi.stub";
-        Uname = "${config.boot.kernelPackages.kernel.modDirVersion}";
-        OSRelease = "@${config.system.build.etc}/etc/os-release";
+        Linux = lib.mkOptionDefault "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}";
+        Initrd = lib.mkOptionDefault "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
+        Cmdline = lib.mkOptionDefault "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}";
+        Stub = lib.mkOptionDefault "${pkgs.systemd}/lib/systemd/boot/efi/linux${efiArch}.efi.stub";
+        Uname = lib.mkOptionDefault "${config.boot.kernelPackages.kernel.modDirVersion}";
+        OSRelease = lib.mkOptionDefault "@${config.system.build.etc}/etc/os-release";
         # This is needed for cross compiling.
-        EFIArch = efiArch;
+        EFIArch = lib.mkOptionDefault efiArch;
       };
     };
 
diff --git a/nixos/modules/tasks/filesystems/overlayfs.nix b/nixos/modules/tasks/filesystems/overlayfs.nix
new file mode 100644
index 000000000000..e71ef9ba62e9
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/overlayfs.nix
@@ -0,0 +1,144 @@
+{ config, lib, pkgs, utils, ... }:
+
+let
+  # The scripted initrd contains some magic to add the prefix to the
+  # paths just in time, so we don't add it here.
+  sysrootPrefix = fs:
+    if config.boot.initrd.systemd.enable && (utils.fsNeededForBoot fs) then
+      "/sysroot"
+    else
+      "";
+
+  # Returns a service that creates the required directories before the mount is
+  # created.
+  preMountService = _name: fs:
+    let
+      prefix = sysrootPrefix fs;
+
+      escapedMountpoint = utils.escapeSystemdPath (prefix + fs.mountPoint);
+      mountUnit = "${escapedMountpoint}.mount";
+
+      upperdir = prefix + fs.overlay.upperdir;
+      workdir = prefix + fs.overlay.workdir;
+    in
+    lib.mkIf (fs.overlay.upperdir != null)
+      {
+        "rw-${escapedMountpoint}" = {
+          requiredBy = [ mountUnit ];
+          before = [ mountUnit ];
+          unitConfig = {
+            DefaultDependencies = false;
+            RequiresMountsFor = "${upperdir} ${workdir}";
+          };
+          serviceConfig = {
+            Type = "oneshot";
+            ExecStart = "${pkgs.coreutils}/bin/mkdir -p -m 0755 ${upperdir} ${workdir}";
+          };
+        };
+      };
+
+  overlayOpts = { config, ... }: {
+
+    options.overlay = {
+
+      lowerdir = lib.mkOption {
+        type = with lib.types; nullOr (nonEmptyListOf (either str pathInStore));
+        default = null;
+        description = lib.mdDoc ''
+          The list of path(s) to the lowerdir(s).
+
+          To create a writable overlay, you MUST provide an upperdir and a
+          workdir.
+
+          You can create a read-only overlay when you provide multiple (at
+          least 2!) lowerdirs and neither an upperdir nor a workdir.
+        '';
+      };
+
+      upperdir = lib.mkOption {
+        type = lib.types.nullOr lib.types.str;
+        default = null;
+        description = lib.mdDoc ''
+          The path to the upperdir.
+
+          If this is null, a read-only overlay is created using the lowerdir.
+
+          If you set this to some value you MUST also set `workdir`.
+        '';
+      };
+
+      workdir = lib.mkOption {
+        type = lib.types.nullOr lib.types.str;
+        default = null;
+        description = lib.mdDoc ''
+          The path to the workdir.
+
+          This MUST be set if you set `upperdir`.
+        '';
+      };
+
+    };
+
+    config = lib.mkIf (config.overlay.lowerdir != null) {
+      fsType = "overlay";
+      device = lib.mkDefault "overlay";
+
+      options =
+        let
+          prefix = sysrootPrefix config;
+
+          lowerdir = map (s: prefix + s) config.overlay.lowerdir;
+          upperdir = prefix + config.overlay.upperdir;
+          workdir = prefix + config.overlay.workdir;
+        in
+        [
+          "lowerdir=${lib.concatStringsSep ":" lowerdir}"
+        ] ++ lib.optionals (config.overlay.upperdir != null) [
+          "upperdir=${upperdir}"
+          "workdir=${workdir}"
+        ] ++ (map (s: "x-systemd.requires-mounts-for=${s}") lowerdir);
+    };
+
+  };
+in
+
+{
+
+  options = {
+
+    # Merge the overlay options into the fileSystems option.
+    fileSystems = lib.mkOption {
+      type = lib.types.attrsOf (lib.types.submodule [ overlayOpts ]);
+    };
+
+  };
+
+  config =
+    let
+      overlayFileSystems = lib.filterAttrs (_name: fs: (fs.overlay.lowerdir != null)) config.fileSystems;
+      initrdFileSystems = lib.filterAttrs (_name: utils.fsNeededForBoot) overlayFileSystems;
+      userspaceFileSystems = lib.filterAttrs (_name: fs: (!utils.fsNeededForBoot fs)) overlayFileSystems;
+    in
+    {
+
+      boot.initrd.availableKernelModules = lib.mkIf (initrdFileSystems != { }) [ "overlay" ];
+
+      assertions = lib.concatLists (lib.mapAttrsToList
+        (_name: fs: [
+          {
+            assertion = (fs.overlay.upperdir == null) == (fs.overlay.workdir == null);
+            message = "You cannot define a `lowerdir` without a `workdir` and vice versa for mount point: ${fs.mountPoint}";
+          }
+          {
+            assertion = (fs.overlay.lowerdir != null && fs.overlay.upperdir == null) -> (lib.length fs.overlay.lowerdir) >= 2;
+            message = "A read-only overlay (without an `upperdir`) requires at least 2 `lowerdir`s: ${fs.mountPoint}";
+          }
+        ])
+        config.fileSystems);
+
+      boot.initrd.systemd.services = lib.mkMerge (lib.mapAttrsToList preMountService initrdFileSystems);
+      systemd.services = lib.mkMerge (lib.mapAttrsToList preMountService userspaceFileSystems);
+
+    };
+
+}
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index f0d9b95f81f6..c7fe1bed5159 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -103,4 +103,5 @@ in
     # (e.g. it depends on GTK).
     services.udisks2.enable = false;
   };
+  meta.maintainers = with maintainers; [ arianvp ];
 }
diff --git a/nixos/modules/virtualisation/amazon-init.nix b/nixos/modules/virtualisation/amazon-init.nix
index 8b98f2e32dd5..8475097df07c 100644
--- a/nixos/modules/virtualisation/amazon-init.nix
+++ b/nixos/modules/virtualisation/amazon-init.nix
@@ -84,4 +84,5 @@ in {
       };
     };
   };
+  meta.maintainers = with maintainers; [ arianvp ];
 }
diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix
index 217242a8fbd2..b8f952d3ba0e 100644
--- a/nixos/modules/virtualisation/libvirtd.nix
+++ b/nixos/modules/virtualisation/libvirtd.nix
@@ -466,6 +466,7 @@ in
         Type = "notify";
         KillMode = "process"; # when stopping, leave the VMs alone
         Restart = "no";
+        OOMScoreAdjust = "-999";
       };
       restartIfChanged = false;
     };
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 3d7f3ccb62f8..57e2c38301a0 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -701,7 +701,10 @@ in
           type = types.listOf types.str;
           default = [];
           example = [ "-vga std" ];
-          description = lib.mdDoc "Options passed to QEMU.";
+          description = lib.mdDoc ''
+            Options passed to QEMU.
+            See [QEMU User Documentation](https://www.qemu.org/docs/master/system/qemu-manpage) for a complete list.
+          '';
         };
 
       consoles = mkOption {
@@ -732,6 +735,7 @@ in
           description = lib.mdDoc ''
             Networking-related command-line options that should be passed to qemu.
             The default is to use userspace networking (SLiRP).
+            See the [QEMU Wiki on Networking](https://wiki.qemu.org/Documentation/Networking) for details.
 
             If you override this option, be advised to keep
             ''${QEMU_NET_OPTS:+,$QEMU_NET_OPTS} (as seen in the example)
@@ -1066,10 +1070,18 @@ in
         ''}
       '';
 
-    systemd.tmpfiles.rules = lib.mkIf config.boot.initrd.systemd.enable [
-      "f /etc/NIXOS 0644 root root -"
-      "d /boot 0644 root root -"
-    ];
+    systemd.tmpfiles.settings."10-qemu-vm" = lib.mkIf config.boot.initrd.systemd.enable {
+      "/etc/NIXOS".f = {
+        mode = "0644";
+        user = "root";
+        group = "root";
+      };
+      "${config.boot.loader.efi.efiSysMountPoint}".d = {
+        mode = "0644";
+        user = "root";
+        group = "root";
+      };
+    };
 
     # After booting, register the closure of the paths in
     # `virtualisation.additionalPaths' in the Nix database in the VM.  This
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index c943179051cc..31af6ec64214 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -301,6 +301,7 @@ in {
   fenics = handleTest ./fenics.nix {};
   ferm = handleTest ./ferm.nix {};
   ferretdb = handleTest ./ferretdb.nix {};
+  filesystems-overlayfs = runTest ./filesystems-overlayfs.nix;
   firefox = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox; };
   firefox-beta = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-beta; };
   firefox-devedition = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-devedition; };
@@ -425,6 +426,7 @@ in {
   inspircd = handleTest ./inspircd.nix {};
   installer = handleTest ./installer.nix {};
   installer-systemd-stage-1 = handleTest ./installer-systemd-stage-1.nix {};
+  intune = handleTest ./intune.nix {};
   invoiceplane = handleTest ./invoiceplane.nix {};
   iodine = handleTest ./iodine.nix {};
   ipv6 = handleTest ./ipv6.nix {};
@@ -933,6 +935,7 @@ in {
   upnp.nftables = handleTest ./upnp.nix { useNftables = true; };
   uptermd = handleTest ./uptermd.nix {};
   uptime-kuma = handleTest ./uptime-kuma.nix {};
+  urn-timer = handleTest ./urn-timer.nix {};
   usbguard = handleTest ./usbguard.nix {};
   user-activation-scripts = handleTest ./user-activation-scripts.nix {};
   user-expiry = runTest ./user-expiry.nix;
diff --git a/nixos/tests/ayatana-indicators.nix b/nixos/tests/ayatana-indicators.nix
index c9cbbda4c601..a7de640f9e37 100644
--- a/nixos/tests/ayatana-indicators.nix
+++ b/nixos/tests/ayatana-indicators.nix
@@ -29,6 +29,7 @@ in {
       packages = with pkgs; [
         ayatana-indicator-datetime
         ayatana-indicator-messages
+        ayatana-indicator-session
       ] ++ (with pkgs.lomiri; [
         lomiri-indicator-network
         telephony-service
diff --git a/nixos/tests/filesystems-overlayfs.nix b/nixos/tests/filesystems-overlayfs.nix
new file mode 100644
index 000000000000..d7cbf640abe4
--- /dev/null
+++ b/nixos/tests/filesystems-overlayfs.nix
@@ -0,0 +1,89 @@
+{ lib, pkgs, ... }:
+
+let
+  initrdLowerdir = pkgs.runCommand "initrd-lowerdir" { } ''
+    mkdir -p $out
+    echo "initrd" > $out/initrd.txt
+  '';
+  initrdLowerdir2 = pkgs.runCommand "initrd-lowerdir-2" { } ''
+    mkdir -p $out
+    echo "initrd2" > $out/initrd2.txt
+  '';
+  userspaceLowerdir = pkgs.runCommand "userspace-lowerdir" { } ''
+    mkdir -p $out
+    echo "userspace" > $out/userspace.txt
+  '';
+  userspaceLowerdir2 = pkgs.runCommand "userspace-lowerdir-2" { } ''
+    mkdir -p $out
+    echo "userspace2" > $out/userspace2.txt
+  '';
+in
+{
+
+  name = "writable-overlays";
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  nodes.machine = { config, pkgs, ... }: {
+    boot.initrd.systemd.enable = true;
+    boot.initrd.availableKernelModules = [ "overlay" ];
+
+    virtualisation.fileSystems = {
+      "/initrd-overlay" = {
+        overlay = {
+          lowerdir = [ initrdLowerdir ];
+          upperdir = "/.rw-initrd-overlay/upper";
+          workdir = "/.rw-initrd-overlay/work";
+        };
+        neededForBoot = true;
+      };
+      "/userspace-overlay" = {
+        overlay = {
+          lowerdir = [ userspaceLowerdir ];
+          upperdir = "/.rw-userspace-overlay/upper";
+          workdir = "/.rw-userspace-overlay/work";
+        };
+      };
+      "/ro-initrd-overlay" = {
+        overlay.lowerdir = [
+          initrdLowerdir
+          initrdLowerdir2
+        ];
+        neededForBoot = true;
+      };
+      "/ro-userspace-overlay" = {
+        overlay.lowerdir = [
+          userspaceLowerdir
+          userspaceLowerdir2
+        ];
+      };
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("default.target")
+
+    with subtest("Initrd overlay"):
+      machine.wait_for_file("/initrd-overlay/initrd.txt", 5)
+      machine.succeed("touch /initrd-overlay/writable.txt")
+      machine.succeed("findmnt --kernel --types overlay /initrd-overlay")
+
+    with subtest("Userspace overlay"):
+      machine.wait_for_file("/userspace-overlay/userspace.txt", 5)
+      machine.succeed("touch /userspace-overlay/writable.txt")
+      machine.succeed("findmnt --kernel --types overlay /userspace-overlay")
+
+    with subtest("Read only initrd overlay"):
+      machine.wait_for_file("/ro-initrd-overlay/initrd.txt", 5)
+      machine.wait_for_file("/ro-initrd-overlay/initrd2.txt", 5)
+      machine.fail("touch /ro-initrd-overlay/not-writable.txt")
+      machine.succeed("findmnt --kernel --types overlay /ro-initrd-overlay")
+
+    with subtest("Read only userspace overlay"):
+      machine.wait_for_file("/ro-userspace-overlay/userspace.txt", 5)
+      machine.wait_for_file("/ro-userspace-overlay/userspace2.txt", 5)
+      machine.fail("touch /ro-userspace-overlay/not-writable.txt")
+      machine.succeed("findmnt --kernel --types overlay /ro-userspace-overlay")
+  '';
+
+}
diff --git a/nixos/tests/freetube.nix b/nixos/tests/freetube.nix
index f285384b68e0..faa534938227 100644
--- a/nixos/tests/freetube.nix
+++ b/nixos/tests/freetube.nix
@@ -23,6 +23,8 @@ let
       inherit name;
       nodes = { "${name}" = machine; };
       meta.maintainers = with pkgs.lib.maintainers; [ kirillrdy ];
+      # time-out on ofborg
+      meta.broken = pkgs.stdenv.isAarch64;
       enableOCR = true;
 
       testScript = ''
diff --git a/nixos/tests/frigate.nix b/nixos/tests/frigate.nix
index 836fe0d063f8..03bd2b89611d 100644
--- a/nixos/tests/frigate.nix
+++ b/nixos/tests/frigate.nix
@@ -41,6 +41,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} :
         serviceConfig = {
           DynamicUser = true;
           ExecStart = "${lib.getBin pkgs.ffmpeg-headless}/bin/ffmpeg -re -f lavfi -i smptebars=size=800x600:rate=10 -f mpegts -listen 1 http://0.0.0.0:8080";
+          Restart = "always";
         };
       };
     };
@@ -51,10 +52,14 @@ import ./make-test-python.nix ({ pkgs, lib, ...} :
 
     machine.wait_for_unit("frigate.service")
 
+    # Frigate startup
     machine.wait_for_open_port(5001)
 
-    machine.succeed("curl http://localhost:5001")
+    # nginx startup
+    machine.wait_for_open_port(80)
 
-    machine.wait_for_file("/var/cache/frigate/test-*.mp4")
+    machine.succeed("curl http://localhost")
+
+    machine.wait_for_file("/var/cache/frigate/test@*.mp4")
   '';
 })
diff --git a/nixos/tests/gitlab.nix b/nixos/tests/gitlab.nix
index 8d3126425311..c4d69a56c93a 100644
--- a/nixos/tests/gitlab.nix
+++ b/nixos/tests/gitlab.nix
@@ -419,7 +419,7 @@ in {
       gitlab.systemctl("start gitlab-backup.service")
       gitlab.wait_for_unit("gitlab-backup.service")
       gitlab.wait_for_file("${nodes.gitlab.services.gitlab.statePath}/backup/dump_gitlab_backup.tar")
-      gitlab.systemctl("stop postgresql.service gitlab.target")
+      gitlab.systemctl("stop postgresql.service gitlab-config.service gitlab.target")
       gitlab.succeed(
           "find ${nodes.gitlab.services.gitlab.statePath} -mindepth 1 -maxdepth 1 -not -name backup -execdir rm -r {} +"
       )
diff --git a/nixos/tests/incus/lxd-to-incus.nix b/nixos/tests/incus/lxd-to-incus.nix
index 42a47a6a07af..c0fc98c224df 100644
--- a/nixos/tests/incus/lxd-to-incus.nix
+++ b/nixos/tests/incus/lxd-to-incus.nix
@@ -18,8 +18,6 @@ import ../make-test-python.nix (
     nodes.machine =
       { lib, ... }:
       {
-        environment.systemPackages = [ pkgs.lxd-to-incus ];
-
         virtualisation = {
           diskSize = 6144;
           cores = 2;
diff --git a/nixos/tests/installed-tests/fwupd.nix b/nixos/tests/installed-tests/fwupd.nix
index c095a50dc836..fe4f443d7004 100644
--- a/nixos/tests/installed-tests/fwupd.nix
+++ b/nixos/tests/installed-tests/fwupd.nix
@@ -1,11 +1,12 @@
-{ pkgs, lib, makeInstalledTest, ... }:
+{ pkgs, makeInstalledTest, ... }:
 
 makeInstalledTest {
   tested = pkgs.fwupd;
 
   testConfig = {
-    services.fwupd.enable = true;
-    services.fwupd.daemonSettings.DisabledPlugins = lib.mkForce [ ]; # don't disable test plugin
-    services.fwupd.enableTestRemote = true;
+    services.fwupd = {
+      enable = true;
+      daemonSettings.TestDevices = true;
+    };
   };
 }
diff --git a/nixos/tests/intune.nix b/nixos/tests/intune.nix
new file mode 100644
index 000000000000..41bf638d7661
--- /dev/null
+++ b/nixos/tests/intune.nix
@@ -0,0 +1,56 @@
+import ./make-test-python.nix ({ pkgs, ...} : {
+  name = "intune";
+  meta = {
+    maintainers = with pkgs.lib.maintainers; [ rhysmdnz ];
+  };
+  enableOCR = true;
+
+  nodes.machine =
+    { nodes, ... }:
+    let user = nodes.machine.users.users.alice;
+    in {
+      services.intune.enable=true;
+      services.gnome.gnome-keyring.enable = true;
+      imports = [ ./common/user-account.nix ./common/x11.nix ];
+      test-support.displayManager.auto.user = user.name;
+      environment = {
+        variables.DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/user/${builtins.toString user.uid}/bus";
+      };
+    };
+  nodes.pam =
+    { nodes, ... }:
+    let user = nodes.machine.users.users.alice;
+    in {
+      services.intune.enable=true;
+      imports = [ ./common/user-account.nix ];
+    };
+
+  testScript = ''
+    start_all()
+
+    # Check System Daemons successfully start
+    machine.succeed("systemctl start microsoft-identity-device-broker.service")
+    machine.succeed("systemctl start intune-daemon.service")
+
+    # Check User Daemons and intune-portal execurtable works
+    # Going any further than starting it would require internet access and a microsoft account
+    machine.wait_for_x()
+    # TODO: This needs an unlocked user keychain before it will work
+    #machine.succeed("su - alice -c 'systemctl start --user microsoft-identity-broker.service'")
+    machine.succeed("su - alice -c 'systemctl start --user intune-agent.service'")
+    machine.succeed("su - alice -c intune-portal >&2 &")
+    machine.wait_for_text("Intune Agent")
+
+    # Check logging in creates password file
+    def login_as_alice():
+        pam.wait_until_tty_matches("1", "login: ")
+        pam.send_chars("alice\n")
+        pam.wait_until_tty_matches("1", "Password: ")
+        pam.send_chars("foobar\n")
+        pam.wait_until_tty_matches("1", "alice\@pam")
+
+    pam.wait_for_unit("multi-user.target")
+    login_as_alice()
+    pam.wait_for_file("/run/intune/1000/pwquality")
+  '';
+})
diff --git a/nixos/tests/kernel-generic.nix b/nixos/tests/kernel-generic.nix
index 34c04e8351ce..0dcab39f3fad 100644
--- a/nixos/tests/kernel-generic.nix
+++ b/nixos/tests/kernel-generic.nix
@@ -23,7 +23,7 @@ let
         assert "${linuxPackages.kernel.modDirVersion}" in machine.succeed("uname -a")
       '';
   }) args);
-  kernels = pkgs.linuxKernel.vanillaPackages // {
+  kernels = (removeAttrs pkgs.linuxKernel.vanillaPackages ["__attrsFailEvaluation"]) // {
     inherit (pkgs.linuxKernel.packages)
       linux_4_19_hardened
       linux_5_4_hardened
diff --git a/nixos/tests/systemd-sysupdate.nix b/nixos/tests/systemd-sysupdate.nix
index 37811605dbb2..6592764c9ff4 100644
--- a/nixos/tests/systemd-sysupdate.nix
+++ b/nixos/tests/systemd-sysupdate.nix
@@ -23,8 +23,8 @@ in
             mkdir -p $out
             cd $out
 
-            echo "nixos" > nixos_1.efi
-            sha256sum nixos_1.efi > SHA256SUMS
+            echo "nixos" > nixos_1.txt
+            sha256sum nixos_1.txt > SHA256SUMS
 
             export GNUPGHOME="$(mktemp -d)"
             cp -R ${gpgKeyring}/* $GNUPGHOME
@@ -39,15 +39,15 @@ in
       systemd.sysupdate = {
         enable = true;
         transfers = {
-          "uki" = {
+          "text-file" = {
             Source = {
               Type = "url-file";
               Path = "http://server/";
-              MatchPattern = "nixos_@v.efi";
+              MatchPattern = "nixos_@v.txt";
             };
             Target = {
-              Path = "/boot/EFI/Linux";
-              MatchPattern = "nixos_@v.efi";
+              Path = "/";
+              MatchPattern = [ "nixos_@v.txt" ];
             };
           };
         };
@@ -61,6 +61,6 @@ in
     server.wait_for_unit("nginx.service")
 
     target.succeed("systemctl start systemd-sysupdate")
-    assert "nixos" in target.wait_until_succeeds("cat /boot/EFI/Linux/nixos_1.efi", timeout=5)
+    assert "nixos" in target.wait_until_succeeds("cat /nixos_1.txt", timeout=5)
   '';
 }
diff --git a/nixos/tests/tsm-client-gui.nix b/nixos/tests/tsm-client-gui.nix
index c9632546db6e..ca10cddc411f 100644
--- a/nixos/tests/tsm-client-gui.nix
+++ b/nixos/tests/tsm-client-gui.nix
@@ -31,7 +31,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
     machine.execute("DSM_LOG=/tmp dsmj -optfile=/dev/null >&2 &")
 
     # does it report the "TCP/IP connection failure" error code?
-    machine.wait_for_window("IBM Spectrum Protect")
+    machine.wait_for_window("IBM Storage Protect")
     machine.wait_for_text("ANS2610S")
     machine.send_key("esc")
 
diff --git a/nixos/tests/urn-timer.nix b/nixos/tests/urn-timer.nix
new file mode 100644
index 000000000000..10c5bef49b5b
--- /dev/null
+++ b/nixos/tests/urn-timer.nix
@@ -0,0 +1,26 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "urn-timer";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ fgaz ];
+  };
+
+  nodes.machine = { config, pkgs, ... }: {
+    imports = [
+      ./common/x11.nix
+    ];
+
+    services.xserver.enable = true;
+    environment.systemPackages = [ pkgs.urn-timer ];
+  };
+
+  enableOCR = true;
+
+  testScript =
+    ''
+      machine.wait_for_x()
+      machine.execute("urn-gtk ${pkgs.urn-timer.src}/splits_examples/sotn.json >&2 &")
+      machine.wait_for_window("urn")
+      machine.wait_for_text(r"(Mist|Bat|Reverse|Dracula)")
+      machine.screenshot("screen")
+    '';
+})