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/x-windows.chapter.md1
-rw-r--r--nixos/doc/manual/default.nix7
-rw-r--r--nixos/doc/manual/development/replace-modules.section.md3
-rw-r--r--nixos/doc/manual/development/running-nixos-tests.section.md10
-rw-r--r--nixos/doc/manual/development/writing-modules.chapter.md7
-rw-r--r--nixos/doc/manual/development/writing-nixos-tests.section.md2
-rw-r--r--nixos/doc/manual/installation/installing.chapter.md3
-rw-r--r--nixos/doc/manual/release-notes/rl-2405.section.md43
-rw-r--r--nixos/lib/make-iso9660-image.nix25
-rw-r--r--nixos/lib/make-iso9660-image.sh5
-rw-r--r--nixos/lib/systemd-lib.nix15
-rw-r--r--nixos/lib/test-driver/test_driver/logger.py12
-rw-r--r--nixos/modules/config/nix.nix9
-rw-r--r--nixos/modules/config/no-x-libs.nix2
-rw-r--r--nixos/modules/config/resolvconf.nix2
-rw-r--r--nixos/modules/config/users-groups.nix5
-rw-r--r--nixos/modules/hardware/video/webcam/ipu6.nix5
-rw-r--r--nixos/modules/image/repart-image.nix38
-rw-r--r--nixos/modules/image/repart.nix32
-rw-r--r--nixos/modules/installer/cd-dvd/iso-image.nix11
-rw-r--r--nixos/modules/module-list.nix2
-rw-r--r--nixos/modules/programs/chromium.nix19
-rw-r--r--nixos/modules/programs/clash-verge.nix7
-rw-r--r--nixos/modules/programs/gnupg.nix42
-rw-r--r--nixos/modules/programs/steam.nix22
-rw-r--r--nixos/modules/programs/wayland/sway.nix5
-rw-r--r--nixos/modules/services/audio/spotifyd.nix4
-rw-r--r--nixos/modules/services/backup/bacula.nix222
-rw-r--r--nixos/modules/services/backup/syncoid.nix2
-rw-r--r--nixos/modules/services/continuous-integration/hydra/default.nix34
-rw-r--r--nixos/modules/services/databases/lldap.nix17
-rw-r--r--nixos/modules/services/databases/memcached.nix2
-rw-r--r--nixos/modules/services/databases/postgresql.md2
-rw-r--r--nixos/modules/services/databases/postgresql.nix45
-rw-r--r--nixos/modules/services/desktop-managers/plasma6.nix (renamed from nixos/modules/services/x11/desktop-managers/plasma6.nix)18
-rw-r--r--nixos/modules/services/desktops/pipewire/wireplumber.nix30
-rw-r--r--nixos/modules/services/development/hoogle.nix15
-rw-r--r--nixos/modules/services/hardware/fwupd.nix4
-rw-r--r--nixos/modules/services/mail/listmonk.nix6
-rw-r--r--nixos/modules/services/matrix/matrix-sliding-sync.nix3
-rw-r--r--nixos/modules/services/matrix/synapse.nix3
-rw-r--r--nixos/modules/services/misc/etebase-server.nix29
-rw-r--r--nixos/modules/services/misc/llama-cpp.nix2
-rw-r--r--nixos/modules/services/misc/ollama.nix60
-rw-r--r--nixos/modules/services/misc/tabby.nix203
-rw-r--r--nixos/modules/services/monitoring/mackerel-agent.nix2
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/restic.nix13
-rw-r--r--nixos/modules/services/monitoring/scrutiny.nix218
-rw-r--r--nixos/modules/services/networking/murmur.nix2
-rw-r--r--nixos/modules/services/networking/nebula.nix34
-rw-r--r--nixos/modules/services/networking/networkmanager.nix8
-rw-r--r--nixos/modules/services/networking/tinyproxy.nix1
-rw-r--r--nixos/modules/services/networking/unbound.nix9
-rw-r--r--nixos/modules/services/security/esdm.nix101
-rw-r--r--nixos/modules/services/security/yubikey-agent.nix14
-rw-r--r--nixos/modules/services/web-apps/engelsystem.nix1
-rw-r--r--nixos/modules/services/web-apps/gotosocial.nix2
-rw-r--r--nixos/modules/services/web-apps/komga.nix145
-rw-r--r--nixos/modules/services/web-apps/nextcloud.nix1
-rw-r--r--nixos/modules/services/web-apps/pretix.nix580
-rw-r--r--nixos/modules/services/web-servers/stargazer.nix8
-rw-r--r--nixos/modules/services/x11/desktop-managers/budgie.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/deepin.nix1
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/lxqt.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/mate.nix126
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix1
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix1
-rw-r--r--nixos/modules/services/x11/window-managers/xmonad.nix2
-rw-r--r--nixos/modules/services/x11/xserver.nix2
-rw-r--r--nixos/modules/system/boot/binfmt.nix1
-rw-r--r--nixos/modules/system/boot/networkd.nix6
-rw-r--r--nixos/modules/system/boot/stage-1.nix2
-rw-r--r--nixos/modules/system/boot/systemd.nix2
-rw-r--r--nixos/modules/system/boot/systemd/initrd.nix38
-rw-r--r--nixos/modules/system/boot/timesyncd.nix3
-rw-r--r--nixos/modules/system/boot/uki.nix2
-rw-r--r--nixos/modules/testing/test-instrumentation.nix10
-rw-r--r--nixos/modules/virtualisation/amazon-ec2-amis.nix68
-rw-r--r--nixos/modules/virtualisation/amazon-image.nix4
-rw-r--r--nixos/modules/virtualisation/incus.nix13
-rw-r--r--nixos/modules/virtualisation/oci-containers.nix2
-rw-r--r--nixos/tests/all-tests.nix8
-rw-r--r--nixos/tests/budgie.nix46
-rw-r--r--nixos/tests/freetube.nix2
-rw-r--r--nixos/tests/hibernate.nix2
-rw-r--r--nixos/tests/incus/container.nix1
-rw-r--r--nixos/tests/incus/default.nix2
-rw-r--r--nixos/tests/incus/lxd-to-incus.nix1
-rw-r--r--nixos/tests/incus/openvswitch.nix65
-rw-r--r--nixos/tests/incus/preseed.nix1
-rw-r--r--nixos/tests/incus/socket-activated.nix1
-rw-r--r--nixos/tests/incus/storage.nix46
-rw-r--r--nixos/tests/incus/ui.nix1
-rw-r--r--nixos/tests/incus/virtual-machine.nix1
-rw-r--r--nixos/tests/installer-systemd-stage-1.nix1
-rw-r--r--nixos/tests/installer.nix42
-rw-r--r--nixos/tests/keycloak.nix32
-rw-r--r--nixos/tests/knot.nix21
-rw-r--r--nixos/tests/krb5/default.nix3
-rw-r--r--nixos/tests/make-test-python.nix2
-rw-r--r--nixos/tests/mate-wayland.nix63
-rw-r--r--nixos/tests/mate.nix9
-rw-r--r--nixos/tests/miriway.nix4
-rw-r--r--nixos/tests/nebula.nix6
-rw-r--r--nixos/tests/nix-config.nix18
-rw-r--r--nixos/tests/nixops/default.nix3
-rw-r--r--nixos/tests/ollama.nix56
-rw-r--r--nixos/tests/opensearch.nix30
-rw-r--r--nixos/tests/pass-secret-service.nix1
-rw-r--r--nixos/tests/pg_anonymizer.nix94
-rw-r--r--nixos/tests/pgvecto-rs.nix76
-rw-r--r--nixos/tests/privoxy.nix13
-rw-r--r--nixos/tests/sanoid.nix3
-rw-r--r--nixos/tests/systemd-machinectl.nix41
-rw-r--r--nixos/tests/vscodium.nix2
-rw-r--r--nixos/tests/web-apps/gotosocial.nix2
-rw-r--r--nixos/tests/web-apps/pretix.nix47
118 files changed, 2571 insertions, 639 deletions
diff --git a/nixos/doc/manual/configuration/x-windows.chapter.md b/nixos/doc/manual/configuration/x-windows.chapter.md
index 0451e4d25265..bf1872ae01ac 100644
--- a/nixos/doc/manual/configuration/x-windows.chapter.md
+++ b/nixos/doc/manual/configuration/x-windows.chapter.md
@@ -150,6 +150,7 @@ Or if you have an older card, you may have to use one of the legacy
 drivers:
 
 ```nix
+services.xserver.videoDrivers = [ "nvidiaLegacy470" ];
 services.xserver.videoDrivers = [ "nvidiaLegacy390" ];
 services.xserver.videoDrivers = [ "nvidiaLegacy340" ];
 services.xserver.videoDrivers = [ "nvidiaLegacy304" ];
diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix
index a368b16201f8..5f51bb53ad7f 100644
--- a/nixos/doc/manual/default.nix
+++ b/nixos/doc/manual/default.nix
@@ -105,7 +105,9 @@ in rec {
       mkdir -p $dst
 
       cp ${../../../doc/style.css} $dst/style.css
-      cp ${../../../doc/overrides.css} $dst/overrides.css
+      cp ${../../../doc/anchor.min.js} $dst/anchor.min.js
+      cp ${../../../doc/anchor-use.js} $dst/anchor-use.js
+
       cp -r ${pkgs.documentation-highlighter} $dst/highlightjs
 
       ${prepareManualFromMD}
@@ -115,10 +117,11 @@ in rec {
         --revision ${lib.escapeShellArg revision} \
         --generator "nixos-render-docs ${lib.version}" \
         --stylesheet style.css \
-        --stylesheet overrides.css \
         --stylesheet highlightjs/mono-blue.css \
         --script ./highlightjs/highlight.pack.js \
         --script ./highlightjs/loader.js \
+        --script ./anchor.min.js \
+        --script ./anchor-use.js \
         --toc-depth 1 \
         --chunk-toc-depth 1 \
         ./manual.md \
diff --git a/nixos/doc/manual/development/replace-modules.section.md b/nixos/doc/manual/development/replace-modules.section.md
index ac9f5adbaf98..45e2adbc2608 100644
--- a/nixos/doc/manual/development/replace-modules.section.md
+++ b/nixos/doc/manual/development/replace-modules.section.md
@@ -47,9 +47,8 @@ without having to know its implementation details.
 ```nix
 { config, lib, pkgs, ... }:
 
-with lib;
-
 let
+  inherit (lib) mkIf mkOption types;
   cfg = config.programs.man;
 in
 
diff --git a/nixos/doc/manual/development/running-nixos-tests.section.md b/nixos/doc/manual/development/running-nixos-tests.section.md
index 33076f5dc2a7..b8191ebd313c 100644
--- a/nixos/doc/manual/development/running-nixos-tests.section.md
+++ b/nixos/doc/manual/development/running-nixos-tests.section.md
@@ -18,3 +18,13 @@ you can view a log of the test:
 ```ShellSession
 $ nix-store --read-log result
 ```
+
+## System Requirements {#sec-running-nixos-tests-requirements}
+
+NixOS tests require virtualization support.
+This means that the machine must have `kvm` in its [system features](https://nixos.org/manual/nix/stable/command-ref/conf-file.html?highlight=system-features#conf-system-features) list, or `apple-virt` in case of macOS.
+These features are autodetected locally, but `apple-virt` is only autodetected since Nix 2.19.0.
+
+Features of **remote builders** must additionally be configured manually on the client, e.g. on NixOS with [`nix.buildMachines.*.supportedFeatures`](https://search.nixos.org/options?show=nix.buildMachines.*.supportedFeatures&sort=alpha_asc&query=nix.buildMachines) or through general [Nix configuration](https://nixos.org/manual/nix/stable/advanced-topics/distributed-builds).
+
+If you run the tests on a **macOS** machine, you also need a "remote" builder for Linux; possibly a VM. [nix-darwin](https://daiderd.com/nix-darwin/) users may enable [`nix.linux-builder.enable`](https://daiderd.com/nix-darwin/manual/index.html#opt-nix.linux-builder.enable) to launch such a VM.
diff --git a/nixos/doc/manual/development/writing-modules.chapter.md b/nixos/doc/manual/development/writing-modules.chapter.md
index e07b899e6df7..20157a21e890 100644
--- a/nixos/doc/manual/development/writing-modules.chapter.md
+++ b/nixos/doc/manual/development/writing-modules.chapter.md
@@ -104,9 +104,8 @@ functions system environment substitution should *not* be disabled explicitly.
 ```nix
 { config, lib, pkgs, ... }:
 
-with lib;
-
 let
+  inherit (lib) concatStringsSep mkIf mkOption optionalString types;
   cfg = config.services.locate;
 in {
   options.services.locate = {
@@ -163,9 +162,7 @@ in {
 ::: {#exec-escaping-example .example}
 ### Escaping in Exec directives
 ```nix
-{ config, lib, pkgs, utils, ... }:
-
-with lib;
+{ config, pkgs, utils, ... }:
 
 let
   cfg = config.services.echo;
diff --git a/nixos/doc/manual/development/writing-nixos-tests.section.md b/nixos/doc/manual/development/writing-nixos-tests.section.md
index 84b247fd2042..50886376c240 100644
--- a/nixos/doc/manual/development/writing-nixos-tests.section.md
+++ b/nixos/doc/manual/development/writing-nixos-tests.section.md
@@ -261,7 +261,7 @@ added using the parameter `extraPythonPackages`. For example, you could add
 
   testScript = ''
     import numpy as np
-    assert str(np.zeros(4) == "array([0., 0., 0., 0.])")
+    assert str(np.zeros(4)) == "[0. 0. 0. 0.]"
   '';
 }
 ```
diff --git a/nixos/doc/manual/installation/installing.chapter.md b/nixos/doc/manual/installation/installing.chapter.md
index 815bcc071cd9..c7deb07352f1 100644
--- a/nixos/doc/manual/installation/installing.chapter.md
+++ b/nixos/doc/manual/installation/installing.chapter.md
@@ -272,6 +272,9 @@ update /etc/fstab.
     # parted /dev/sda -- mkpart ESP fat32 1MB 512MB
     # parted /dev/sda -- set 3 esp on
     ```
+    ::: {.note}
+    In case you decided to not create a swap partition, replace `3` by `2`. To be sure of the id number of ESP, run `parted --list`.
+    :::
 
 Once complete, you can follow with
 [](#sec-installation-manual-partitioning-formatting).
diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md
index daabca2aee60..1a86beaba73f 100644
--- a/nixos/doc/manual/release-notes/rl-2405.section.md
+++ b/nixos/doc/manual/release-notes/rl-2405.section.md
@@ -42,6 +42,12 @@ In addition to numerous new and upgraded packages, this release has the followin
 - A new option `system.etc.overlay.enable` was added. If enabled, `/etc` is
   mounted via an overlayfs instead of being created by a custom perl script.
 
+- NixOS AMIs are now uploaded regularly to a new AWS Account.
+  Instructions on how to use them can be found on <https://nixos.github.io/amis>.
+  We are working on integration the data into the NixOS homepage.
+  The list in `nixos/modules/virtualisation/amazon-ec2-amis.nix` will stop
+  being updated and will be removed in the future.
+
 - It is now possible to have a completely perlless system (i.e. a system
   without perl). Previously, the NixOS activation depended on two perl scripts
   which can now be replaced via an opt-in mechanism. To make your system
@@ -97,6 +103,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - [Monado](https://monado.freedesktop.org/), an open source XR runtime. Available as [services.monado](#opt-services.monado.enable).
 
+- [Pretix](https://pretix.eu/about/en/), an open source ticketing software for events. Available as [services.pretix]($opt-services-pretix.enable).
+
 - [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable).
 
 - [armagetronad](https://wiki.armagetronad.org), a mid-2000s 3D lightcycle game widely played at iD Tech Camps. You can define multiple servers using `services.armagetronad.<server>.enable`.
@@ -117,16 +125,33 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
 
+- `k3s`: was updated to version [v1.29](https://github.com/k3s-io/k3s/releases/tag/v1.29.1%2Bk3s2), all previous versions (k3s_1_26, k3s_1_27, k3s_1_28) will be removed. See [changelog and upgrade notes](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.29.md#urgent-upgrade-notes) for more information.
+
 - `himalaya` was updated to `v1.0.0-beta.3`, which introduces breaking changes. Check out the [release note](https://github.com/soywod/himalaya/releases/tag/v1.0.0-beta.3) for details.
 
 - The `power.ups` module now generates `upsd.conf`, `upsd.users` and `upsmon.conf` automatically from a set of new configuration options. This breaks compatibility with existing `power.ups` setups where these files were created manually. Back up these files before upgrading NixOS.
 
+- `pdns` was updated to version [v4.9.x](https://doc.powerdns.com/authoritative/changelog/4.9.html), which introduces breaking changes. Check out the [Upgrade Notes](https://doc.powerdns.com/authoritative/upgrading.html#to-4-9-0) for details.
+
+- `unrar` was updated to v7. See [changelog](https://www.rarlab.com/unrar7notes.htm) for more information.
+
 - `k9s` was updated to v0.31. There have been various breaking changes in the config file format,
   check out the changelog of [v0.29](https://github.com/derailed/k9s/releases/tag/v0.29.0),
   [v0.30](https://github.com/derailed/k9s/releases/tag/v0.30.0) and
   [v0.31](https://github.com/derailed/k9s/releases/tag/v0.31.0) for details. It is recommended
   to back up your current configuration and let k9s recreate the new base configuration.
 
+- NixOS AMIs are now uploaded regularly to a new AWS Account.
+  Instructions on how to use them can be found on <https://nixos.github.io/amis>.
+  We are working on integration the data into the NixOS homepage.
+  The list in `nixos/modules/virtualisation/amazon-ec2-amis.nix` will stop
+  being updated and will be removed in the future.
+
+- The option `services.postgresql.ensureUsers._.ensurePermissions` has been removed as it's
+  not declarative and is broken with newer postgresql versions. Consider using
+  [](#opt-services.postgresql.ensureUsers._.ensureDBOwnership)
+  instead or a tool that's more suited for managing the data inside a postgresql database.
+
 - `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/)
@@ -152,6 +177,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - `services.homepage-dashboard` now takes it's configuration using native Nix expressions, rather than dumping templated configurations into `/var/lib/homepage-dashboard` where they were previously managed manually. There are now new options which allow the configuration of bookmarks, services, widgets and custom CSS/JS natively in Nix.
 
+- `hare` may now be cross-compiled. For that to work, however, `haredoc` needed to stop being built together with it. Thus, the latter is now its own package with the name of `haredoc`.
+
 - The legacy and long deprecated systemd target `network-interfaces.target` has been removed. Use `network.target` instead.
 
 - `services.frp.settings` now generates the frp configuration file in TOML format as [recommended by upstream](https://github.com/fatedier/frp#configuration-files), instead of the legacy INI format. This has also introduced other changes in the configuration file structure and options.
@@ -297,7 +324,12 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - `addDriverRunpath` has been added to facilitate the deprecation of the old `addOpenGLRunpath` setuphook. This change is motivated by the evolution of the setuphook to include all hardware acceleration.
 
-- Cinnamon has been updated to 6.0. Please beware that the [Wayland session](https://blog.linuxmint.com/?p=4591) is still experimental in this release.
+- Cinnamon has been updated to 6.0. Please beware that the [Wayland session](https://blog.linuxmint.com/?p=4591) is still experimental in this release and could potentially [affect Xorg sessions](https://blog.linuxmint.com/?p=4639). We suggest a reboot when switching between sessions.
+
+- MATE has been updated to 1.28.
+  - To properly support panel plugins built with Wayland (in-process) support, we are introducing `services.xserver.desktopManager.mate.extraPanelApplets` option, please use that for installing panel applets.
+  - Similarly, please use `services.xserver.desktopManager.mate.extraCajaExtensions` option for installing Caja extensions.
+  - To use the Wayland session, enable `services.xserver.desktopManager.mate.enableWaylandSession`. This is opt-in for now as it is in early stage and introduces a new set of Wayfire closure. Due to [known issues with LightDM](https://github.com/canonical/lightdm/issues/63), we suggest using SDDM for display manager.
 
 - New `boot.loader.systemd-boot.xbootldrMountPoint` allows setting up a separate [XBOOTLDR partition](https://uapi-group.org/specifications/specs/boot_loader_specification/) to store boot files. Useful on systems with a small EFI System partition that cannot be easily repartitioned.
 
@@ -324,6 +356,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - [Lilypond](https://lilypond.org/index.html) and [Denemo](https://www.denemo.org) are now compiled with Guile 3.0.
 
+- The EC2 image module now enables the [Amazon SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html) by default.
+
 - The following options of the Nextcloud module were moved into [`services.nextcloud.settings`](#opt-services.nextcloud.settings) and renamed to match the name from Nextcloud's `config.php`:
   - `logLevel` -> [`loglevel`](#opt-services.nextcloud.settings.loglevel),
   - `logType` -> [`log_type`](#opt-services.nextcloud.settings.log_type),
@@ -350,6 +384,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - A new hardening flag, `zerocallusedregs` was made available, corresponding to the gcc/clang option `-fzero-call-used-regs=used-gpr`.
 
+- A new hardening flag, `trivialautovarinit` was made available, corresponding to the gcc/clang option `-ftrivial-auto-var-init=pattern`.
+
 - 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.
 
@@ -364,6 +400,9 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - [Nginx virtual hosts](#opt-services.nginx.virtualHosts) using `forceSSL` or
   `globalRedirect` can now have redirect codes other than 301 through
+
+- `bacula` now allows to configure `TLS` for encrypted communication.
+
   `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`.
@@ -414,4 +453,4 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 - QtMultimedia has changed its default backend to `QT_MEDIA_BACKEND=ffmpeg` (previously `gstreamer` on Linux or `darwin` on MacOS).
   The previous native backends remain available but are now minimally maintained. Refer to [upstream documentation](https://doc.qt.io/qt-6/qtmultimedia-index.html#ffmpeg-as-the-default-backend) for further details about each platform.
 
-- The oil shell is now using the c++ version by default. The python based build is still available as `oil-python`
+- The oil shell's c++ version is now available as `oils-for-unix`. The python version is still available as `oil`
diff --git a/nixos/lib/make-iso9660-image.nix b/nixos/lib/make-iso9660-image.nix
index 2f7dcf519a16..ec520f570682 100644
--- a/nixos/lib/make-iso9660-image.nix
+++ b/nixos/lib/make-iso9660-image.nix
@@ -1,4 +1,4 @@
-{ stdenv, closureInfo, xorriso, syslinux, libossp_uuid
+{ lib, stdenv, callPackage, closureInfo, xorriso, syslinux, libossp_uuid, squashfsTools
 
 , # The file name of the resulting ISO image.
   isoName ? "cd.iso"
@@ -16,6 +16,17 @@
   # symlink to `object' that will be added to the CD.
   storeContents ? []
 
+, # In addition to `contents', the closure of the store paths listed
+  # in `squashfsContents' is compressed as squashfs and the result is
+  # placed in /nix-store.squashfs on the CD.
+  # FIXME: This is a performance optimization to avoid Hydra copying
+  # the squashfs between builders and should be removed when Hydra
+  # is smarter about scheduling.
+  squashfsContents ? []
+
+, # Compression settings for squashfs
+  squashfsCompression ? "xz -Xdict-size 100%"
+
 , # Whether this should be an El-Torito bootable CD.
   bootable ? false
 
@@ -45,12 +56,20 @@ assert bootable -> bootImage != "";
 assert efiBootable -> efiBootImage != "";
 assert usbBootable -> isohybridMbrImage != "";
 
+let
+  needSquashfs = squashfsContents != [];
+  makeSquashfsDrv = callPackage ./make-squashfs.nix {
+    storeContents = squashfsContents;
+    comp = squashfsCompression;
+  };
+in
 stdenv.mkDerivation {
   name = isoName;
   __structuredAttrs = true;
 
   buildCommandPath = ./make-iso9660-image.sh;
-  nativeBuildInputs = [ xorriso syslinux zstd libossp_uuid ];
+  nativeBuildInputs = [ xorriso syslinux zstd libossp_uuid ]
+    ++ lib.optionals needSquashfs makeSquashfsDrv.nativeBuildInputs;
 
   inherit isoName bootable bootImage compressImage volumeID efiBootImage efiBootable isohybridMbrImage usbBootable;
 
@@ -60,6 +79,8 @@ stdenv.mkDerivation {
   objects = map (x: x.object) storeContents;
   symlinks = map (x: x.symlink) storeContents;
 
+  squashfsCommand = lib.optionalString needSquashfs makeSquashfsDrv.buildCommand;
+
   # For obtaining the closure of `storeContents'.
   closureInfo = closureInfo { rootPaths = map (x: x.object) storeContents; };
 }
diff --git a/nixos/lib/make-iso9660-image.sh b/nixos/lib/make-iso9660-image.sh
index 34febe9cfe0e..5881195e461f 100644
--- a/nixos/lib/make-iso9660-image.sh
+++ b/nixos/lib/make-iso9660-image.sh
@@ -68,6 +68,11 @@ for i in $(< $closureInfo/store-paths); do
     addPath "${i:1}" "$i"
 done
 
+# If needed, build a squashfs and add that
+if [[ -n "$squashfsCommand" ]]; then
+    (out="nix-store.squashfs" eval "$squashfsCommand")
+    addPath "nix-store.squashfs" "nix-store.squashfs"
+fi
 
 # Also include a manifest of the closures in a format suitable for
 # nix-store --load-db.
diff --git a/nixos/lib/systemd-lib.nix b/nixos/lib/systemd-lib.nix
index ef218e674ebf..c00b2d0f207c 100644
--- a/nixos/lib/systemd-lib.nix
+++ b/nixos/lib/systemd-lib.nix
@@ -73,13 +73,26 @@ in rec {
     optional (attr ? ${name} && (! isMacAddress attr.${name} && attr.${name} != "none"))
       "Systemd ${group} field `${name}` must be a valid MAC address or the special value `none`.";
 
-
+  isNumberOrRangeOf = check: v:
+    if isInt v
+    then check v
+    else let
+      parts = splitString "-" v;
+      lower = toIntBase10 (head parts);
+      upper = if tail parts != [] then toIntBase10 (head (tail parts)) else lower;
+    in
+      length parts <= 2 && lower <= upper && check lower && check upper;
   isPort = i: i >= 0 && i <= 65535;
+  isPortOrPortRange = isNumberOrRangeOf isPort;
 
   assertPort = name: group: attr:
     optional (attr ? ${name} && ! isPort attr.${name})
       "Error on the systemd ${group} field `${name}': ${attr.name} is not a valid port number.";
 
+  assertPortOrPortRange = name: group: attr:
+    optional (attr ? ${name} && ! isPortOrPortRange attr.${name})
+      "Error on the systemd ${group} field `${name}': ${attr.name} is not a valid port number or range of port numbers.";
+
   assertValueOneOf = name: values: group: attr:
     optional (attr ? ${name} && !elem attr.${name} values)
       "Systemd ${group} field `${name}' cannot have value `${toString attr.${name}}'.";
diff --git a/nixos/lib/test-driver/test_driver/logger.py b/nixos/lib/test-driver/test_driver/logger.py
index 116244b5e4ae..0b0623bddfa1 100644
--- a/nixos/lib/test-driver/test_driver/logger.py
+++ b/nixos/lib/test-driver/test_driver/logger.py
@@ -1,6 +1,3 @@
-# mypy: disable-error-code="no-untyped-call"
-# drop the above line when mypy is upgraded to include
-# https://github.com/python/typeshed/commit/49b717ca52bf0781a538b04c0d76a5513f7119b8
 import codecs
 import os
 import sys
@@ -10,6 +7,7 @@ from contextlib import contextmanager
 from queue import Empty, Queue
 from typing import Any, Dict, Iterator
 from xml.sax.saxutils import XMLGenerator
+from xml.sax.xmlreader import AttributesImpl
 
 from colorama import Fore, Style
 
@@ -22,7 +20,7 @@ class Logger:
         self.queue: "Queue[Dict[str, str]]" = Queue()
 
         self.xml.startDocument()
-        self.xml.startElement("logfile", attrs={})
+        self.xml.startElement("logfile", attrs=AttributesImpl({}))
 
         self._print_serial_logs = True
 
@@ -44,7 +42,7 @@ class Logger:
         return message
 
     def log_line(self, message: str, attributes: Dict[str, str]) -> None:
-        self.xml.startElement("line", attributes)
+        self.xml.startElement("line", attrs=AttributesImpl(attributes))
         self.xml.characters(message)
         self.xml.endElement("line")
 
@@ -89,8 +87,8 @@ class Logger:
             )
         )
 
-        self.xml.startElement("nest", attrs={})
-        self.xml.startElement("head", attributes)
+        self.xml.startElement("nest", attrs=AttributesImpl({}))
+        self.xml.startElement("head", attrs=AttributesImpl(attributes))
         self.xml.characters(message)
         self.xml.endElement("head")
 
diff --git a/nixos/modules/config/nix.nix b/nixos/modules/config/nix.nix
index e6a74bbb73fc..bce6fd5e5028 100644
--- a/nixos/modules/config/nix.nix
+++ b/nixos/modules/config/nix.nix
@@ -14,8 +14,10 @@ let
     concatStringsSep
     boolToString
     escape
+    filterAttrs
     floatToString
     getVersion
+    hasPrefix
     isBool
     isDerivation
     isFloat
@@ -95,14 +97,19 @@ let
 
       mkKeyValuePairs = attrs: concatStringsSep "\n" (mapAttrsToList mkKeyValue attrs);
 
+      isExtra = key: hasPrefix "extra-" key;
+
     in
     pkgs.writeTextFile {
       name = "nix.conf";
+      # workaround for https://github.com/NixOS/nix/issues/9487
+      # extra-* settings must come after their non-extra counterpart
       text = ''
         # WARNING: this file is generated from the nix.* options in
         # your NixOS configuration, typically
         # /etc/nixos/configuration.nix.  Do not edit it!
-        ${mkKeyValuePairs cfg.settings}
+        ${mkKeyValuePairs (filterAttrs (key: value: !(isExtra key)) cfg.settings)}
+        ${mkKeyValuePairs (filterAttrs (key: value: isExtra key) cfg.settings)}
         ${cfg.extraOptions}
       '';
       checkPhase = lib.optionalString cfg.checkConfig (
diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix
index 870b3fe77cca..fea6e0c4110b 100644
--- a/nixos/modules/config/no-x-libs.nix
+++ b/nixos/modules/config/no-x-libs.nix
@@ -66,7 +66,7 @@ with lib;
       networkmanager-sstp = super.networkmanager-vpnc.override { withGnome = false; };
       networkmanager-vpnc = super.networkmanager-vpnc.override { withGnome = false; };
       pango = super.pango.override { x11Support = false; };
-      pinentry = super.pinentry.override { enabledFlavors = [ "curses" "tty" "emacs" ]; withLibsecret = false; };
+      pinentry-curses = super.pinentry-curses.override { withLibsecret = false; };
       pipewire = super.pipewire.override { vulkanSupport = false; x11Support = false; };
       pythonPackagesExtensions = super.pythonPackagesExtensions ++ [
         (python-final: python-prev: {
diff --git a/nixos/modules/config/resolvconf.nix b/nixos/modules/config/resolvconf.nix
index e9ae4d651d26..3b8cc0cb8f42 100644
--- a/nixos/modules/config/resolvconf.nix
+++ b/nixos/modules/config/resolvconf.nix
@@ -28,6 +28,8 @@ let
     '' + optionalString cfg.useLocalResolver ''
       # This hosts runs a full-blown DNS resolver.
       name_servers='127.0.0.1'
+    '' + optionalString (cfg.useLocalResolver && config.networking.enableIPv6) ''
+      name_servers='::1'
     '' + cfg.extraConfig;
 
 in
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index dd34771c0b42..02cd1a17f538 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -704,6 +704,11 @@ in {
     in stringAfter [ "users" ] ''
       if [ -e ${lingerDir} ] ; then
         cd ${lingerDir}
+        for user in ${lingerDir}/*; do
+          if ! id "$user" >/dev/null 2>&1; then
+            rm --force -- "$user"
+          fi
+        done
         ls ${lingerDir} | sort | comm -3 -1 ${lingeringUsersFile} - | xargs -r ${pkgs.systemd}/bin/loginctl disable-linger
         ls ${lingerDir} | sort | comm -3 -2 ${lingeringUsersFile} - | xargs -r ${pkgs.systemd}/bin/loginctl  enable-linger
       fi
diff --git a/nixos/modules/hardware/video/webcam/ipu6.nix b/nixos/modules/hardware/video/webcam/ipu6.nix
index c2dbdc217bd6..a7767e446bd4 100644
--- a/nixos/modules/hardware/video/webcam/ipu6.nix
+++ b/nixos/modules/hardware/video/webcam/ipu6.nix
@@ -30,7 +30,10 @@ in
       ipu6-drivers
     ];
 
-    hardware.firmware = [ pkgs.ipu6-camera-bins ];
+    hardware.firmware = with pkgs; [
+      ipu6-camera-bins
+      ivsc-firmware
+    ];
 
     services.udev.extraRules = ''
       SUBSYSTEM=="intel-ipu6-psys", MODE="0660", GROUP="video"
diff --git a/nixos/modules/image/repart-image.nix b/nixos/modules/image/repart-image.nix
index 7ac47ee32ff4..5ae523c43f58 100644
--- a/nixos/modules/image/repart-image.nix
+++ b/nixos/modules/image/repart-image.nix
@@ -3,6 +3,7 @@
 
 { lib
 , runCommand
+, runCommandLocal
 , python3
 , black
 , ruff
@@ -33,6 +34,7 @@
 , seed
 , definitionsDirectory
 , sectorSize
+, mkfsEnv ? {}
 }:
 
 let
@@ -50,6 +52,11 @@ let
     mypy --strict $out
   '';
 
+  amendedRepartDefinitions = runCommandLocal "amended-repart.d" {} ''
+    definitions=$(${amendRepartDefinitions} ${partitions} ${definitionsDirectory})
+    cp -r $definitions $out
+  '';
+
   fileSystemToolMapping = {
     "vfat" = [ dosfstools mtools ];
     "ext4" = [ e2fsprogs.bin ];
@@ -74,28 +81,39 @@ in
 
 runCommand imageFileBasename
 {
+  __structuredAttrs = true;
+
   nativeBuildInputs = [
     systemd
     fakeroot
     util-linux
     compressionPkg
   ] ++ fileSystemTools;
-} ''
-  amendedRepartDefinitions=$(${amendRepartDefinitions} ${partitions} ${definitionsDirectory})
 
+  env = mkfsEnv;
+
+  systemdRepartFlags = [
+    "--dry-run=no"
+    "--empty=create"
+    "--size=auto"
+    "--seed=${seed}"
+    "--definitions=${amendedRepartDefinitions}"
+    "--split=${lib.boolToString split}"
+    "--json=pretty"
+  ] ++ lib.optionals (sectorSize != null) [
+    "--sector-size=${toString sectorSize}"
+  ];
+
+  passthru = {
+    inherit amendRepartDefinitions amendedRepartDefinitions;
+  };
+} ''
   mkdir -p $out
   cd $out
 
   echo "Building image with systemd-repart..."
   unshare --map-root-user fakeroot systemd-repart \
-    --dry-run=no \
-    --empty=create \
-    --size=auto \
-    --seed="${seed}" \
-    --definitions="$amendedRepartDefinitions" \
-    --split="${lib.boolToString split}" \
-    --json=pretty \
-    ${lib.optionalString (sectorSize != null) "--sector-size=${toString sectorSize}"} \
+    ''${systemdRepartFlags[@]} \
     ${imageFileBasename}.raw \
     | tee repart-output.json
 
diff --git a/nixos/modules/image/repart.nix b/nixos/modules/image/repart.nix
index 6a933f0d83cc..90c9c7e51dfa 100644
--- a/nixos/modules/image/repart.nix
+++ b/nixos/modules/image/repart.nix
@@ -60,6 +60,11 @@ let
       };
     };
   };
+
+  mkfsOptionsToEnv = opts: lib.mapAttrs' (fsType: options: {
+    name = "SYSTEMD_REPART_MKFS_OPTIONS_${lib.toUpper fsType}";
+    value = builtins.concatStringsSep " " options;
+  }) opts;
 in
 {
   options.image.repart = {
@@ -183,6 +188,29 @@ in
       '';
     };
 
+    mkfsOptions = lib.mkOption {
+      type = with lib.types; attrsOf (listOf str);
+      default = {};
+      example = lib.literalExpression ''
+        {
+          vfat = [ "-S 512" "-c" ];
+        }
+      '';
+      description = lib.mdDoc ''
+        Specify extra options for created file systems. The specified options
+        are converted to individual environment variables of the format
+        `SYSTEMD_REPART_MKFS_OPTIONS_<FSTYPE>`.
+
+        See [upstream systemd documentation](https://github.com/systemd/systemd/blob/v255/docs/ENVIRONMENT.md?plain=1#L575-L577)
+        for information about the usage of these environment variables.
+
+        The example would produce the following environment variable:
+        ```
+        SYSTEMD_REPART_MKFS_OPTIONS_VFAT="-S 512 -c"
+        ```
+      '';
+    };
+
   };
 
   config = {
@@ -239,11 +267,13 @@ in
           (lib.mapAttrs (_n: v: { Partition = v.repartConfig; }) finalPartitions);
 
         partitions = pkgs.writeText "partitions.json" (builtins.toJSON finalPartitions);
+
+        mkfsEnv = mkfsOptionsToEnv cfg.mkfsOptions;
       in
       pkgs.callPackage ./repart-image.nix {
         systemd = cfg.package;
         inherit (cfg) imageFileBasename compression split seed sectorSize;
-        inherit fileSystems definitionsDirectory partitions;
+        inherit fileSystems definitionsDirectory partitions mkfsEnv;
       };
 
     meta.maintainers = with lib.maintainers; [ nikstur ];
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index 6adb94e09aff..f5b6af3a6b7f 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -811,12 +811,6 @@ in
       optional config.isoImage.includeSystemBuildDependencies
         config.system.build.toplevel.drvPath;
 
-    # Create the squashfs image that contains the Nix store.
-    system.build.squashfsStore = pkgs.callPackage ../../../lib/make-squashfs.nix {
-      storeContents = config.isoImage.storeContents;
-      comp = config.isoImage.squashfsCompression;
-    };
-
     # Individual files to be included on the CD, outside of the Nix
     # store on the CD.
     isoImage.contents =
@@ -827,9 +821,6 @@ in
         { source = config.system.build.initialRamdisk + "/" + config.system.boot.loader.initrdFile;
           target = "/boot/" + config.system.boot.loader.initrdFile;
         }
-        { source = config.system.build.squashfsStore;
-          target = "/nix-store.squashfs";
-        }
         { source = pkgs.writeText "version" config.system.nixos.label;
           target = "/version.txt";
         }
@@ -878,6 +869,8 @@ in
       bootable = config.isoImage.makeBiosBootable;
       bootImage = "/isolinux/isolinux.bin";
       syslinux = if config.isoImage.makeBiosBootable then pkgs.syslinux else null;
+      squashfsContents = config.isoImage.storeContents;
+      squashfsCompression = config.isoImage.squashfsCompression;
     } // optionalAttrs (config.isoImage.makeUsbBootable && config.isoImage.makeBiosBootable) {
       usbBootable = true;
       isohybridMbrImage = "${pkgs.syslinux}/share/syslinux/isohdpfx.bin";
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index cfe2350d5762..2ccaea466c6a 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -783,6 +783,7 @@
   ./services/misc/svnserve.nix
   ./services/misc/synergy.nix
   ./services/misc/sysprof.nix
+  ./services/misc/tabby.nix
   ./services/misc/tandoor-recipes.nix
   ./services/misc/taskserver
   ./services/misc/tautulli.nix
@@ -1357,6 +1358,7 @@
   ./services/web-apps/plausible.nix
   ./services/web-apps/powerdns-admin.nix
   ./services/web-apps/pretalx.nix
+  ./services/web-apps/pretix.nix
   ./services/web-apps/prosody-filer.nix
   ./services/web-apps/rimgo.nix
   ./services/web-apps/sftpgo.nix
diff --git a/nixos/modules/programs/chromium.nix b/nixos/modules/programs/chromium.nix
index 45a9e9e2a689..5e8983730048 100644
--- a/nixos/modules/programs/chromium.nix
+++ b/nixos/modules/programs/chromium.nix
@@ -98,6 +98,24 @@ in
           }
         '';
       };
+
+      initialPrefs = mkOption {
+        type = types.attrs;
+        description = lib.mdDoc ''
+          Initial preferences are used to configure the browser for the first run.
+          Unlike {option}`programs.chromium.extraOpts`, initialPrefs can be changed by users in the browser settings.
+          More information can be found in the Chromium documentation:
+          <https://www.chromium.org/administrators/configuring-other-preferences/>
+        '';
+        default = {};
+        example = literalExpression ''
+          {
+            "first_run_tabs" = [
+              "https://nixos.org/"
+            ];
+          }
+        '';
+      };
     };
   };
 
@@ -110,6 +128,7 @@ in
         { source = "${cfg.plasmaBrowserIntegrationPackage}/etc/chromium/native-messaging-hosts/org.kde.plasma.browser_integration.json"; };
       "chromium/policies/managed/default.json" = lib.mkIf (defaultProfile != {}) { text = builtins.toJSON defaultProfile; };
       "chromium/policies/managed/extra.json" = lib.mkIf (cfg.extraOpts != {}) { text = builtins.toJSON cfg.extraOpts; };
+      "chromium/initial_preferences" = lib.mkIf (cfg.initialPrefs != {}) { text = builtins.toJSON cfg.initialPrefs; };
       # for google-chrome https://www.chromium.org/administrators/linux-quick-start
       "opt/chrome/native-messaging-hosts/org.kde.plasma.browser_integration.json" = lib.mkIf cfg.enablePlasmaBrowserIntegration
         { source = "${cfg.plasmaBrowserIntegrationPackage}/etc/opt/chrome/native-messaging-hosts/org.kde.plasma.browser_integration.json"; };
diff --git a/nixos/modules/programs/clash-verge.nix b/nixos/modules/programs/clash-verge.nix
index 57a1c0377edb..e1afafa7cadc 100644
--- a/nixos/modules/programs/clash-verge.nix
+++ b/nixos/modules/programs/clash-verge.nix
@@ -3,6 +3,7 @@
 {
   options.programs.clash-verge = {
     enable = lib.mkEnableOption (lib.mdDoc "Clash Verge");
+    package = lib.mkPackageOption pkgs "clash-verge" {};
     autoStart = lib.mkEnableOption (lib.mdDoc "Clash Verge auto launch");
     tunMode = lib.mkEnableOption (lib.mdDoc "Clash Verge TUN mode");
   };
@@ -14,10 +15,10 @@
     lib.mkIf cfg.enable {
 
       environment.systemPackages = [
-        pkgs.clash-verge
+        cfg.package
         (lib.mkIf cfg.autoStart (pkgs.makeAutostartItem {
           name = "clash-verge";
-          package = pkgs.clash-verge;
+          package = cfg.package;
         }))
       ];
 
@@ -25,7 +26,7 @@
         owner = "root";
         group = "root";
         capabilities = "cap_net_bind_service,cap_net_admin=+ep";
-        source = "${lib.getExe pkgs.clash-verge}";
+        source = "${lib.getExe cfg.package}";
       };
     };
 
diff --git a/nixos/modules/programs/gnupg.nix b/nixos/modules/programs/gnupg.nix
index 179d2de87cc5..66be1f247fbd 100644
--- a/nixos/modules/programs/gnupg.nix
+++ b/nixos/modules/programs/gnupg.nix
@@ -1,8 +1,7 @@
 { config, lib, pkgs, ... }:
 
-with lib;
-
 let
+  inherit (lib) mkRemovedOptionModule mkOption mkPackageOption types mkIf optionalString;
 
   cfg = config.programs.gnupg;
 
@@ -26,8 +25,10 @@ let
       "curses";
 
 in
-
 {
+  imports = [
+    (mkRemovedOptionModule [ "programs" "gnupg" "agent" "pinentryFlavor" ] "Use programs.gnupg.agent.pinentryPackage instead")
+  ];
 
   options.programs.gnupg = {
     package = mkPackageOption pkgs "gnupg" { };
@@ -66,17 +67,17 @@ in
       '';
     };
 
-    agent.pinentryFlavor = mkOption {
-      type = types.nullOr (types.enum pkgs.pinentry.flavors);
-      example = "gnome3";
-      default = defaultPinentryFlavor;
-      defaultText = literalMD ''matching the configured desktop environment'';
+    agent.pinentryPackage = mkOption {
+      type = types.nullOr types.package;
+      example = lib.literalMD "pkgs.pinentry-gnome3";
+      default = pkgs.pinentry-curses;
+      defaultText = lib.literalMD "matching the configured desktop environment or `pkgs.pinentry-curses`";
       description = lib.mdDoc ''
-        Which pinentry interface to use. If not null, the path to the
-        pinentry binary will be set in /etc/gnupg/gpg-agent.conf.
-        If not set at all, it'll pick an appropriate flavor depending on the
-        system configuration (qt flavor for lxqt and plasma5, gtk2 for xfce
-        4.12, gnome3 on all other systems with X enabled, ncurses otherwise).
+        Which pinentry package to use. The path to the mainProgram as defined in
+        the package's meta attriutes will be set in /etc/gnupg/gpg-agent.conf.
+        If not set by the user, it'll pick an appropriate flavor depending on the
+        system configuration (qt flavor for lxqt and plasma5, gtk2 for xfce,
+        gnome3 on all other systems with X enabled, curses otherwise).
       '';
     };
 
@@ -102,9 +103,8 @@ in
   };
 
   config = mkIf cfg.agent.enable {
-    programs.gnupg.agent.settings = {
-      pinentry-program = lib.mkIf (cfg.agent.pinentryFlavor != null)
-        "${pkgs.pinentry.${cfg.agent.pinentryFlavor}}/bin/pinentry";
+    programs.gnupg.agent.settings = mkIf (cfg.agent.pinentryPackage != null) {
+      pinentry-program = lib.getExe cfg.agent.pinentryPackage;
     };
 
     environment.etc."gnupg/gpg-agent.conf".source =
@@ -207,9 +207,9 @@ in
       wantedBy = [ "sockets.target" ];
     };
 
-    services.dbus.packages = mkIf (cfg.agent.pinentryFlavor == "gnome3") [ pkgs.gcr ];
+    services.dbus.packages = mkIf (lib.elem "gnome3" (cfg.agent.pinentryPackage.flavors or [])) [ pkgs.gcr ];
 
-    environment.systemPackages = with pkgs; [ cfg.package ];
+    environment.systemPackages = [ cfg.package ];
 
     environment.interactiveShellInit = ''
       # Bind gpg-agent to this TTY if gpg commands are used.
@@ -230,12 +230,10 @@ in
     '';
 
     assertions = [
-      { assertion = cfg.agent.enableSSHSupport -> !config.programs.ssh.startAgent;
+      {
+        assertion = cfg.agent.enableSSHSupport -> !config.programs.ssh.startAgent;
         message = "You can't use ssh-agent and GnuPG agent with SSH support enabled at the same time!";
       }
     ];
   };
-
-  # uses attributes of the linked package
-  meta.buildDocsInSandbox = false;
 }
diff --git a/nixos/modules/programs/steam.nix b/nixos/modules/programs/steam.nix
index d6e2a82af100..c93a34f61849 100644
--- a/nixos/modules/programs/steam.nix
+++ b/nixos/modules/programs/steam.nix
@@ -43,6 +43,9 @@ in {
         }
       '';
       apply = steam: steam.override (prev: {
+        extraEnv = (lib.optionalAttrs (cfg.extraCompatPackages != [ ]) {
+          STEAM_EXTRA_COMPAT_TOOLS_PATHS = makeSearchPathOutput "steamcompattool" "" cfg.extraCompatPackages;
+        }) // (prev.extraEnv or {});
         extraLibraries = pkgs: let
           prevLibs = if prev ? extraLibraries then prev.extraLibraries pkgs else [ ];
           additionalLibs = with config.hardware.opengl;
@@ -68,6 +71,23 @@ in {
       '';
     };
 
+    extraCompatPackages = mkOption {
+      type = types.listOf types.package;
+      default = [ ];
+      example = literalExpression ''
+        with pkgs; [
+          proton-ge-bin
+        ]
+      '';
+      description = lib.mdDoc ''
+        Extra packages to be used as compatibility tools for Steam on Linux. Packages will be included
+        in the `STEAM_EXTRA_COMPAT_TOOLS_PATHS` environmental variable. For more information see
+        https://github.com/ValveSoftware/steam-for-linux/issues/6310.
+
+        These packages must be Steam compatibility tools that have a `steamcompattool` output.
+      '';
+    };
+
     remotePlay.openFirewall = mkOption {
       type = types.bool;
       default = false;
@@ -174,5 +194,5 @@ in {
     ];
   };
 
-  meta.maintainers = with maintainers; [ mkg20001 ];
+  meta.maintainers = teams.steam;
 }
diff --git a/nixos/modules/programs/wayland/sway.nix b/nixos/modules/programs/wayland/sway.nix
index ca2503ae5da7..2bd297af5254 100644
--- a/nixos/modules/programs/wayland/sway.nix
+++ b/nixos/modules/programs/wayland/sway.nix
@@ -152,6 +152,7 @@ in {
             '';
           }
         ];
+
         environment = {
           systemPackages = optional (cfg.package != null) cfg.package ++ cfg.extraPackages;
           # Needed for the default wallpaper:
@@ -166,8 +167,12 @@ in {
             "sway/config".source = mkOptionDefault "${cfg.package}/etc/sway/config";
           };
         };
+
+        programs.gnupg.agent.pinentryPackage = lib.mkDefault pkgs.pinentry-gnome3;
+
         # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1050913
         xdg.portal.config.sway.default = mkDefault [ "wlr" "gtk" ];
+
         # To make a Sway session available if a display manager like SDDM is enabled:
         services.xserver.displayManager.sessionPackages = optionals (cfg.package != null) [ cfg.package ]; }
       (import ./wayland-session.nix { inherit lib pkgs; })
diff --git a/nixos/modules/services/audio/spotifyd.nix b/nixos/modules/services/audio/spotifyd.nix
index 1194b6f200d7..04bb523e25b1 100644
--- a/nixos/modules/services/audio/spotifyd.nix
+++ b/nixos/modules/services/audio/spotifyd.nix
@@ -24,7 +24,7 @@ in
         type = types.lines;
         description = lib.mdDoc ''
           (Deprecated) Configuration for Spotifyd. For syntax and directives, see
-          <https://github.com/Spotifyd/spotifyd#Configuration>.
+          <https://docs.spotifyd.rs/config/File.html>.
         '';
       };
 
@@ -34,7 +34,7 @@ in
         example = { global.bitrate = 320; };
         description = lib.mdDoc ''
           Configuration for Spotifyd. For syntax and directives, see
-          <https://github.com/Spotifyd/spotifyd#Configuration>.
+          <https://docs.spotifyd.rs/config/File.html>.
         '';
       };
     };
diff --git a/nixos/modules/services/backup/bacula.nix b/nixos/modules/services/backup/bacula.nix
index 5a75a46e5259..39975adf5909 100644
--- a/nixos/modules/services/backup/bacula.nix
+++ b/nixos/modules/services/backup/bacula.nix
@@ -4,11 +4,36 @@
 # TODO: test configuration when building nixexpr (use -t parameter)
 # TODO: support sqlite3 (it's deprecate?) and mysql
 
-with lib;
 
 let
+  inherit (lib)
+    concatStringsSep
+    literalExpression
+    mapAttrsToList
+    mdDoc
+    mkIf
+    mkOption
+    optional
+    optionalString
+    types
+    ;
   libDir = "/var/lib/bacula";
 
+  yes_no = bool: if bool then "yes" else "no";
+  tls_conf = tls_cfg: optionalString tls_cfg.enable (
+    concatStringsSep
+      "\n"
+      (
+      ["TLS Enable = yes;"]
+      ++ optional (tls_cfg.require != null) "TLS Require = ${yes_no tls_cfg.require};"
+      ++ optional (tls_cfg.certificate != null) ''TLS Certificate = "${tls_cfg.certificate}";''
+      ++ [''TLS Key = "${tls_cfg.key}";'']
+      ++ optional (tls_cfg.verifyPeer != null) "TLS Verify Peer = ${yes_no tls_cfg.verifyPeer};"
+      ++ optional (tls_cfg.allowedCN != [ ]) "TLS Allowed CN = ${concatStringsSep " " (tls_cfg.allowedCN)};"
+      ++ optional (tls_cfg.caCertificateFile != null) ''TLS CA Certificate File = "${tls_cfg.caCertificateFile}";''
+      )
+  );
+
   fd_cfg = config.services.bacula-fd;
   fd_conf = pkgs.writeText "bacula-fd.conf"
     ''
@@ -18,6 +43,7 @@ let
         WorkingDirectory = ${libDir};
         Pid Directory = /run;
         ${fd_cfg.extraClientConfig}
+        ${tls_conf fd_cfg.tls}
       }
 
       ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
@@ -25,6 +51,7 @@ let
         Name = "${name}";
         Password = ${value.password};
         Monitor = ${value.monitor};
+        ${tls_conf value.tls}
       }
       '') fd_cfg.director)}
 
@@ -44,6 +71,7 @@ let
         WorkingDirectory = ${libDir};
         Pid Directory = /run;
         ${sd_cfg.extraStorageConfig}
+        ${tls_conf sd_cfg.tls}
       }
 
       ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
@@ -70,6 +98,7 @@ let
         Name = "${name}";
         Password = ${value.password};
         Monitor = ${value.monitor};
+        ${tls_conf value.tls}
       }
       '') sd_cfg.director)}
 
@@ -90,6 +119,7 @@ let
       Working Directory = ${libDir};
       Pid Directory = /run/;
       QueryFile = ${pkgs.bacula}/etc/query.sql;
+      ${tls_conf dir_cfg.tls}
       ${dir_cfg.extraDirectorConfig}
     }
 
@@ -108,13 +138,99 @@ let
     ${dir_cfg.extraConfig}
     '';
 
-  directorOptions = {...}:
+  linkOption = name: destination: "[${name}](#opt-${builtins.replaceStrings [ "<" ">"] ["_" "_"] destination})";
+  tlsLink = destination: submodulePath: linkOption "${submodulePath}.${destination}" "${submodulePath}.${destination}";
+
+  tlsOptions = submodulePath: {...}:
+  {
+    options = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = mdDoc ''
+          Specifies if TLS should be enabled.
+          If this set to `false` TLS will be completely disabled, even if ${tlsLink "tls.require" submodulePath} is true.
+        '';
+      };
+      require = mkOption {
+        type = types.nullOr types.bool;
+        default = null;
+        description = mdDoc ''
+          Require TLS or TLS-PSK encryption.
+          This directive is ignored unless one of ${tlsLink "tls.enable" submodulePath} is true or TLS PSK Enable is set to `yes`.
+          If TLS is not required while TLS or TLS-PSK are enabled, then the Bacula component
+          will connect with other components either with or without TLS or TLS-PSK
+
+          If ${tlsLink "tls.enable" submodulePath} or TLS-PSK is enabled and TLS is required, then the Bacula
+          component will refuse any connection request that does not use TLS.
+        '';
+      };
+      certificate = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = mdDoc ''
+          The full path to the PEM encoded TLS certificate.
+          It will be used as either a client or server certificate,
+          depending on the connection direction.
+          This directive is required in a server context, but it may
+          not be specified in a client context if ${tlsLink "tls.verifyPeer" submodulePath} is
+          `false` in the corresponding server context.
+        '';
+      };
+      key = mkOption {
+        type = types.path;
+        description = mdDoc ''
+          The path of a PEM encoded TLS private key.
+          It must correspond to the TLS certificate.
+        '';
+      };
+      verifyPeer = mkOption {
+        type = types.nullOr types.bool;
+        default = null;
+        description = mdDoc ''
+          Verify peer certificate.
+          Instructs server to request and verify the client's X.509 certificate.
+          Any client certificate signed by a known-CA will be accepted.
+          Additionally, the client's X509 certificate Common Name must meet the value of the Address directive.
+          If ${tlsLink "tls.allowedCN" submodulePath} is used,
+          the client's x509 certificate Common Name must also correspond to
+          one of the CN specified in the ${tlsLink "tls.allowedCN" submodulePath} directive.
+          This directive is valid only for a server and not in client context.
+
+          Standard from Bacula is `true`.
+        '';
+      };
+      allowedCN = mkOption {
+        type = types.listOf types.str;
+        default = [ ];
+        description = mdDoc ''
+          Common name attribute of allowed peer certificates.
+          This directive is valid for a server and in a client context.
+          If this directive is specified, the peer certificate will be verified against this list.
+          In the case this directive is configured on a server side, the allowed
+          CN list will not be checked if ${tlsLink "tls.verifyPeer" submodulePath} is false.
+        '';
+      };
+      caCertificateFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = mdDoc ''
+          The path specifying a PEM encoded TLS CA certificate(s).
+          Multiple certificates are permitted in the file.
+          One of TLS CA Certificate File or TLS CA Certificate Dir are required in a server context, unless
+          ${tlsLink "tls.verifyPeer" submodulePath} is false, and are always required in a client context.
+        '';
+      };
+    };
+  };
+
+  directorOptions = submodulePath:{...}:
   {
     options = {
       password = mkOption {
         type = types.str;
         # TODO: required?
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Specifies the password that must be supplied for the default Bacula
           Console to be authorized. The same password must appear in the
           Director resource of the Console configuration file. For added
@@ -135,7 +251,7 @@ let
         type = types.enum [ "no" "yes" ];
         default = "no";
         example = "yes";
-        description = lib.mdDoc ''
+        description = mdDoc ''
           If Monitor is set to `no`, this director will have
           full access to this Storage daemon. If Monitor is set to
           `yes`, this director will only be able to fetch the
@@ -146,6 +262,13 @@ let
           security problems.
         '';
       };
+
+      tls = mkOption {
+        type = types.submodule (tlsOptions "${submodulePath}.director.<name>");
+        description = mdDoc ''
+          TLS Options for the Director in this Configuration.
+        '';
+      };
     };
   };
 
@@ -154,7 +277,7 @@ let
     options = {
       changerDevice = mkOption {
         type = types.str;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           The specified name-string must be the generic SCSI device name of the
           autochanger that corresponds to the normal read/write Archive Device
           specified in the Device resource. This generic SCSI device name
@@ -173,7 +296,7 @@ let
 
       changerCommand = mkOption {
         type = types.str;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           The name-string specifies an external program to be called that will
           automatically change volumes as required by Bacula. Normally, this
           directive will be specified only in the AutoChanger resource, which
@@ -195,14 +318,14 @@ let
       };
 
       devices = mkOption {
-        description = lib.mdDoc "";
+        description = mdDoc "";
         type = types.listOf types.str;
       };
 
       extraAutochangerConfig = mkOption {
         default = "";
         type = types.lines;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Extra configuration to be passed in Autochanger directive.
         '';
         example = ''
@@ -219,7 +342,7 @@ let
       archiveDevice = mkOption {
         # TODO: required?
         type = types.str;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           The specified name-string gives the system file name of the storage
           device managed by this storage daemon. This will usually be the
           device file name of a removable storage device (tape drive), for
@@ -236,7 +359,7 @@ let
       mediaType = mkOption {
         # TODO: required?
         type = types.str;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           The specified name-string names the type of media supported by this
           device, for example, `DLT7000`. Media type names are
           arbitrary in that you set them to anything you want, but they must be
@@ -274,7 +397,7 @@ let
       extraDeviceConfig = mkOption {
         default = "";
         type = types.lines;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Extra configuration to be passed in Device directive.
         '';
         example = ''
@@ -295,7 +418,7 @@ in {
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Whether to enable the Bacula File Daemon.
         '';
       };
@@ -304,7 +427,7 @@ in {
         default = "${config.networking.hostName}-fd";
         defaultText = literalExpression ''"''${config.networking.hostName}-fd"'';
         type = types.str;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           The client name that must be used by the Director when connecting.
           Generally, it is a good idea to use a name related to the machine so
           that error messages can be easily identified if you have multiple
@@ -315,7 +438,7 @@ in {
       port = mkOption {
         default = 9102;
         type = types.port;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           This specifies the port number on which the Client listens for
           Director connections. It must agree with the FDPort specified in
           the Client resource of the Director's configuration file.
@@ -324,16 +447,26 @@ in {
 
       director = mkOption {
         default = {};
-        description = lib.mdDoc ''
+        description = mdDoc ''
           This option defines director resources in Bacula File Daemon.
         '';
-        type = with types; attrsOf (submodule directorOptions);
+        type = types.attrsOf (types.submodule (directorOptions "services.bacula-fd"));
       };
 
+
+      tls = mkOption {
+        type = types.submodule (tlsOptions "services.bacula-fd");
+        default = { };
+        description = mdDoc ''
+          TLS Options for the File Daemon.
+          Important notice: The backup won't be encrypted.
+        '';
+       };
+
       extraClientConfig = mkOption {
         default = "";
         type = types.lines;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Extra configuration to be passed in Client directive.
         '';
         example = ''
@@ -345,7 +478,7 @@ in {
       extraMessagesConfig = mkOption {
         default = "";
         type = types.lines;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Extra configuration to be passed in Messages directive.
         '';
         example = ''
@@ -358,7 +491,7 @@ in {
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Whether to enable Bacula Storage Daemon.
         '';
       };
@@ -367,7 +500,7 @@ in {
         default = "${config.networking.hostName}-sd";
         defaultText = literalExpression ''"''${config.networking.hostName}-sd"'';
         type = types.str;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Specifies the Name of the Storage daemon.
         '';
       };
@@ -375,7 +508,7 @@ in {
       port = mkOption {
         default = 9103;
         type = types.port;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Specifies port number on which the Storage daemon listens for
           Director connections.
         '';
@@ -383,32 +516,32 @@ in {
 
       director = mkOption {
         default = {};
-        description = lib.mdDoc ''
+        description = mdDoc ''
           This option defines Director resources in Bacula Storage Daemon.
         '';
-        type = with types; attrsOf (submodule directorOptions);
+        type = types.attrsOf (types.submodule (directorOptions "services.bacula-sd"));
       };
 
       device = mkOption {
         default = {};
-        description = lib.mdDoc ''
+        description = mdDoc ''
           This option defines Device resources in Bacula Storage Daemon.
         '';
-        type = with types; attrsOf (submodule deviceOptions);
+        type = types.attrsOf (types.submodule deviceOptions);
       };
 
       autochanger = mkOption {
         default = {};
-        description = lib.mdDoc ''
+        description = mdDoc ''
           This option defines Autochanger resources in Bacula Storage Daemon.
         '';
-        type = with types; attrsOf (submodule autochangerOptions);
+        type = types.attrsOf (types.submodule autochangerOptions);
       };
 
       extraStorageConfig = mkOption {
         default = "";
         type = types.lines;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Extra configuration to be passed in Storage directive.
         '';
         example = ''
@@ -420,13 +553,21 @@ in {
       extraMessagesConfig = mkOption {
         default = "";
         type = types.lines;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Extra configuration to be passed in Messages directive.
         '';
         example = ''
           console = all
         '';
       };
+      tls = mkOption {
+        type = types.submodule (tlsOptions "services.bacula-sd");
+        default = { };
+        description = mdDoc ''
+          TLS Options for the Storage Daemon.
+          Important notice: The backup won't be encrypted.
+        '';
+       };
 
     };
 
@@ -434,7 +575,7 @@ in {
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Whether to enable Bacula Director Daemon.
         '';
       };
@@ -443,7 +584,7 @@ in {
         default = "${config.networking.hostName}-dir";
         defaultText = literalExpression ''"''${config.networking.hostName}-dir"'';
         type = types.str;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           The director name used by the system administrator. This directive is
           required.
         '';
@@ -452,7 +593,7 @@ in {
       port = mkOption {
         default = 9101;
         type = types.port;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Specify the port (a positive integer) on which the Director daemon
           will listen for Bacula Console connections. This same port number
           must be specified in the Director resource of the Console
@@ -465,7 +606,7 @@ in {
       password = mkOption {
         # TODO: required?
         type = types.str;
-        description = lib.mdDoc ''
+        description = mdDoc ''
            Specifies the password that must be supplied for a Director.
         '';
       };
@@ -473,7 +614,7 @@ in {
       extraMessagesConfig = mkOption {
         default = "";
         type = types.lines;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Extra configuration to be passed in Messages directive.
         '';
         example = ''
@@ -484,7 +625,7 @@ in {
       extraDirectorConfig = mkOption {
         default = "";
         type = types.lines;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Extra configuration to be passed in Director directive.
         '';
         example = ''
@@ -496,13 +637,22 @@ in {
       extraConfig = mkOption {
         default = "";
         type = types.lines;
-        description = lib.mdDoc ''
+        description = mdDoc ''
           Extra configuration for Bacula Director Daemon.
         '';
         example = ''
           TODO
         '';
       };
+
+      tls = mkOption {
+        type = types.submodule (tlsOptions "services.bacula-dir");
+        default = { };
+        description = mdDoc ''
+          TLS Options for the Director.
+          Important notice: The backup won't be encrypted.
+        '';
+       };
     };
   };
 
diff --git a/nixos/modules/services/backup/syncoid.nix b/nixos/modules/services/backup/syncoid.nix
index 7b8d3b431309..4a04f0aa1622 100644
--- a/nixos/modules/services/backup/syncoid.nix
+++ b/nixos/modules/services/backup/syncoid.nix
@@ -134,7 +134,7 @@ in
     localSourceAllow = mkOption {
       type = types.listOf types.str;
       # Permissions snapshot and destroy are in case --no-sync-snap is not used
-      default = [ "bookmark" "hold" "send" "snapshot" "destroy" ];
+      default = [ "bookmark" "hold" "send" "snapshot" "destroy" "mount" ];
       description = lib.mdDoc ''
         Permissions granted for the {option}`services.syncoid.user` user
         for local source datasets. See
diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix
index b1d44e67658b..10e1f0532c84 100644
--- a/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -178,6 +178,24 @@ in
         description = lib.mdDoc "Whether to run the server in debug mode.";
       };
 
+      maxServers = mkOption {
+        type = types.int;
+        default = 25;
+        description = lib.mdDoc "Maximum number of starman workers to spawn.";
+      };
+
+      minSpareServers = mkOption {
+        type = types.int;
+        default = 4;
+        description = lib.mdDoc "Minimum number of spare starman workers to keep.";
+      };
+
+      maxSpareServers = mkOption {
+        type = types.int;
+        default = 5;
+        description = lib.mdDoc "Maximum number of spare starman workers to keep.";
+      };
+
       extraConfig = mkOption {
         type = types.lines;
         description = lib.mdDoc "Extra lines for the Hydra configuration.";
@@ -224,6 +242,16 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
+    assertions = [
+      {
+        assertion = cfg.maxServers != 0 && cfg.maxSpareServers != 0 && cfg.minSpareServers != 0;
+        message = "services.hydra.{minSpareServers,maxSpareServers,minSpareServers} cannot be 0";
+      }
+      {
+        assertion = cfg.minSpareServers < cfg.maxSpareServers;
+        message = "services.hydra.minSpareServers cannot be bigger than servives.hydra.maxSpareServers";
+      }
+    ];
 
     users.groups.hydra = {
       gid = config.ids.gids.hydra;
@@ -258,7 +286,7 @@ in
         using_frontend_proxy = 1
         base_uri = ${cfg.hydraURL}
         notification_sender = ${cfg.notificationSender}
-        max_servers = 25
+        max_servers = ${toString cfg.maxServers}
         ${optionalString (cfg.logo != null) ''
           hydra_logo = ${cfg.logo}
         ''}
@@ -359,8 +387,8 @@ in
         serviceConfig =
           { ExecStart =
               "@${hydra-package}/bin/hydra-server hydra-server -f -h '${cfg.listenHost}' "
-              + "-p ${toString cfg.port} --max_spare_servers 5 --max_servers 25 "
-              + "--max_requests 100 ${optionalString cfg.debugServer "-d"}";
+              + "-p ${toString cfg.port} --min_spare_servers ${toString cfg.minSpareServers} --max_spare_servers ${toString cfg.maxSpareServers} "
+              + "--max_servers ${toString cfg.maxServers} --max_requests 100 ${optionalString cfg.debugServer "-d"}";
             User = "hydra-www";
             PermissionsStartOnly = true;
             Restart = "always";
diff --git a/nixos/modules/services/databases/lldap.nix b/nixos/modules/services/databases/lldap.nix
index e821da8e58aa..033de7af886f 100644
--- a/nixos/modules/services/databases/lldap.nix
+++ b/nixos/modules/services/databases/lldap.nix
@@ -107,10 +107,25 @@ in
       wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
+      # lldap defaults to a hardcoded `jwt_secret` value if none is provided, which is bad, because
+      # an attacker could create a valid admin jwt access token fairly trivially.
+      # Because there are 3 different ways `jwt_secret` can be provided, we check if any one of them is present,
+      # and if not, bootstrap a secret in `/var/lib/lldap/jwt_secret_file` and give that to lldap.
+      script = lib.optionalString (!cfg.settings ? jwt_secret) ''
+        if [[ -z "$LLDAP_JWT_SECRET_FILE" ]] && [[ -z "$LLDAP_JWT_SECRET" ]]; then
+          if [[ ! -e "./jwt_secret_file" ]]; then
+            ${lib.getExe pkgs.openssl} rand -base64 -out ./jwt_secret_file 32
+          fi
+          export LLDAP_JWT_SECRET_FILE="./jwt_secret_file"
+        fi
+      '' + ''
+         ${lib.getExe cfg.package} run --config-file ${format.generate "lldap_config.toml" cfg.settings}
+      '';
       serviceConfig = {
-        ExecStart = "${lib.getExe cfg.package} run --config-file ${format.generate "lldap_config.toml" cfg.settings}";
         StateDirectory = "lldap";
+        StateDirectoryMode = "0750";
         WorkingDirectory = "%S/lldap";
+        UMask = "0027";
         User = "lldap";
         Group = "lldap";
         DynamicUser = true;
diff --git a/nixos/modules/services/databases/memcached.nix b/nixos/modules/services/databases/memcached.nix
index 542c80ab2e67..fd943c20091a 100644
--- a/nixos/modules/services/databases/memcached.nix
+++ b/nixos/modules/services/databases/memcached.nix
@@ -37,7 +37,7 @@ in
         description = lib.mdDoc "The port to bind to.";
       };
 
-      enableUnixSocket = mkEnableOption (lib.mdDoc "unix socket at /run/memcached/memcached.sock");
+      enableUnixSocket = mkEnableOption (lib.mdDoc "Unix Domain Socket at /run/memcached/memcached.sock instead of listening on an IP address and port. The `listen` and `port` options are ignored.");
 
       maxMemory = mkOption {
         type = types.ints.unsigned;
diff --git a/nixos/modules/services/databases/postgresql.md b/nixos/modules/services/databases/postgresql.md
index 7d141f12b5de..3ff1f00fa9cf 100644
--- a/nixos/modules/services/databases/postgresql.md
+++ b/nixos/modules/services/databases/postgresql.md
@@ -277,7 +277,7 @@ self: super: {
 Here's a recipe on how to override a particular plugin through an overlay:
 ```
 self: super: {
-  postgresql_15 = super.postgresql_15.override { this = self.postgresql_15; } // {
+  postgresql_15 = super.postgresql_15// {
     pkgs = super.postgresql_15.pkgs // {
       pg_repack = super.postgresql_15.pkgs.pg_repack.overrideAttrs (_: {
         name = "pg_repack-v20181024";
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index ed5915735730..c3f3b98ae5e7 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -14,7 +14,7 @@ let
       #     package = pkgs.postgresql_<major>;
       #   };
       # works.
-      base = if cfg.enableJIT && !cfg.package.jitSupport then cfg.package.withJIT else cfg.package;
+      base = if cfg.enableJIT then cfg.package.withJIT else cfg.package;
     in
     if cfg.extraPlugins == []
       then base
@@ -161,33 +161,6 @@ in
               '';
             };
 
-            ensurePermissions = mkOption {
-              type = types.attrsOf types.str;
-              default = {};
-              visible = false; # This option has been deprecated.
-              description = lib.mdDoc ''
-                This option is DEPRECATED and should not be used in nixpkgs anymore,
-                use `ensureDBOwnership` instead. It can also break with newer
-                versions of PostgreSQL (≥ 15).
-
-                Permissions to ensure for the user, specified as an attribute set.
-                The attribute names specify the database and tables to grant the permissions for.
-                The attribute values specify the permissions to grant. You may specify one or
-                multiple comma-separated SQL privileges here.
-
-                For more information on how to specify the target
-                and on which privileges exist, see the
-                [GRANT syntax](https://www.postgresql.org/docs/current/sql-grant.html).
-                The attributes are used as `GRANT ''${attrValue} ON ''${attrName}`.
-              '';
-              example = literalExpression ''
-                {
-                  "DATABASE \"nextcloud\"" = "ALL PRIVILEGES";
-                  "ALL TABLES IN SCHEMA public" = "ALL PRIVILEGES";
-                }
-              '';
-            };
-
             ensureDBOwnership = mkOption {
               type = types.bool;
               default = false;
@@ -460,16 +433,6 @@ in
         Offender: ${name} has not been found among databases.
       '';
     }) cfg.ensureUsers;
-    # `ensurePermissions` is now deprecated, let's avoid it.
-    warnings = lib.optional (any ({ ensurePermissions, ... }: ensurePermissions != {}) cfg.ensureUsers) "
-      `services.postgresql.ensureUsers.*.ensurePermissions` is used in your expressions,
-      this option is known to be broken with newer PostgreSQL versions,
-      consider migrating to `services.postgresql.ensureUsers.*.ensureDBOwnership` or
-      consult the release notes or manual for more migration guidelines.
-
-      This option will be removed in NixOS 24.05 unless it sees significant
-      maintenance improvements.
-    ";
 
     services.postgresql.settings =
       {
@@ -583,11 +546,6 @@ in
               concatMapStrings
               (user:
               let
-                  userPermissions = concatStringsSep "\n"
-                    (mapAttrsToList
-                      (database: permission: ''$PSQL -tAc 'GRANT ${permission} ON ${database} TO "${user.name}"' '')
-                      user.ensurePermissions
-                    );
                   dbOwnershipStmt = optionalString
                     user.ensureDBOwnership
                     ''$PSQL -tAc 'ALTER DATABASE "${user.name}" OWNER TO "${user.name}";' '';
@@ -599,7 +557,6 @@ in
                   userClauses = ''$PSQL -tAc 'ALTER ROLE "${user.name}" ${concatStringsSep " " clauseSqlStatements}' '';
                 in ''
                   $PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='${user.name}'" | grep -q 1 || $PSQL -tAc 'CREATE USER "${user.name}"'
-                  ${userPermissions}
                   ${userClauses}
 
                   ${dbOwnershipStmt}
diff --git a/nixos/modules/services/x11/desktop-managers/plasma6.nix b/nixos/modules/services/desktop-managers/plasma6.nix
index 1237261e0af7..1cb7a7ea778b 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma6.nix
+++ b/nixos/modules/services/desktop-managers/plasma6.nix
@@ -5,8 +5,7 @@
   utils,
   ...
 }: let
-  xcfg = config.services.xserver;
-  cfg = xcfg.desktopManager.plasma6;
+  cfg = config.services.desktopManager.plasma6;
 
   inherit (pkgs) kdePackages;
   inherit (lib) literalExpression mkDefault mkIf mkOption mkPackageOptionMD types;
@@ -17,7 +16,7 @@
   '';
 in {
   options = {
-    services.xserver.desktopManager.plasma6 = {
+    services.desktopManager.plasma6 = {
       enable = mkOption {
         type = types.bool;
         default = false;
@@ -44,6 +43,12 @@ in {
     };
   };
 
+  imports = [
+    (lib.mkRenamedOptionModule [ "services" "xserver" "desktopManager" "plasma6" "enable" ] [ "services" "desktopManager" "plasma6" "enable" ])
+    (lib.mkRenamedOptionModule [ "services" "xserver" "desktopManager" "plasma6" "enableQt5Integration" ] [ "services" "desktopManager" "plasma6" "enableQt5Integration" ])
+    (lib.mkRenamedOptionModule [ "services" "xserver" "desktopManager" "plasma6" "notoPackage" ] [ "services" "desktopManager" "plasma6" "notoPackage" ])
+  ];
+
   config = mkIf cfg.enable {
     assertions = [
       {
@@ -161,7 +166,7 @@ in {
     in
       requiredPackages
       ++ utils.removePackagesByName optionalPackages config.environment.plasma6.excludePackages
-      ++ lib.optionals config.services.xserver.desktopManager.plasma6.enableQt5Integration [
+      ++ lib.optionals config.services.desktopManager.plasma6.enableQt5Integration [
         breeze.qt5
         plasma-integration.qt5
         pkgs.plasma5Packages.kwayland-integration
@@ -175,7 +180,7 @@ in {
       ++ lib.optional config.powerManagement.enable powerdevil
       ++ lib.optional config.services.colord.enable colord-kde
       ++ lib.optional config.services.hardware.bolt.enable plasma-thunderbolt
-      ++ lib.optionals config.services.samba.enable [kdenetwork-filesharing pkgs.samba]
+      ++ lib.optional config.services.samba.enable kdenetwork-filesharing
       ++ lib.optional config.services.xserver.wacom.enable wacomtablet
       ++ lib.optional config.services.flatpak.enable flatpak-kcm;
 
@@ -185,7 +190,7 @@ in {
       "/libexec" # for drkonqi
     ];
 
-    environment.etc."X11/xkb".source = xcfg.xkb.dir;
+    environment.etc."X11/xkb".source = config.services.xserver.xkb.dir;
 
     # Add ~/.config/kdedefaults to XDG_CONFIG_DIRS for shells, since Plasma sets that.
     # FIXME: maybe we should append to XDG_CONFIG_DIRS in /etc/set-environment instead?
@@ -210,6 +215,7 @@ in {
       serif = ["Noto Serif"];
     };
 
+    programs.gnupg.agent.pinentryPackage = mkDefault pkgs.pinentry-qt;
     programs.ssh.askPassword = mkDefault "${kdePackages.ksshaskpass.out}/bin/ksshaskpass";
 
     # Enable helpful DBus services.
diff --git a/nixos/modules/services/desktops/pipewire/wireplumber.nix b/nixos/modules/services/desktops/pipewire/wireplumber.nix
index 009d68bd4f28..5967ac36fa85 100644
--- a/nixos/modules/services/desktops/pipewire/wireplumber.nix
+++ b/nixos/modules/services/desktops/pipewire/wireplumber.nix
@@ -56,24 +56,28 @@ in
 
   config =
     let
-      pwNotForAudioConfigPkg = pkgs.writeTextDir "share/wireplumber/main.lua.d/80-pw-not-for-audio.lua" ''
-        -- PipeWire is not used for audio, so prevent it from grabbing audio devices
-        alsa_monitor.enable = function() end
-      '';
-      systemwideConfigPkg = pkgs.writeTextDir "share/wireplumber/main.lua.d/80-systemwide.lua" ''
-        -- When running system-wide, these settings need to be disabled (they
-        -- use functions that aren't available on the system dbus).
-        alsa_monitor.properties["alsa.reserve"] = false
-        default_access.properties["enable-flatpak-portal"] = false
+      pwNotForAudioConfigPkg = pkgs.writeTextDir "share/wireplumber/wireplumber.conf.d/90-nixos-no-audio.conf" ''
+        # PipeWire is not used for audio, so WirePlumber should not be handling it
+        wireplumber.profiles = {
+          main = {
+            hardware.audio = disabled
+            hardware.bluetooth = disabled
+          }
+        }
       '';
-      systemwideBluetoothConfigPkg = pkgs.writeTextDir "share/wireplumber/bluetooth.lua.d/80-systemwide.lua" ''
-        -- When running system-wide, logind-integration needs to be disabled.
-        bluez_monitor.properties["with-logind"] = false
+
+      systemwideConfigPkg = pkgs.writeTextDir "share/wireplumber/wireplumber.conf.d/90-nixos-systemwide.conf" ''
+        # When running system-wide, we don't have logind to call ReserveDevice
+        wireplumber.profiles = {
+          main = {
+            support.reserve-device = disabled
+          }
+        }
       '';
 
       configPackages = cfg.configPackages
           ++ lib.optional (!pwUsedForAudio) pwNotForAudioConfigPkg
-          ++ lib.optionals config.services.pipewire.systemWide [ systemwideConfigPkg systemwideBluetoothConfigPkg ];
+          ++ lib.optional config.services.pipewire.systemWide systemwideConfigPkg;
 
       configs = pkgs.buildEnv {
         name = "wireplumber-configs";
diff --git a/nixos/modules/services/development/hoogle.nix b/nixos/modules/services/development/hoogle.nix
index 88dd01fd8aab..c90bb7f01902 100644
--- a/nixos/modules/services/development/hoogle.nix
+++ b/nixos/modules/services/development/hoogle.nix
@@ -56,6 +56,16 @@ in {
       description = lib.mdDoc "Set the host to bind on.";
       default = "127.0.0.1";
     };
+
+    extraOptions = mkOption {
+      type = types.listOf types.str;
+      default = [];
+      example = [ "--no-security-headers" ];
+      description = lib.mdDoc ''
+        Additional command-line arguments to pass to
+        {command}`hoogle server`
+      '';
+    };
   };
 
   config = mkIf cfg.enable {
@@ -66,7 +76,10 @@ in {
 
       serviceConfig = {
         Restart = "always";
-        ExecStart = ''${hoogleEnv}/bin/hoogle server --local --port ${toString cfg.port} --home ${cfg.home} --host ${cfg.host}'';
+        ExecStart = ''
+          ${hoogleEnv}/bin/hoogle server --local --port ${toString cfg.port} --home ${cfg.home} --host ${cfg.host} \
+            ${concatStringsSep " " cfg.extraOptions}
+        '';
 
         DynamicUser = true;
 
diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix
index 8a9e38d0547b..c4837ff80ec7 100644
--- a/nixos/modules/services/hardware/fwupd.nix
+++ b/nixos/modules/services/hardware/fwupd.nix
@@ -14,11 +14,11 @@ let
 
   customEtc = {
     "fwupd/fwupd.conf" = {
-      source = format.generate "fwupd.conf" {
+      source = format.generate "fwupd.conf" ({
         fwupd = cfg.daemonSettings;
       } // lib.optionalAttrs (lib.length (lib.attrNames cfg.uefiCapsuleSettings) != 0) {
         uefi_capsule = cfg.uefiCapsuleSettings;
-      };
+      });
       # fwupd tries to chmod the file if it doesn't have the right permissions
       mode = "0640";
     };
diff --git a/nixos/modules/services/mail/listmonk.nix b/nixos/modules/services/mail/listmonk.nix
index 945eb436c1f2..d6399304cc10 100644
--- a/nixos/modules/services/mail/listmonk.nix
+++ b/nixos/modules/services/mail/listmonk.nix
@@ -187,7 +187,11 @@ in {
           # Indeed, it will try to create all the folders and realize one of them already exist.
           # Therefore, we have to create it ourselves.
           ''${pkgs.coreutils}/bin/mkdir -p "''${STATE_DIRECTORY}/listmonk/uploads"''
-          "${cfg.package}/bin/listmonk --config ${cfgFile} --idempotent --install --upgrade --yes"
+          # setup database if not already done
+          "${cfg.package}/bin/listmonk --config ${cfgFile} --idempotent --install --yes"
+          # apply db migrations (setup and migrations can not be done in one step
+          # with "--install --upgrade" listmonk ignores the upgrade)
+          "${cfg.package}/bin/listmonk --config ${cfgFile} --upgrade --yes"
           "${updateDatabaseConfigScript}/bin/update-database-config.sh"
         ];
         ExecStart = "${cfg.package}/bin/listmonk --config ${cfgFile}";
diff --git a/nixos/modules/services/matrix/matrix-sliding-sync.nix b/nixos/modules/services/matrix/matrix-sliding-sync.nix
index 8b22cd7dba80..d62e41bebd64 100644
--- a/nixos/modules/services/matrix/matrix-sliding-sync.nix
+++ b/nixos/modules/services/matrix/matrix-sliding-sync.nix
@@ -37,7 +37,7 @@ in
             type = lib.types.str;
             default = "127.0.0.1:8009";
             example = "[::]:8008";
-            description = lib.mdDoc "The interface and port to listen on.";
+            description = lib.mdDoc "The interface and port or path (for unix socket) to listen on.";
           };
 
           SYNCV3_LOG_LEVEL = lib.mkOption {
@@ -98,6 +98,7 @@ in
         ExecStart = lib.getExe cfg.package;
         StateDirectory = "matrix-sliding-sync";
         WorkingDirectory = "%S/matrix-sliding-sync";
+        RuntimeDirectory = "matrix-sliding-sync";
         Restart = "on-failure";
         RestartSec = "1s";
       };
diff --git a/nixos/modules/services/matrix/synapse.nix b/nixos/modules/services/matrix/synapse.nix
index e3f9c7742cc7..7291c0fcbcdd 100644
--- a/nixos/modules/services/matrix/synapse.nix
+++ b/nixos/modules/services/matrix/synapse.nix
@@ -1232,7 +1232,8 @@ in {
             ProtectKernelTunables = true;
             ProtectProc = "invisible";
             ProtectSystem = "strict";
-            ReadWritePaths = [ cfg.dataDir cfg.settings.media_store_path ];
+            ReadWritePaths = [ cfg.dataDir cfg.settings.media_store_path ] ++
+              (map (listener: dirOf listener.path) (filter (listener: listener.path != null) cfg.settings.listeners));
             RemoveIPC = true;
             RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
             RestrictNamespaces = true;
diff --git a/nixos/modules/services/misc/etebase-server.nix b/nixos/modules/services/misc/etebase-server.nix
index 045048a1a2e3..546d52b1a3b5 100644
--- a/nixos/modules/services/misc/etebase-server.nix
+++ b/nixos/modules/services/misc/etebase-server.nix
@@ -5,9 +5,6 @@ with lib;
 let
   cfg = config.services.etebase-server;
 
-  pythonEnv = pkgs.python3.withPackages (ps: with ps;
-    [ etebase-server daphne ]);
-
   iniFmt = pkgs.formats.ini {};
 
   configIni = iniFmt.generate "etebase-server.ini" cfg.settings;
@@ -46,6 +43,13 @@ in
         '';
       };
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.python3.pkgs.etebase-server;
+        defaultText = literalExpression "pkgs.python3.pkgs.etebase-server";
+        description = lib.mdDoc "etebase-server package to use.";
+      };
+
       dataDir = mkOption {
         type = types.str;
         default = "/var/lib/etebase-server";
@@ -164,7 +168,7 @@ in
       (runCommand "etebase-server" {
         nativeBuildInputs = [ makeWrapper ];
       } ''
-        makeWrapper ${pythonEnv}/bin/etebase-server \
+        makeWrapper ${cfg.package}/bin/etebase-server \
           $out/bin/etebase-server \
           --chdir ${escapeShellArg cfg.dataDir} \
           --prefix ETEBASE_EASY_CONFIG_PATH : "${configIni}"
@@ -173,13 +177,14 @@ in
 
     systemd.tmpfiles.rules = [
       "d '${cfg.dataDir}' - ${cfg.user} ${config.users.users.${cfg.user}.group} - -"
+      "d '${builtins.dirOf cfg.unixSocket}' - ${cfg.user} ${config.users.users.${cfg.user}.group} - -"
     ];
 
     systemd.services.etebase-server = {
       description = "An Etebase (EteSync 2.0) server";
       after = [ "network.target" "systemd-tmpfiles-setup.service" ];
+      path = [ cfg.package ];
       wantedBy = [ "multi-user.target" ];
-      path = [ pythonEnv ];
       serviceConfig = {
         User = cfg.user;
         Restart = "always";
@@ -187,24 +192,26 @@ in
       };
       environment = {
         ETEBASE_EASY_CONFIG_PATH = configIni;
+        PYTHONPATH = cfg.package.pythonPath;
       };
       preStart = ''
         # Auto-migrate on first run or if the package has changed
         versionFile="${cfg.dataDir}/src-version"
-        if [[ $(cat "$versionFile" 2>/dev/null) != ${pkgs.etebase-server} ]]; then
+        if [[ $(cat "$versionFile" 2>/dev/null) != ${cfg.package} ]]; then
           etebase-server migrate --no-input
           etebase-server collectstatic --no-input --clear
-          echo ${pkgs.etebase-server} > "$versionFile"
+          echo ${cfg.package} > "$versionFile"
         fi
       '';
       script =
         let
+          python = cfg.package.python;
           networking = if cfg.unixSocket != null
-          then "-u ${cfg.unixSocket}"
-          else "-b 0.0.0.0 -p ${toString cfg.port}";
+          then "--uds ${cfg.unixSocket}"
+          else "--host 0.0.0.0 --port ${toString cfg.port}";
         in ''
-          cd "${pythonEnv}/lib/etebase-server";
-          daphne ${networking} \
+          ${python.pkgs.uvicorn}/bin/uvicorn ${networking} \
+            --app-dir ${cfg.package}/${cfg.package.python.sitePackages} \
             etebase_server.asgi:application
         '';
     };
diff --git a/nixos/modules/services/misc/llama-cpp.nix b/nixos/modules/services/misc/llama-cpp.nix
index 4d76456fb2fd..305d4538e89a 100644
--- a/nixos/modules/services/misc/llama-cpp.nix
+++ b/nixos/modules/services/misc/llama-cpp.nix
@@ -56,7 +56,7 @@ in {
       serviceConfig = {
         Type = "idle";
         KillSignal = "SIGINT";
-        ExecStart = "${cfg.package}/bin/llama-cpp-server --log-disable --host ${cfg.host} --port ${builtins.toString cfg.port} -m ${cfg.model} ${utils.escapeSystemdExecArgs cfg.extraFlags}";
+        ExecStart = "${cfg.package}/bin/llama-server --log-disable --host ${cfg.host} --port ${builtins.toString cfg.port} -m ${cfg.model} ${utils.escapeSystemdExecArgs cfg.extraFlags}";
         Restart = "on-failure";
         RestartSec = 300;
 
diff --git a/nixos/modules/services/misc/ollama.nix b/nixos/modules/services/misc/ollama.nix
index 3ac3beb4de07..7a5661510e25 100644
--- a/nixos/modules/services/misc/ollama.nix
+++ b/nixos/modules/services/misc/ollama.nix
@@ -13,48 +13,60 @@ in
 {
   options = {
     services.ollama = {
-      enable = lib.mkEnableOption (
-        lib.mdDoc "Server for local large language models"
-      );
+      enable = lib.mkEnableOption "ollama server for local large language models";
+      package = lib.mkPackageOption pkgs "ollama" { };
       listenAddress = lib.mkOption {
         type = types.str;
         default = "127.0.0.1:11434";
-        description = lib.mdDoc ''
-          Specifies the bind address on which the ollama server HTTP interface listens.
+        example = "0.0.0.0:11111";
+        description = ''
+          The address which the ollama server HTTP interface binds and listens to.
         '';
       };
       acceleration = lib.mkOption {
         type = types.nullOr (types.enum [ "rocm" "cuda" ]);
         default = null;
         example = "rocm";
-        description = lib.mdDoc ''
-          Specifies the interface to use for hardware acceleration.
+        description = ''
+          What interface to use for hardware acceleration.
 
           - `rocm`: supported by modern AMD GPUs
           - `cuda`: supported by modern NVIDIA GPUs
         '';
       };
-      package = lib.mkPackageOption pkgs "ollama" { };
+      environmentVariables = lib.mkOption {
+        type = types.attrsOf types.str;
+        default = { };
+        example = {
+          HOME = "/tmp";
+          OLLAMA_LLM_LIBRARY = "cpu";
+        };
+        description = ''
+          Set arbitrary environment variables for the ollama service.
+
+          Be aware that these are only seen by the ollama server (systemd service),
+          not normal invocations like `ollama run`.
+          Since `ollama run` is mostly a shell around the ollama server, this is usually sufficient.
+        '';
+      };
     };
   };
 
   config = lib.mkIf cfg.enable {
-    systemd = {
-      services.ollama = {
-        wantedBy = [ "multi-user.target" ];
-        description = "Server for local large language models";
-        after = [ "network.target" ];
-        environment = {
-          HOME = "%S/ollama";
-          OLLAMA_MODELS = "%S/ollama/models";
-          OLLAMA_HOST = cfg.listenAddress;
-        };
-        serviceConfig = {
-          ExecStart = "${lib.getExe ollamaPackage} serve";
-          WorkingDirectory = "/var/lib/ollama";
-          StateDirectory = [ "ollama" ];
-          DynamicUser = true;
-        };
+    systemd.services.ollama = {
+      description = "Server for local large language models";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      environment = cfg.environmentVariables // {
+        HOME = "%S/ollama";
+        OLLAMA_MODELS = "%S/ollama/models";
+        OLLAMA_HOST = cfg.listenAddress;
+      };
+      serviceConfig = {
+        ExecStart = "${lib.getExe ollamaPackage} serve";
+        WorkingDirectory = "%S/ollama";
+        StateDirectory = [ "ollama" ];
+        DynamicUser = true;
       };
     };
 
diff --git a/nixos/modules/services/misc/tabby.nix b/nixos/modules/services/misc/tabby.nix
new file mode 100644
index 000000000000..a3072e5df75e
--- /dev/null
+++ b/nixos/modules/services/misc/tabby.nix
@@ -0,0 +1,203 @@
+{ config, lib, pkgs, ... }:
+let
+  inherit (lib) types;
+
+  cfg = config.services.tabby;
+  format = pkgs.formats.toml { };
+  tabbyPackage = cfg.package.override {
+    inherit (cfg) acceleration;
+  };
+in
+{
+  options = {
+    services.tabby = {
+      enable = lib.mkEnableOption (
+        lib.mdDoc "Self-hosted AI coding assistant using large language models"
+      );
+
+      package = lib.mkPackageOption pkgs "tabby" { };
+
+      port = lib.mkOption {
+        type = types.port;
+        default = 11029;
+        description = lib.mdDoc ''
+          Specifies the bind port on which the tabby server HTTP interface listens.
+        '';
+      };
+
+      model = lib.mkOption {
+        type = types.str;
+        default = "TabbyML/StarCoder-1B";
+        description = lib.mdDoc ''
+          Specify the model that tabby will use to generate completions.
+
+          This model will be downloaded automatically if it is not already present.
+
+          If you want to utilize an existing model that you've already
+          downloaded you'll need to move it into tabby's state directory which
+          lives in `/var/lib/tabby`. Because the tabby.service is configured to
+          use a DyanmicUser the service will need to have been started at least
+          once before you can move the locally existing model into
+          `/var/lib/tabby`. You can set the model to 'none' and tabby will
+          startup and fail to download a model, but will have created the
+          `/var/lib/tabby` directory. You can then copy over the model manually
+          into `/var/lib/tabby`, update the model option to the name you just
+          downloaded and copied over then `nixos-rebuild switch` to start using
+          it.
+
+          $ tabby download --model TabbyML/DeepseekCoder-6.7B
+          $ find ~/.tabby/ | tail -n1
+          /home/ghthor/.tabby/models/TabbyML/DeepseekCoder-6.7B/ggml/q8_0.v2.gguf
+          $ sudo rsync -r ~/.tabby/models/ /var/lib/tabby/models/
+          $ sudo chown -R tabby:tabby /var/lib/tabby/models/
+
+          See for Model Options:
+          > https://github.com/TabbyML/registry-tabby
+        '';
+      };
+
+      acceleration = lib.mkOption {
+        type = types.nullOr (types.enum [ "cpu" "rocm" "cuda" "metal" ]);
+        default = null;
+        example = "rocm";
+        description = lib.mdDoc ''
+          Specifies the device to use for hardware acceleration.
+
+          -   `cpu`: no acceleration just use the CPU
+          -  `rocm`: supported by modern AMD GPUs
+          -  `cuda`: supported by modern NVIDIA GPUs
+          - `metal`: supported on darwin aarch64 machines
+
+          Tabby will try and determine what type of acceleration that is
+          already enabled in your configuration when `acceleration = null`.
+
+          - nixpkgs.config.cudaSupport
+          - nixpkgs.config.rocmSupport
+          - if stdenv.isDarwin && stdenv.isAarch64
+
+          IFF multiple acceleration methods are found to be enabled or if you
+          haven't set either `cudaSupport or rocmSupport` you will have to
+          specify the device type manually here otherwise it will default to
+          the first from the list above or to cpu.
+        '';
+      };
+
+      settings = lib.mkOption {
+        inherit (format) type;
+        default = { };
+        description = lib.mdDoc ''
+          Tabby scheduler configuration
+
+          See for more details:
+          > https://tabby.tabbyml.com/docs/configuration/#repository-context-for-code-completion
+        '';
+        example = lib.literalExpression ''
+          settings = {
+            repositories = [
+              { name = "tabby"; git_url = "https://github.com/TabbyML/tabby.git"; }
+              { name = "CTranslate2"; git_url = "git@github.com:OpenNMT/CTranslate2.git"; }
+
+              # local directory is also supported, but limited by systemd DynamicUser=1
+              # adding local repositories will need to be done manually
+              { name = "repository_a"; git_url = "file:///var/lib/tabby/repository_a"; }
+            ];
+          };
+        '';
+      };
+
+      usageCollection = lib.mkOption {
+        type = types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Enable sending anonymous usage data.
+
+          See for more details:
+          > https://tabby.tabbyml.com/docs/configuration#usage-collection
+        '';
+      };
+
+      indexInterval = lib.mkOption {
+        type = types.str;
+        default = "5hours";
+        example = "5hours";
+        description = lib.mdDoc ''
+          Run tabby scheduler to generate the index database at this interval.
+          Updates by default every 5 hours. This value applies to
+          `OnUnitInactiveSec`
+
+          The format is described in
+          {manpage}`systemd.time(7)`.
+
+          To disable running `tabby scheduler --now` updates, set to `"never"`
+        '';
+      };
+    };
+  };
+
+  # TODO(ghthor): firewall config
+
+  config = lib.mkIf cfg.enable {
+    environment = {
+      etc."tabby/config.toml".source = format.generate "config.toml" cfg.settings;
+      systemPackages = [ tabbyPackage ];
+    };
+
+
+    systemd = let
+      serviceUser = {
+        WorkingDirectory = "/var/lib/tabby";
+        StateDirectory = [ "tabby" ];
+        ConfigurationDirectory = [ "tabby" ];
+        DynamicUser = true;
+        User = "tabby";
+        Group = "tabby";
+      };
+
+      serviceEnv = lib.mkMerge [
+        {
+          TABBY_ROOT = "%S/tabby";
+        }
+        (lib.mkIf (!cfg.usageCollection) {
+          TABBY_DISABLE_USAGE_COLLECTION = "1";
+        })
+      ];
+    in {
+      services.tabby = {
+        wantedBy = [ "multi-user.target" ];
+        description = "Self-hosted AI coding assistant using large language models";
+        after = [ "network.target" ];
+        environment = serviceEnv;
+        serviceConfig = lib.mkMerge [
+          serviceUser
+          {
+            ExecStart =
+              "${lib.getExe tabbyPackage} serve --model ${cfg.model} --port ${toString cfg.port} --device ${tabbyPackage.featureDevice}";
+          }
+        ];
+      };
+
+      services.tabby-scheduler = lib.mkIf (cfg.indexInterval != "never") {
+        wantedBy = [ "multi-user.target" ];
+        description = "Tabby repository indexing service";
+        after = [ "network.target" ];
+        environment = serviceEnv;
+        preStart = "cp -f /etc/tabby/config.toml \${TABBY_ROOT}/config.toml";
+        serviceConfig = lib.mkMerge [
+          serviceUser
+          {
+            # Type = "oneshot";
+            ExecStart = "${lib.getExe tabbyPackage} scheduler --now";
+          }
+        ];
+      };
+      timers.tabby-scheduler = lib.mkIf (cfg.indexInterval != "never") {
+        description = "Update timer for tabby-scheduler";
+        partOf = [ "tabby-scheduler.service" ];
+        wantedBy = [ "timers.target" ];
+        timerConfig.OnUnitInactiveSec = cfg.indexInterval;
+      };
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ ghthor ];
+}
diff --git a/nixos/modules/services/monitoring/mackerel-agent.nix b/nixos/modules/services/monitoring/mackerel-agent.nix
index 5915634ed26f..d1e84c0359dc 100644
--- a/nixos/modules/services/monitoring/mackerel-agent.nix
+++ b/nixos/modules/services/monitoring/mackerel-agent.nix
@@ -81,7 +81,7 @@ in {
       include = mkDefault "/etc/mackerel-agent/conf.d/*.conf";
     };
 
-    # upstream service file in https://git.io/JUt4Q
+    # upstream service file in https://github.com/mackerelio/mackerel-agent/blob/master/packaging/rpm/src/mackerel-agent.service
     systemd.services.mackerel-agent = {
       description = "mackerel.io agent";
       wants = [ "network-online.target" ];
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/restic.nix b/nixos/modules/services/monitoring/prometheus/exporters/restic.nix
index 5b32c93a666d..977bd42e9812 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/restic.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/restic.nix
@@ -93,12 +93,14 @@ in
   };
 
   serviceOpts = {
+    script = ''
+      export RESTIC_PASSWORD_FILE=$CREDENTIALS_DIRECTORY/RESTIC_PASSWORD_FILE
+      ${pkgs.prometheus-restic-exporter}/bin/restic-exporter.py \
+        ${concatStringsSep " \\\n  " cfg.extraFlags}
+    '';
     serviceConfig = {
-      ExecStart = ''
-        ${pkgs.prometheus-restic-exporter}/bin/restic-exporter.py \
-          ${concatStringsSep " \\\n  " cfg.extraFlags}
-      '';
       EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
+      LoadCredential = [ "RESTIC_PASSWORD_FILE:${cfg.passwordFile}" ];
     };
     environment =
       let
@@ -108,8 +110,7 @@ in
         toRcloneVal = v: if lib.isBool v then lib.boolToString v else v;
       in
       {
-        RESTIC_REPO_URL = cfg.repository;
-        RESTIC_REPO_PASSWORD_FILE = cfg.passwordFile;
+        RESTIC_REPOSITORY = cfg.repository;
         LISTEN_ADDRESS = cfg.listenAddress;
         LISTEN_PORT = toString cfg.port;
         REFRESH_INTERVAL = toString cfg.refreshInterval;
diff --git a/nixos/modules/services/monitoring/scrutiny.nix b/nixos/modules/services/monitoring/scrutiny.nix
index 454668a9a128..031f5a30cada 100644
--- a/nixos/modules/services/monitoring/scrutiny.nix
+++ b/nixos/modules/services/monitoring/scrutiny.nix
@@ -1,5 +1,11 @@
 { config, lib, pkgs, ... }:
 let
+  inherit (lib) maintainers;
+  inherit (lib.meta) getExe;
+  inherit (lib.modules) mkIf mkMerge;
+  inherit (lib.options) literalExpression mkEnableOption mkOption mkPackageOption;
+  inherit (lib.types) bool enum nullOr port str submodule;
+
   cfg = config.services.scrutiny;
   # Define the settings format used for this program
   settingsFormat = pkgs.formats.yaml { };
@@ -7,20 +13,16 @@ in
 {
   options = {
     services.scrutiny = {
-      enable = lib.mkEnableOption "Enables the scrutiny web application.";
+      enable = mkEnableOption "Scrutiny, a web application for drive monitoring";
 
-      package = lib.mkPackageOptionMD pkgs "scrutiny" { };
+      package = mkPackageOption pkgs "scrutiny" { };
 
-      openFirewall = lib.mkOption {
-        type = lib.types.bool;
-        default = false;
-        description = "Open the default ports in the firewall for Scrutiny.";
-      };
+      openFirewall = mkEnableOption "opening the default ports in the firewall for Scrutiny";
 
-      influxdb.enable = lib.mkOption {
-        type = lib.types.bool;
+      influxdb.enable = mkOption {
+        type = bool;
         default = true;
-        description = lib.mdDoc ''
+        description = ''
           Enables InfluxDB on the host system using the `services.influxdb2` NixOS module
           with default options.
 
@@ -29,127 +31,124 @@ in
         '';
       };
 
-      settings = lib.mkOption {
-        description = lib.mdDoc ''
+      settings = mkOption {
+        description = ''
           Scrutiny settings to be rendered into the configuration file.
 
           See https://github.com/AnalogJ/scrutiny/blob/master/example.scrutiny.yaml.
         '';
         default = { };
-        type = lib.types.submodule {
+        type = submodule {
           freeformType = settingsFormat.type;
 
-          options.web.listen.port = lib.mkOption {
-            type = lib.types.port;
+          options.web.listen.port = mkOption {
+            type = port;
             default = 8080;
-            description = lib.mdDoc "Port for web application to listen on.";
+            description = "Port for web application to listen on.";
           };
 
-          options.web.listen.host = lib.mkOption {
-            type = lib.types.str;
+          options.web.listen.host = mkOption {
+            type = str;
             default = "0.0.0.0";
-            description = lib.mdDoc "Interface address for web application to bind to.";
+            description = "Interface address for web application to bind to.";
           };
 
-          options.web.listen.basepath = lib.mkOption {
-            type = lib.types.str;
+          options.web.listen.basepath = mkOption {
+            type = str;
             default = "";
             example = "/scrutiny";
-            description = lib.mdDoc ''
+            description = ''
               If Scrutiny will be behind a path prefixed reverse proxy, you can override this
               value to serve Scrutiny on a subpath.
             '';
           };
 
-          options.log.level = lib.mkOption {
-            type = lib.types.enum [ "INFO" "DEBUG" ];
+          options.log.level = mkOption {
+            type = enum [ "INFO" "DEBUG" ];
             default = "INFO";
-            description = lib.mdDoc "Log level for Scrutiny.";
+            description = "Log level for Scrutiny.";
           };
 
-          options.web.influxdb.scheme = lib.mkOption {
-            type = lib.types.str;
+          options.web.influxdb.scheme = mkOption {
+            type = str;
             default = "http";
-            description = lib.mdDoc "URL scheme to use when connecting to InfluxDB.";
+            description = "URL scheme to use when connecting to InfluxDB.";
           };
 
-          options.web.influxdb.host = lib.mkOption {
-            type = lib.types.str;
+          options.web.influxdb.host = mkOption {
+            type = str;
             default = "0.0.0.0";
-            description = lib.mdDoc "IP or hostname of the InfluxDB instance.";
+            description = "IP or hostname of the InfluxDB instance.";
           };
 
-          options.web.influxdb.port = lib.mkOption {
-            type = lib.types.port;
+          options.web.influxdb.port = mkOption {
+            type = port;
             default = 8086;
-            description = lib.mdDoc "The port of the InfluxDB instance.";
+            description = "The port of the InfluxDB instance.";
           };
 
-          options.web.influxdb.tls.insecure_skip_verify = lib.mkOption {
-            type = lib.types.bool;
-            default = false;
-            description = lib.mdDoc "Skip TLS verification when connecting to InfluxDB.";
-          };
+          options.web.influxdb.tls.insecure_skip_verify = mkEnableOption "skipping TLS verification when connecting to InfluxDB";
 
-          options.web.influxdb.token = lib.mkOption {
-            type = lib.types.nullOr lib.types.str;
+          options.web.influxdb.token = mkOption {
+            type = nullOr str;
             default = null;
-            description = lib.mdDoc "Authentication token for connecting to InfluxDB.";
+            description = "Authentication token for connecting to InfluxDB.";
           };
 
-          options.web.influxdb.org = lib.mkOption {
-            type = lib.types.nullOr lib.types.str;
+          options.web.influxdb.org = mkOption {
+            type = nullOr str;
             default = null;
-            description = lib.mdDoc "InfluxDB organisation under which to store data.";
+            description = "InfluxDB organisation under which to store data.";
           };
 
-          options.web.influxdb.bucket = lib.mkOption {
-            type = lib.types.nullOr lib.types.str;
+          options.web.influxdb.bucket = mkOption {
+            type = nullOr str;
             default = null;
-            description = lib.mdDoc "InfluxDB bucket in which to store data.";
+            description = "InfluxDB bucket in which to store data.";
           };
         };
       };
 
       collector = {
-        enable = lib.mkEnableOption "Enables the scrutiny metrics collector.";
+        enable = mkEnableOption "the Scrutiny metrics collector";
 
-        package = lib.mkPackageOptionMD pkgs "scrutiny-collector" { };
+        package = mkPackageOption pkgs "scrutiny-collector" { };
 
-        schedule = lib.mkOption {
-          type = lib.types.str;
+        schedule = mkOption {
+          type = str;
           default = "*:0/15";
-          description = lib.mdDoc ''
+          description = ''
             How often to run the collector in systemd calendar format.
           '';
         };
 
-        settings = lib.mkOption {
-          description = lib.mdDoc ''
+        settings = mkOption {
+          description = ''
             Collector settings to be rendered into the collector configuration file.
 
             See https://github.com/AnalogJ/scrutiny/blob/master/example.collector.yaml.
           '';
           default = { };
-          type = lib.types.submodule {
+          type = submodule {
             freeformType = settingsFormat.type;
 
-            options.host.id = lib.mkOption {
-              type = lib.types.nullOr lib.types.str;
+            options.host.id = mkOption {
+              type = nullOr str;
               default = null;
-              description = lib.mdDoc "Host ID for identifying/labelling groups of disks";
+              description = "Host ID for identifying/labelling groups of disks";
             };
 
-            options.api.endpoint = lib.mkOption {
-              type = lib.types.str;
-              default = "http://localhost:8080";
-              description = lib.mdDoc "Scrutiny app API endpoint for sending metrics to.";
+            options.api.endpoint = mkOption {
+              type = str;
+              default = "http://localhost:${toString cfg.settings.web.listen.port}";
+              defaultText = literalExpression ''"http://localhost:''${config.services.scrutiny.settings.web.listen.port}"'';
+              description = "Scrutiny app API endpoint for sending metrics to.";
             };
 
-            options.log.level = lib.mkOption {
-              type = lib.types.enum [ "INFO" "DEBUG" ];
+            options.log.level = mkOption {
+              type = enum [ "INFO" "DEBUG" ];
               default = "INFO";
-              description = lib.mdDoc "Log level for Scrutiny collector.";
+              description = "Log level for Scrutiny collector.";
             };
           };
         };
@@ -157,65 +156,62 @@ in
     };
   };
 
-  config = lib.mkIf (cfg.enable || cfg.collector.enable) {
-    services.influxdb2.enable = cfg.influxdb.enable;
-
-    networking.firewall = lib.mkIf cfg.openFirewall {
-      allowedTCPPorts = [ cfg.settings.web.listen.port ];
-    };
+  config = mkMerge [
+    (mkIf cfg.enable {
+      services.influxdb2.enable = cfg.influxdb.enable;
 
-    services.smartd = lib.mkIf cfg.collector.enable {
-      enable = true;
-      extraOptions = [
-        "-A /var/log/smartd/"
-        "--interval=600"
-      ];
-    };
+      networking.firewall = mkIf cfg.openFirewall {
+        allowedTCPPorts = [ cfg.settings.web.listen.port ];
+      };
 
-    systemd = {
-      services = {
-        scrutiny = lib.mkIf cfg.enable {
-          description = "Hard Drive S.M.A.R.T Monitoring, Historical Trends & Real World Failure Thresholds";
-          wantedBy = [ "multi-user.target" ];
-          after = [ "network.target" ];
-          environment = {
-            SCRUTINY_VERSION = "1";
-            SCRUTINY_WEB_DATABASE_LOCATION = "/var/lib/scrutiny/scrutiny.db";
-            SCRUTINY_WEB_SRC_FRONTEND_PATH = "${cfg.package}/share/scrutiny";
-          };
-          serviceConfig = {
-            DynamicUser = true;
-            ExecStart = "${lib.getExe cfg.package} start --config ${settingsFormat.generate "scrutiny.yaml" cfg.settings}";
-            Restart = "always";
-            StateDirectory = "scrutiny";
-            StateDirectoryMode = "0750";
-          };
+      systemd.services.scrutiny = {
+        description = "Hard Drive S.M.A.R.T Monitoring, Historical Trends & Real World Failure Thresholds";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ] ++ lib.optional cfg.influxdb.enable "influxdb2.service";
+        wants = lib.optional cfg.influxdb.enable "influxdb2.service";
+        environment = {
+          SCRUTINY_VERSION = "1";
+          SCRUTINY_WEB_DATABASE_LOCATION = "/var/lib/scrutiny/scrutiny.db";
+          SCRUTINY_WEB_SRC_FRONTEND_PATH = "${cfg.package}/share/scrutiny";
+        };
+        serviceConfig = {
+          DynamicUser = true;
+          ExecStart = "${getExe cfg.package} start --config ${settingsFormat.generate "scrutiny.yaml" cfg.settings}";
+          Restart = "always";
+          StateDirectory = "scrutiny";
+          StateDirectoryMode = "0750";
         };
+      };
+    })
+    (mkIf cfg.collector.enable {
+      services.smartd = {
+        enable = true;
+        extraOptions = [
+          "-A /var/log/smartd/"
+          "--interval=600"
+        ];
+      };
 
-        scrutiny-collector = lib.mkIf cfg.collector.enable {
+      systemd = {
+        services.scrutiny-collector = {
           description = "Scrutiny Collector Service";
+          after = lib.optional cfg.enable "scrutiny.service";
+          wants = lib.optional cfg.enable "scrutiny.service";
           environment = {
             COLLECTOR_VERSION = "1";
             COLLECTOR_API_ENDPOINT = cfg.collector.settings.api.endpoint;
           };
           serviceConfig = {
             Type = "oneshot";
-            ExecStart = "${lib.getExe cfg.collector.package} run --config ${settingsFormat.generate "scrutiny-collector.yaml" cfg.collector.settings}";
+            ExecStart = "${getExe cfg.collector.package} run --config ${settingsFormat.generate "scrutiny-collector.yaml" cfg.collector.settings}";
           };
+          startAt = cfg.collector.schedule;
         };
-      };
 
-      timers = lib.mkIf cfg.collector.enable {
-        scrutiny-collector = {
-          timerConfig = {
-            OnCalendar = cfg.collector.schedule;
-            Persistent = true;
-            Unit = "scrutiny-collector.service";
-          };
-        };
+        timers.scrutiny-collector.timerConfig.Persistent = true;
       };
-    };
-  };
+    })
+  ];
 
-  meta.maintainers = [ lib.maintainers.jnsgruk ];
+  meta.maintainers = [ maintainers.jnsgruk ];
 }
diff --git a/nixos/modules/services/networking/murmur.nix b/nixos/modules/services/networking/murmur.nix
index 5805f332a66f..1fb5063e5ad8 100644
--- a/nixos/modules/services/networking/murmur.nix
+++ b/nixos/modules/services/networking/murmur.nix
@@ -33,7 +33,7 @@ let
     sendversion=${boolToString cfg.sendVersion}
 
     ${optionalString (cfg.registerName != "") "registerName=${cfg.registerName}"}
-    ${optionalString (cfg.registerPassword == "") "registerPassword=${cfg.registerPassword}"}
+    ${optionalString (cfg.registerPassword != "") "registerPassword=${cfg.registerPassword}"}
     ${optionalString (cfg.registerUrl != "") "registerUrl=${cfg.registerUrl}"}
     ${optionalString (cfg.registerHostname != "") "registerHostname=${cfg.registerHostname}"}
 
diff --git a/nixos/modules/services/networking/nebula.nix b/nixos/modules/services/networking/nebula.nix
index e13876172dac..2f9e41ae9c80 100644
--- a/nixos/modules/services/networking/nebula.nix
+++ b/nixos/modules/services/networking/nebula.nix
@@ -10,6 +10,15 @@ let
   format = pkgs.formats.yaml {};
 
   nameToId = netName: "nebula-${netName}";
+
+  resolveFinalPort = netCfg:
+    if netCfg.listen.port == null then
+      if (netCfg.isLighthouse || netCfg.isRelay) then
+        4242
+      else
+        0
+    else
+      netCfg.listen.port;
 in
 {
   # Interface
@@ -95,8 +104,15 @@ in
             };
 
             listen.port = mkOption {
-              type = types.port;
-              default = 4242;
+              type = types.nullOr types.port;
+              default = null;
+              defaultText = lib.literalExpression ''
+                if (config.services.nebula.networks.''${name}.isLighthouse ||
+                    config.services.nebula.networks.''${name}.isRelay) then
+                  4242
+                else
+                  0;
+              '';
               description = lib.mdDoc "Port number to listen on.";
             };
 
@@ -174,7 +190,7 @@ in
           };
           listen = {
             host = netCfg.listen.host;
-            port = netCfg.listen.port;
+            port = resolveFinalPort netCfg;
           };
           tun = {
             disabled = netCfg.tun.disable;
@@ -185,7 +201,15 @@ in
             outbound = netCfg.firewall.outbound;
           };
         } netCfg.settings;
-        configFile = format.generate "nebula-config-${netName}.yml" settings;
+        configFile = format.generate "nebula-config-${netName}.yml" (
+          warnIf
+            ((settings.lighthouse.am_lighthouse || settings.relay.am_relay) && settings.listen.port == 0)
+            ''
+              Nebula network '${netName}' is configured as a lighthouse or relay, and its port is ${builtins.toString settings.listen.port}.
+              You will likely experience connectivity issues: https://nebula.defined.net/docs/config/listen/#listenport
+            ''
+            settings
+          );
         in
         {
           # Create the systemd service for Nebula.
@@ -229,7 +253,7 @@ in
 
     # Open the chosen ports for UDP.
     networking.firewall.allowedUDPPorts =
-      unique (mapAttrsToList (netName: netCfg: netCfg.listen.port) enabledNetworks);
+      unique (filter (port: port > 0) (mapAttrsToList (netName: netCfg: resolveFinalPort netCfg) enabledNetworks));
 
     # Create the service users and groups.
     users.users = mkMerge (mapAttrsToList (netName: netCfg:
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index c96439cf2641..b7f0d9373608 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -291,7 +291,7 @@ in
       };
 
       dns = mkOption {
-        type = types.enum [ "default" "dnsmasq" "unbound" "systemd-resolved" "none" ];
+        type = types.enum [ "default" "dnsmasq" "systemd-resolved" "none" ];
         default = "default";
         description = lib.mdDoc ''
           Set the DNS (`resolv.conf`) processing mode.
@@ -436,6 +436,7 @@ in
             And if you edit a declarative profile NetworkManager will move it to the persistent storage and treat it like a ad-hoc one,
             but there will be two profiles as soon as the systemd unit from this option runs again which can be confusing since NetworkManager tools will start displaying two profiles with the same name and probably a bit different settings depending on what you edited.
             A profile won't be deleted even if it's removed from the config until the system reboots because that's when NetworkManager clears it's temp directory.
+            If `networking.resolvconf.enable` is true, attributes affecting the name resolution (such as `ignore-auto-dns`) may not end up changing `/etc/resolv.conf` as expected when other name services (for example `networking.dhcpcd`) are enabled. Run `resolvconf -l` in the terminal to see what each service produces.
           '';
         };
         environmentFiles = mkOption {
@@ -583,6 +584,7 @@ in
       description = "Ensure that NetworkManager declarative profiles are created";
       wantedBy = [ "multi-user.target" ];
       before = [ "network-online.target" ];
+      after = [ "NetworkManager.service" ];
       script = let
         path = id: "/run/NetworkManager/system-connections/${id}.nmconnection";
       in ''
@@ -592,9 +594,7 @@ in
           ${pkgs.envsubst}/bin/envsubst -i ${ini.generate (lib.escapeShellArg profile.n) profile.v} > ${path (lib.escapeShellArg profile.n)}
         '') (lib.mapAttrsToList (n: v: { inherit n v; }) cfg.ensureProfiles.profiles)
       + ''
-        if systemctl is-active --quiet NetworkManager; then
-          ${pkgs.networkmanager}/bin/nmcli connection reload
-        fi
+        ${pkgs.networkmanager}/bin/nmcli connection reload
       '';
       serviceConfig = {
         EnvironmentFile = cfg.ensureProfiles.environmentFiles;
diff --git a/nixos/modules/services/networking/tinyproxy.nix b/nixos/modules/services/networking/tinyproxy.nix
index 8ff12b52f10c..2b7509e99ca4 100644
--- a/nixos/modules/services/networking/tinyproxy.nix
+++ b/nixos/modules/services/networking/tinyproxy.nix
@@ -7,6 +7,7 @@ let
   mkValueStringTinyproxy = with lib; v:
         if true  ==         v then "yes"
         else if false ==    v then "no"
+        else if types.path.check v then ''"${v}"''
         else generators.mkValueStringDefault {} v;
   mkKeyValueTinyproxy = {
     mkValueString ? mkValueStringDefault {}
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index 8438e472e11e..242fcd500bb0 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -76,12 +76,13 @@ in {
 
       checkconf = mkOption {
         type = types.bool;
-        default = !cfg.settings ? include;
-        defaultText = "!config.services.unbound.settings ? include";
+        default = !cfg.settings ? include && !cfg.settings ? remote-control;
+        defaultText = "!services.unbound.settings ? include && !services.unbound.settings ? remote-control";
         description = lib.mdDoc ''
           Wether to check the resulting config file with unbound checkconf for syntax errors.
 
-          If settings.include is used, then this options is disabled, as the import can likely not be resolved at build time.
+          If settings.include is used, this options is disabled, as the import can likely not be accessed at build time.
+          If settings.remote-control is used, this option is disabled, too as the control-key-file, server-cert-file and server-key-file cannot be accessed at build time.
         '';
       };
 
@@ -229,8 +230,6 @@ in {
       resolvconf = {
         useLocalResolver = mkDefault true;
       };
-
-      networkmanager.dns = "unbound";
     };
 
     environment.etc."unbound/unbound.conf".source = confFile;
diff --git a/nixos/modules/services/security/esdm.nix b/nixos/modules/services/security/esdm.nix
index 134b4be1a94c..c34fba1b3c75 100644
--- a/nixos/modules/services/security/esdm.nix
+++ b/nixos/modules/services/security/esdm.nix
@@ -4,49 +4,33 @@ let
   cfg = config.services.esdm;
 in
 {
+  imports = [
+    # removed option 'services.esdm.cuseRandomEnable'
+    (lib.mkRemovedOptionModule [ "services" "esdm" "cuseRandomEnable" ] ''
+      Use services.esdm.enableLinuxCompatServices instead.
+    '')
+    # removed option 'services.esdm.cuseUrandomEnable'
+    (lib.mkRemovedOptionModule [ "services" "esdm" "cuseUrandomEnable" ] ''
+      Use services.esdm.enableLinuxCompatServices instead.
+    '')
+    # removed option 'services.esdm.procEnable'
+    (lib.mkRemovedOptionModule [ "services" "esdm" "procEnable" ] ''
+      Use services.esdm.enableLinuxCompatServices instead.
+    '')
+    # removed option 'services.esdm.verbose'
+    (lib.mkRemovedOptionModule [ "services" "esdm" "verbose" ] ''
+      There is no replacement.
+    '')
+  ];
+
   options.services.esdm = {
     enable = lib.mkEnableOption (lib.mdDoc "ESDM service configuration");
     package = lib.mkPackageOption pkgs "esdm" { };
-    serverEnable = lib.mkOption {
-      type = lib.types.bool;
-      default = true;
-      description = lib.mdDoc ''
-        Enable option for ESDM server service. If serverEnable == false, then the esdm-server
-        will not start. Also the subsequent services esdm-cuse-random, esdm-cuse-urandom
-        and esdm-proc will not start as these have the entry Want=esdm-server.service.
-      '';
-    };
-    cuseRandomEnable = lib.mkOption {
-      type = lib.types.bool;
-      default = true;
-      description = lib.mdDoc ''
-        Enable option for ESDM cuse-random service. Determines if the esdm-cuse-random.service
-        is started.
-      '';
-    };
-    cuseUrandomEnable = lib.mkOption {
-      type = lib.types.bool;
-      default = true;
-      description = lib.mdDoc ''
-        Enable option for ESDM cuse-urandom service. Determines if the esdm-cuse-urandom.service
-        is started.
-      '';
-    };
-    procEnable = lib.mkOption {
+    enableLinuxCompatServices = lib.mkOption {
       type = lib.types.bool;
       default = true;
       description = lib.mdDoc ''
-        Enable option for ESDM proc service. Determines if the esdm-proc.service
-        is started.
-      '';
-    };
-    verbose = lib.mkOption {
-      type = lib.types.bool;
-      default = false;
-      description = lib.mdDoc ''
-        Enable verbose ExecStart for ESDM. If verbose == true, then the corresponding "ExecStart"
-        values of the 4 aforementioned services are overwritten with the option
-        for the highest verbosity.
+        Enable /dev/random, /dev/urandom and /proc/sys/kernel/random/* userspace wrapper.
       '';
     };
   };
@@ -55,46 +39,13 @@ in
     lib.mkMerge [
       ({
         systemd.packages = [ cfg.package ];
-      })
-      # It is necessary to set those options for these services to be started by systemd in NixOS
-      (lib.mkIf cfg.serverEnable {
         systemd.services."esdm-server".wantedBy = [ "basic.target" ];
-        systemd.services."esdm-server".serviceConfig = lib.mkIf cfg.verbose {
-          ExecStart = [
-            " " # unset previous value defined in 'esdm-server.service'
-            "${cfg.package}/bin/esdm-server -f -vvvvvv"
-          ];
-        };
-      })
-
-      (lib.mkIf cfg.cuseRandomEnable {
-        systemd.services."esdm-cuse-random".wantedBy = [ "basic.target" ];
-        systemd.services."esdm-cuse-random".serviceConfig = lib.mkIf cfg.verbose {
-          ExecStart = [
-            " " # unset previous value defined in 'esdm-cuse-random.service'
-            "${cfg.package}/bin/esdm-cuse-random -f -v 6"
-          ];
-        };
       })
-
-      (lib.mkIf cfg.cuseUrandomEnable {
-        systemd.services."esdm-cuse-urandom".wantedBy = [ "basic.target" ];
-        systemd.services."esdm-cuse-urandom".serviceConfig = lib.mkIf cfg.verbose {
-          ExecStart = [
-            " " # unset previous value defined in 'esdm-cuse-urandom.service'
-            "${config.services.esdm.package}/bin/esdm-cuse-urandom -f -v 6"
-          ];
-        };
-      })
-
-      (lib.mkIf cfg.procEnable {
-        systemd.services."esdm-proc".wantedBy = [ "basic.target" ];
-        systemd.services."esdm-proc".serviceConfig = lib.mkIf cfg.verbose {
-          ExecStart = [
-            " " # unset previous value defined in 'esdm-proc.service'
-            "${cfg.package}/bin/esdm-proc --relabel -f -o allow_other /proc/sys/kernel/random -v 6"
-          ];
-        };
+      # It is necessary to set those options for these services to be started by systemd in NixOS
+      (lib.mkIf cfg.enableLinuxCompatServices {
+        systemd.targets."esdm-linux-compat".wantedBy = [ "basic.target" ];
+        systemd.services."esdm-server-suspend".wantedBy = [ "sleep.target" "suspend.target" "hibernate.target" ];
+        systemd.services."esdm-server-resume".wantedBy = [ "sleep.target" "suspend.target" "hibernate.target" ];
       })
     ]);
 
diff --git a/nixos/modules/services/security/yubikey-agent.nix b/nixos/modules/services/security/yubikey-agent.nix
index a9f15e4405f2..3d5f84af2cf4 100644
--- a/nixos/modules/services/security/yubikey-agent.nix
+++ b/nixos/modules/services/security/yubikey-agent.nix
@@ -6,9 +6,6 @@ with lib;
 
 let
   cfg = config.services.yubikey-agent;
-
-  # reuse the pinentryFlavor option from the gnupg module
-  pinentryFlavor = config.programs.gnupg.agent.pinentryFlavor;
 in
 {
   ###### interface
@@ -40,14 +37,9 @@ in
 
     # This overrides the systemd user unit shipped with the
     # yubikey-agent package
-    systemd.user.services.yubikey-agent = mkIf (pinentryFlavor != null) {
-      path = [ pkgs.pinentry.${pinentryFlavor} ];
-      wantedBy = [
-        (if pinentryFlavor == "tty" || pinentryFlavor == "curses" then
-          "default.target"
-        else
-          "graphical-session.target")
-      ];
+    systemd.user.services.yubikey-agent = mkIf (config.programs.gnupg.agent.pinentryPackage != null) {
+      path = [ config.programs.gnupg.agent.pinentryPackage ];
+      wantedBy = [ "default.target" ];
     };
 
     # Yubikey-agent expects pcsd to be running in order to function.
diff --git a/nixos/modules/services/web-apps/engelsystem.nix b/nixos/modules/services/web-apps/engelsystem.nix
index 669620debce5..ae7b2b9e7d0c 100644
--- a/nixos/modules/services/web-apps/engelsystem.nix
+++ b/nixos/modules/services/web-apps/engelsystem.nix
@@ -99,7 +99,6 @@ in {
       '';
 
     services.phpfpm.pools.engelsystem = {
-      phpPackage = pkgs.php81;
       user = "engelsystem";
       settings = {
         "listen.owner" = config.services.nginx.user;
diff --git a/nixos/modules/services/web-apps/gotosocial.nix b/nixos/modules/services/web-apps/gotosocial.nix
index 45464f646da8..657509c11005 100644
--- a/nixos/modules/services/web-apps/gotosocial.nix
+++ b/nixos/modules/services/web-apps/gotosocial.nix
@@ -27,7 +27,7 @@ let
 in
 {
   meta.doc = ./gotosocial.md;
-  meta.maintainers = with lib.maintainers; [ misuzu ];
+  meta.maintainers = with lib.maintainers; [ misuzu blakesmith ];
 
   options.services.gotosocial = {
     enable = lib.mkEnableOption (lib.mdDoc "ActivityPub social network server");
diff --git a/nixos/modules/services/web-apps/komga.nix b/nixos/modules/services/web-apps/komga.nix
index 31f475fc7b04..d7ab2a9e612e 100644
--- a/nixos/modules/services/web-apps/komga.nix
+++ b/nixos/modules/services/web-apps/komga.nix
@@ -1,99 +1,122 @@
-{ config, pkgs, lib, ... }:
-
-with lib;
+{
+  config,
+  pkgs,
+  lib,
+  ...
+}:
 
 let
   cfg = config.services.komga;
-
-in {
+  inherit (lib) mkOption mkEnableOption maintainers;
+  inherit (lib.types) port str bool;
+in
+{
   options = {
     services.komga = {
-      enable = mkEnableOption (lib.mdDoc "Komga, a free and open source comics/mangas media server");
+      enable = mkEnableOption "Komga, a free and open source comics/mangas media server";
 
       port = mkOption {
-        type = types.port;
+        type = port;
         default = 8080;
-        description = lib.mdDoc ''
-          The port that Komga will listen on.
-        '';
+        description = "The port that Komga will listen on.";
       };
 
       user = mkOption {
-        type = types.str;
+        type = str;
         default = "komga";
-        description = lib.mdDoc ''
-          User account under which Komga runs.
-        '';
+        description = "User account under which Komga runs.";
       };
 
       group = mkOption {
-        type = types.str;
+        type = str;
         default = "komga";
-        description = lib.mdDoc ''
-          Group under which Komga runs.
-        '';
+        description = "Group under which Komga runs.";
       };
 
       stateDir = mkOption {
-        type = types.str;
+        type = str;
         default = "/var/lib/komga";
-        description = lib.mdDoc ''
-          State and configuration directory Komga will use.
-        '';
+        description = "State and configuration directory Komga will use.";
       };
 
       openFirewall = mkOption {
-        type = types.bool;
+        type = bool;
         default = false;
-        description = lib.mdDoc ''
-          Whether to open the firewall for the port in {option}`services.komga.port`.
-        '';
+        description = "Whether to open the firewall for the port in {option}`services.komga.port`.";
       };
     };
   };
 
-  config = mkIf cfg.enable {
-
-    networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
+  config =
+    let
+      inherit (lib) mkIf getExe;
+    in
+    mkIf cfg.enable {
 
-    users.groups = mkIf (cfg.group == "komga") {
-      komga = {};
-    };
+      networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
 
-    users.users = mkIf (cfg.user == "komga") {
-      komga = {
-        group = cfg.group;
-        home = cfg.stateDir;
-        description = "Komga Daemon user";
-        isSystemUser = true;
-      };
-    };
+      users.groups = mkIf (cfg.group == "komga") { komga = { }; };
 
-    systemd.services.komga = {
-      environment = {
-        SERVER_PORT = builtins.toString cfg.port;
-        KOMGA_CONFIGDIR = cfg.stateDir;
+      users.users = mkIf (cfg.user == "komga") {
+        komga = {
+          group = cfg.group;
+          home = cfg.stateDir;
+          description = "Komga Daemon user";
+          isSystemUser = true;
+        };
       };
 
-      description = "Komga is a free and open source comics/mangas media server";
-
-      wantedBy = [ "multi-user.target" ];
-      wants = [ "network-online.target" ];
-      after = [ "network-online.target" ];
-
-      serviceConfig = {
-        User = cfg.user;
-        Group = cfg.group;
-
-        Type = "simple";
-        Restart = "on-failure";
-        ExecStart = "${pkgs.komga}/bin/komga";
-
-        StateDirectory = mkIf (cfg.stateDir == "/var/lib/komga") "komga";
+      systemd.services.komga = {
+        environment = {
+          SERVER_PORT = builtins.toString cfg.port;
+          KOMGA_CONFIGDIR = cfg.stateDir;
+        };
+
+        description = "Komga is a free and open source comics/mangas media server";
+
+        wantedBy = [ "multi-user.target" ];
+        wants = [ "network-online.target" ];
+        after = [ "network-online.target" ];
+
+        serviceConfig = {
+          User = cfg.user;
+          Group = cfg.group;
+
+          Type = "simple";
+          Restart = "on-failure";
+          ExecStart = getExe pkgs.komga;
+
+          StateDirectory = mkIf (cfg.stateDir == "/var/lib/komga") "komga";
+
+          RemoveIPC = true;
+          NoNewPrivileges = true;
+          CapabilityBoundingSet = "";
+          SystemCallFilter = [ "@system-service" ];
+          ProtectSystem = "full";
+          PrivateTmp = true;
+          ProtectProc = "invisible";
+          ProtectClock = true;
+          ProcSubset = "pid";
+          PrivateUsers = true;
+          PrivateDevices = true;
+          ProtectHostname = true;
+          ProtectKernelTunables = true;
+          RestrictAddressFamilies = [
+            "AF_INET"
+            "AF_INET6"
+            "AF_NETLINK"
+          ];
+          LockPersonality = true;
+          RestrictNamespaces = true;
+          ProtectKernelLogs = true;
+          ProtectControlGroups = true;
+          ProtectKernelModules = true;
+          SystemCallArchitectures = "native";
+          RestrictSUIDSGID = true;
+          RestrictRealtime = true;
+        };
       };
-
     };
-  };
 
   meta.maintainers = with maintainers; [ govanify ];
 }
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index 5cda4a00a9de..7f998207c434 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -14,7 +14,6 @@ let
     expose_php = "Off";
     error_reporting = "E_ALL & ~E_DEPRECATED & ~E_STRICT";
     display_errors = "stderr";
-    "opcache.enable_cli" = "1";
     "opcache.interned_strings_buffer" = "8";
     "opcache.max_accelerated_files" = "10000";
     "opcache.memory_consumption" = "128";
diff --git a/nixos/modules/services/web-apps/pretix.nix b/nixos/modules/services/web-apps/pretix.nix
new file mode 100644
index 000000000000..500b2eb5416b
--- /dev/null
+++ b/nixos/modules/services/web-apps/pretix.nix
@@ -0,0 +1,580 @@
+{ config
+, lib
+, pkgs
+, utils
+, ...
+}:
+
+let
+  inherit (lib)
+    concatMapStringsSep
+    escapeShellArgs
+    filter
+    filterAttrs
+    getExe
+    getExe'
+    isAttrs
+    isList
+    literalExpression
+    mapAttrs
+    mkDefault
+    mkEnableOption
+    mkIf
+    mkOption
+    mkPackageOption
+    optionals
+    optionalString
+    recursiveUpdate
+    types
+  ;
+
+  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;
+
+  cfg = config.services.pretix;
+  format = pkgs.formats.ini { };
+
+  configFile = format.generate "pretix.cfg" (filterRecursiveNull cfg.settings);
+
+  finalPackage = cfg.package.override {
+    inherit (cfg) plugins;
+  };
+
+  pythonEnv = cfg.package.python.buildEnv.override {
+    extraLibs = with cfg.package.python.pkgs; [
+      (toPythonModule finalPackage)
+      gunicorn
+    ]
+    ++ lib.optionals (cfg.settings.memcached.location != null)
+      cfg.package.optional-dependencies.memcached
+    ;
+  };
+
+  withRedis = cfg.settings.redis.location != null;
+in
+{
+  meta = with lib; {
+    maintainers = with maintainers; [ hexa ];
+  };
+
+  options.services.pretix = {
+    enable = mkEnableOption "pretix";
+
+    package = mkPackageOption pkgs "pretix" { };
+
+    group = mkOption {
+      type = types.str;
+      default = "pretix";
+      description = ''
+        Group under which pretix should run.
+      '';
+    };
+
+    user = mkOption {
+      type = types.str;
+      default = "pretix";
+      description = ''
+        User under which pretix should run.
+      '';
+    };
+
+    environmentFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      example = "/run/keys/pretix-secrets.env";
+      description = ''
+        Environment file to pass secret configuration values.
+
+        Each line must follow the `PRETIX_SECTION_KEY=value` pattern.
+      '';
+    };
+
+    plugins = mkOption {
+      type = types.listOf types.package;
+      default = [];
+      example = literalExpression ''
+        with config.services.pretix.package.plugins; [
+          passbook
+          pages
+        ];
+      '';
+      description = ''
+        Pretix plugins to install into the Python environment.
+      '';
+    };
+
+    gunicorn.extraArgs = mkOption {
+      type = with types; listOf str;
+      default = [
+        "--name=pretix"
+      ];
+      example = [
+        "--name=pretix"
+        "--workers=4"
+        "--max-requests=1200"
+        "--max-requests-jitter=50"
+        "--log-level=info"
+      ];
+      description = ''
+        Extra arguments to pass to gunicorn.
+        See <https://docs.pretix.eu/en/latest/admin/installation/manual_smallscale.html#start-pretix-as-a-service> for details.
+      '';
+      apply = escapeShellArgs;
+    };
+
+    celery = {
+      extraArgs = mkOption {
+        type = with types; listOf str;
+        default = [ ];
+        description = ''
+          Extra arguments to pass to celery.
+
+          See <https://docs.celeryq.dev/en/stable/reference/cli.html#celery-worker> for more info.
+        '';
+        apply = utils.escapeSystemdExecArgs;
+      };
+    };
+
+    nginx = {
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        example = false;
+        description = ''
+          Whether to set up an nginx virtual host.
+        '';
+      };
+
+      domain = mkOption {
+        type = types.str;
+        example = "talks.example.com";
+        description = ''
+          The domain name under which to set up the virtual host.
+        '';
+      };
+    };
+
+    database.createLocally = mkOption {
+      type = types.bool;
+      default = true;
+      example = false;
+      description = ''
+        Whether to automatically set up the database on the local DBMS instance.
+
+        Only supported for PostgreSQL. Not required for sqlite.
+      '';
+    };
+
+    settings = mkOption {
+      type = types.submodule {
+        freeformType = format.type;
+        options = {
+          pretix = {
+            instance_name = mkOption {
+              type = types.str;
+              example = "tickets.example.com";
+              description = ''
+                The name of this installation.
+              '';
+            };
+
+            url = mkOption {
+              type = types.str;
+              example = "https://tickets.example.com";
+              description = ''
+                The installation’s full URL, without a trailing slash.
+              '';
+            };
+
+            cachedir = mkOption {
+              type = types.path;
+              default = "/var/cache/pretix";
+              description = ''
+                Directory for storing temporary files.
+              '';
+            };
+
+            datadir = mkOption {
+              type = types.path;
+              default = "/var/lib/pretix";
+              description = ''
+                Directory for storing user uploads and similar data.
+              '';
+            };
+
+            logdir = mkOption {
+              type = types.path;
+              default = "/var/log/pretix";
+              description = ''
+                Directory for storing log files.
+              '';
+            };
+
+            currency = mkOption {
+              type = types.str;
+              default = "EUR";
+              example = "USD";
+              description = ''
+                Default currency for events in its ISO 4217 three-letter code.
+              '';
+            };
+
+            registration = mkOption {
+              type = types.bool;
+              default = false;
+              example = true;
+              description = ''
+                Whether to allow registration of new admin users.
+              '';
+            };
+          };
+
+          database = {
+            backend = mkOption {
+              type = types.enum [
+                "sqlite3"
+                "postgresql"
+              ];
+              default = "postgresql";
+              description = ''
+                Database backend to use.
+
+                Only postgresql is recommended for production setups.
+              '';
+            };
+
+            host = mkOption {
+              type = with types; nullOr types.path;
+              default = if cfg.settings.database.backend == "postgresql" then "/run/postgresql" else null;
+              defaultText = literalExpression ''
+                if config.services.pretix.settings..database.backend == "postgresql" then "/run/postgresql"
+                else null
+              '';
+              description = ''
+                Database host or socket path.
+              '';
+            };
+
+            name = mkOption {
+              type = types.str;
+              default = "pretix";
+              description = ''
+                Database name.
+              '';
+            };
+
+            user = mkOption {
+              type = types.str;
+              default = "pretix";
+              description = ''
+                Database username.
+              '';
+            };
+          };
+
+          mail = {
+            from = mkOption {
+              type = types.str;
+              example = "tickets@example.com";
+              description = ''
+                E-Mail address used in the `FROM` header of outgoing mails.
+              '';
+            };
+
+            host = mkOption {
+              type = types.str;
+              default = "localhost";
+              example = "mail.example.com";
+              description = ''
+                Hostname of the SMTP server use for mail delivery.
+              '';
+            };
+
+            port = mkOption {
+              type = types.port;
+              default = 25;
+              example = 587;
+              description = ''
+                Port of the SMTP server to use for mail delivery.
+              '';
+            };
+          };
+
+          celery = {
+            backend = mkOption {
+              type = types.str;
+              default = "redis+socket://${config.services.redis.servers.pretix.unixSocket}?virtual_host=1";
+              defaultText = literalExpression ''
+                optionalString config.services.pretix.celery.enable "redis+socket://''${config.services.redis.servers.pretix.unixSocket}?virtual_host=1"
+              '';
+              description = ''
+                URI to the celery backend used for the asynchronous job queue.
+              '';
+            };
+
+            broker = mkOption {
+              type = types.str;
+              default = "redis+socket://${config.services.redis.servers.pretix.unixSocket}?virtual_host=2";
+              defaultText = literalExpression ''
+                optionalString config.services.pretix.celery.enable "redis+socket://''${config.services.redis.servers.pretix.unixSocket}?virtual_host=2"
+              '';
+              description = ''
+                URI to the celery broker used for the asynchronous job queue.
+              '';
+            };
+          };
+
+          redis = {
+            location = mkOption {
+              type = with types; nullOr str;
+              default = "unix://${config.services.redis.servers.pretix.unixSocket}?db=0";
+              defaultText = literalExpression ''
+                "unix://''${config.services.redis.servers.pretix.unixSocket}?db=0"
+              '';
+              description = ''
+                URI to the redis server, used to speed up locking, caching and session storage.
+              '';
+            };
+
+            sessions = mkOption {
+              type = types.bool;
+              default = true;
+              example = false;
+              description = ''
+                Whether to use redis as the session storage.
+              '';
+            };
+          };
+
+          memcached = {
+            location = mkOption {
+              type = with types; nullOr str;
+              default = null;
+              example = "127.0.0.1:11211";
+              description = ''
+                The `host:port` combination or the path to the UNIX socket of a memcached instance.
+
+                Can be used instead of Redis for caching.
+              '';
+            };
+          };
+
+          tools = {
+            pdftk = mkOption {
+              type = types.path;
+              default = getExe pkgs.pdftk;
+              defaultText = literalExpression ''
+                lib.getExe pkgs.pdftk
+              '';
+              description = ''
+                Path to the pdftk executable.
+              '';
+            };
+          };
+        };
+      };
+      default = { };
+      description = ''
+        pretix configuration as a Nix attribute set. All settings can also be passed
+        from the environment.
+
+        See <https://docs.pretix.eu/en/latest/admin/config.html> for possible options.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    # https://docs.pretix.eu/en/latest/admin/installation/index.html
+
+    environment.systemPackages = [
+      (pkgs.writeScriptBin "pretix-manage" ''
+        cd ${cfg.settings.pretix.datadir}
+        sudo=exec
+        if [[ "$USER" != ${cfg.user} ]]; then
+          sudo='exec /run/wrappers/bin/sudo -u ${cfg.user} ${optionalString withRedis "-g redis-pretix"} --preserve-env=PRETIX_CONFIG_FILE'
+        fi
+        export PRETIX_CONFIG_FILE=${configFile}
+        $sudo ${getExe' pythonEnv "pretix-manage"} "$@"
+      '')
+    ];
+
+    services = {
+      nginx = mkIf cfg.nginx.enable {
+        enable = true;
+        recommendedGzipSettings = mkDefault true;
+        recommendedOptimisation = mkDefault true;
+        recommendedProxySettings = mkDefault true;
+        recommendedTlsSettings = mkDefault true;
+        upstreams.pretix.servers."unix:/run/pretix/pretix.sock" = { };
+        virtualHosts.${cfg.nginx.domain} = {
+          # https://docs.pretix.eu/en/latest/admin/installation/manual_smallscale.html#ssl
+          extraConfig = ''
+            more_set_headers Referrer-Policy same-origin;
+            more_set_headers X-Content-Type-Options nosniff;
+          '';
+          locations = {
+            "/".proxyPass = "http://pretix";
+            "/media/" = {
+              alias = "${cfg.settings.pretix.datadir}/media/";
+              extraConfig = ''
+                access_log off;
+                expires 7d;
+              '';
+            };
+            "^~ /media/(cachedfiles|invoices)" = {
+              extraConfig = ''
+                deny all;
+                return 404;
+              '';
+            };
+            "/static/" = {
+              alias = "${finalPackage}/${cfg.package.python.sitePackages}/pretix/static.dist/";
+              extraConfig = ''
+                access_log off;
+                more_set_headers Cache-Control "public";
+                expires 365d;
+              '';
+            };
+          };
+        };
+      };
+
+      postgresql = mkIf (cfg.database.createLocally && cfg.settings.database.backend == "postgresql") {
+        enable = true;
+        ensureUsers = [ {
+          name = cfg.settings.database.user;
+          ensureDBOwnership = true;
+        } ];
+        ensureDatabases = [ cfg.settings.database.name ];
+      };
+
+      redis.servers.pretix.enable = withRedis;
+    };
+
+    systemd.services = let
+      commonUnitConfig = {
+        environment.PRETIX_CONFIG_FILE = configFile;
+        serviceConfig = {
+          User = "pretix";
+          Group = "pretix";
+          EnvironmentFile = optionals (cfg.environmentFile != null) [
+            cfg.environmentFile
+          ];
+          StateDirectory = [
+            "pretix"
+          ];
+          StateDirectoryMode = "0755";
+          CacheDirectory = "pretix";
+          LogsDirectory = "pretix";
+          WorkingDirectory = cfg.settings.pretix.datadir;
+          SupplementaryGroups = optionals withRedis [
+            "redis-pretix"
+          ];
+          AmbientCapabilities = "";
+          CapabilityBoundingSet = [ "" ];
+          DevicePolicy = "closed";
+          LockPersonality = true;
+          MemoryDenyWriteExecute = true;
+          NoNewPrivileges = true;
+          PrivateDevices = true;
+          PrivateTmp = true;
+          ProcSubset = "pid";
+          ProtectControlGroups = true;
+          ProtectHome = true;
+          ProtectHostname = true;
+          ProtectKernelLogs = true;
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          ProtectProc = "invisible";
+          ProtectSystem = "strict";
+          RemoveIPC = true;
+          RestrictAddressFamilies = [
+            "AF_INET"
+            "AF_INET6"
+            "AF_UNIX"
+          ];
+          RestrictNamespaces = true;
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+          SystemCallArchitectures = "native";
+          SystemCallFilter = [
+            "@system-service"
+            "~@privileged"
+            "@chown"
+          ];
+          UMask = "0022";
+        };
+      };
+    in {
+      pretix-web = recursiveUpdate commonUnitConfig {
+        description = "pretix web service";
+        after = [
+          "network.target"
+          "redis-pretix.service"
+          "postgresql.service"
+        ];
+        wantedBy = [ "multi-user.target" ];
+        preStart = ''
+          versionFile="${cfg.settings.pretix.datadir}/.version"
+          version=$(cat "$versionFile" 2>/dev/null || echo 0)
+
+          pluginsFile="${cfg.settings.pretix.datadir}/.plugins"
+          plugins=$(cat "$pluginsFile" 2>/dev/null || echo "")
+          configuredPlugins="${concatMapStringsSep "|" (package: package.name) cfg.plugins}"
+
+          if [[ $version != ${cfg.package.version} || $plugins != $configuredPlugins ]]; then
+            ${getExe' pythonEnv "pretix-manage"} migrate
+
+            echo "${cfg.package.version}" > "$versionFile"
+            echo "$configuredPlugins" > "$pluginsFile"
+          fi
+        '';
+        serviceConfig = {
+          ExecStart = "${getExe' pythonEnv "gunicorn"} --bind unix:/run/pretix/pretix.sock ${cfg.gunicorn.extraArgs} pretix.wsgi";
+          RuntimeDirectory = "pretix";
+        };
+      };
+
+      pretix-periodic = recursiveUpdate commonUnitConfig {
+        description = "pretix periodic task runner";
+        # every 15 minutes
+        startAt = [ "*:3,18,33,48" ];
+        serviceConfig = {
+          Type = "oneshot";
+          ExecStart = "${getExe' pythonEnv "pretix-manage"} runperiodic";
+        };
+      };
+
+      pretix-worker = recursiveUpdate commonUnitConfig {
+        description = "pretix asynchronous job runner";
+        after = [
+          "network.target"
+          "redis-pretix.service"
+          "postgresql.service"
+        ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig.ExecStart = "${getExe' pythonEnv "celery"} -A pretix.celery_app worker ${cfg.celery.extraArgs}";
+      };
+    };
+
+    systemd.sockets.pretix-web.socketConfig = {
+      ListenStream = "/run/pretix/pretix.sock";
+      SocketUser = "nginx";
+    };
+
+    users = {
+      groups."${cfg.group}" = {};
+      users."${cfg.user}" = {
+        isSystemUser = true;
+        createHome = true;
+        home = cfg.settings.pretix.datadir;
+        inherit (cfg) group;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/web-servers/stargazer.nix b/nixos/modules/services/web-servers/stargazer.nix
index 18f57363137c..4eca33326040 100644
--- a/nixos/modules/services/web-servers/stargazer.nix
+++ b/nixos/modules/services/web-servers/stargazer.nix
@@ -129,6 +129,12 @@ in
       example = lib.literalExpression "\"1y\"";
     };
 
+    debugMode = lib.mkOption {
+      type = lib.types.bool;
+      default = false;
+      description = lib.mdDoc "Run Stargazer in debug mode.";
+    };
+
     routes = lib.mkOption {
       type = lib.types.listOf
         (lib.types.submodule {
@@ -195,7 +201,7 @@ in
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       serviceConfig = {
-        ExecStart = "${pkgs.stargazer}/bin/stargazer ${configFile}";
+        ExecStart = "${pkgs.stargazer}/bin/stargazer ${configFile} ${lib.optionalString cfg.debugMode "-D"}";
         Restart = "always";
         # User and group
         User = cfg.user;
diff --git a/nixos/modules/services/x11/desktop-managers/budgie.nix b/nixos/modules/services/x11/desktop-managers/budgie.nix
index fe39097a22e8..7d8bb1963d78 100644
--- a/nixos/modules/services/x11/desktop-managers/budgie.nix
+++ b/nixos/modules/services/x11/desktop-managers/budgie.nix
@@ -159,7 +159,7 @@ in {
       ++ cfg.sessionPath;
 
     # Fonts.
-    fonts.packages = mkDefault [
+    fonts.packages = [
       pkgs.noto-fonts
       pkgs.hack-font
     ];
diff --git a/nixos/modules/services/x11/desktop-managers/deepin.nix b/nixos/modules/services/x11/desktop-managers/deepin.nix
index 0824d6e30a8a..902e3a9317dd 100644
--- a/nixos/modules/services/x11/desktop-managers/deepin.nix
+++ b/nixos/modules/services/x11/desktop-managers/deepin.nix
@@ -66,6 +66,7 @@ in
       services.upower.enable = mkDefault config.powerManagement.enable;
       networking.networkmanager.enable = mkDefault true;
       programs.dconf.enable = mkDefault true;
+      programs.gnupg.agent.pinentryPackage = mkDefault pkgs.pinentry-qt;
 
       fonts.packages = with pkgs; [ noto-fonts ];
       xdg.mime.enable = true;
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index ecb8d1e91bde..33d0a7b52643 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -18,7 +18,7 @@ in
   # determines the default: later modules (if enabled) are preferred.
   # E.g., if Plasma 5 is enabled, it supersedes xterm.
   imports = [
-    ./none.nix ./xterm.nix ./phosh.nix ./xfce.nix ./plasma5.nix ./plasma6.nix ./lumina.nix
+    ./none.nix ./xterm.nix ./phosh.nix ./xfce.nix ./plasma5.nix ../../desktop-managers/plasma6.nix ./lumina.nix
     ./lxqt.nix ./enlightenment.nix ./gnome.nix ./retroarch.nix ./kodi.nix
     ./mate.nix ./pantheon.nix ./surf-display.nix ./cde.nix
     ./cinnamon.nix ./budgie.nix ./deepin.nix
diff --git a/nixos/modules/services/x11/desktop-managers/lxqt.nix b/nixos/modules/services/x11/desktop-managers/lxqt.nix
index 50ad72dc7388..3d02deba6fc7 100644
--- a/nixos/modules/services/x11/desktop-managers/lxqt.nix
+++ b/nixos/modules/services/x11/desktop-managers/lxqt.nix
@@ -62,6 +62,8 @@ in
     # Link some extra directories in /run/current-system/software/share
     environment.pathsToLink = [ "/share" ];
 
+    programs.gnupg.agent.pinentryPackage = mkDefault pkgs.pinentry-qt;
+
     # virtual file systems support for PCManFM-QT
     services.gvfs.enable = true;
 
diff --git a/nixos/modules/services/x11/desktop-managers/mate.nix b/nixos/modules/services/x11/desktop-managers/mate.nix
index f535a1d298b9..957eac7848e7 100644
--- a/nixos/modules/services/x11/desktop-managers/mate.nix
+++ b/nixos/modules/services/x11/desktop-managers/mate.nix
@@ -20,6 +20,22 @@ in
       };
 
       debug = mkEnableOption (lib.mdDoc "mate-session debug messages");
+
+      extraPanelApplets = mkOption {
+        default = [ ];
+        example = literalExpression "with pkgs.mate; [ mate-applets ]";
+        type = types.listOf types.package;
+        description = lib.mdDoc "Extra applets to add to mate-panel.";
+      };
+
+      extraCajaExtensions = mkOption {
+        default = [ ];
+        example = lib.literalExpression "with pkgs.mate; [ caja-extensions ]";
+        type = types.listOf types.package;
+        description = lib.mdDoc "Extra extensions to add to caja.";
+      };
+
+      enableWaylandSession = mkEnableOption (lib.mdDoc "MATE Wayland session");
     };
 
     environment.mate.excludePackages = mkOption {
@@ -31,55 +47,63 @@ in
 
   };
 
-  config = mkIf cfg.enable {
-
-    services.xserver.displayManager.sessionPackages = [
-      pkgs.mate.mate-session-manager
-    ];
-
-    # Let caja find extensions
-    environment.sessionVariables.CAJA_EXTENSION_DIRS = [ "${config.system.path}/lib/caja/extensions-2.0" ];
-
-    # Let mate-panel find applets
-    environment.sessionVariables."MATE_PANEL_APPLETS_DIR" = "${config.system.path}/share/mate-panel/applets";
-    environment.sessionVariables."MATE_PANEL_EXTRA_MODULES" = "${config.system.path}/lib/mate-panel/applets";
-
-    # Debugging
-    environment.sessionVariables.MATE_SESSION_DEBUG = mkIf cfg.debug "1";
-
-    environment.systemPackages = utils.removePackagesByName
-      (pkgs.mate.basePackages ++
-      pkgs.mate.extraPackages ++
-      [
-        pkgs.desktop-file-utils
-        pkgs.glib
-        pkgs.gtk3.out
-        pkgs.shared-mime-info
-        pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
-        pkgs.yelp # for 'Contents' in 'Help' menus
-      ])
-      config.environment.mate.excludePackages;
-
-    programs.dconf.enable = true;
-    # Shell integration for VTE terminals
-    programs.bash.vteIntegration = mkDefault true;
-    programs.zsh.vteIntegration = mkDefault true;
-
-    # Mate uses this for printing
-    programs.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
-
-    services.gnome.at-spi2-core.enable = true;
-    services.gnome.gnome-keyring.enable = true;
-    services.udev.packages = [ pkgs.mate.mate-settings-daemon ];
-    services.gvfs.enable = true;
-    services.upower.enable = config.powerManagement.enable;
-    services.xserver.libinput.enable = mkDefault true;
-
-    security.pam.services.mate-screensaver.unixAuth = true;
-
-    xdg.portal.configPackages = mkDefault [ pkgs.mate.mate-desktop ];
-
-    environment.pathsToLink = [ "/share" ];
-  };
-
+  config = mkMerge [
+    (mkIf (cfg.enable || cfg.enableWaylandSession) {
+      services.xserver.displayManager.sessionPackages = [
+        pkgs.mate.mate-session-manager
+      ];
+
+      # Debugging
+      environment.sessionVariables.MATE_SESSION_DEBUG = mkIf cfg.debug "1";
+
+      environment.systemPackages = utils.removePackagesByName
+        (pkgs.mate.basePackages ++
+        pkgs.mate.extraPackages ++
+        [
+          (pkgs.mate.caja-with-extensions.override {
+            extensions = cfg.extraCajaExtensions;
+          })
+          (pkgs.mate.mate-panel-with-applets.override {
+            applets = cfg.extraPanelApplets;
+          })
+          pkgs.desktop-file-utils
+          pkgs.glib
+          pkgs.gtk3.out
+          pkgs.shared-mime-info
+          pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
+          pkgs.yelp # for 'Contents' in 'Help' menus
+        ])
+        config.environment.mate.excludePackages;
+
+      programs.dconf.enable = true;
+      # Shell integration for VTE terminals
+      programs.bash.vteIntegration = mkDefault true;
+      programs.zsh.vteIntegration = mkDefault true;
+
+      # Mate uses this for printing
+      programs.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
+
+      services.gnome.at-spi2-core.enable = true;
+      services.gnome.gnome-keyring.enable = true;
+      services.udev.packages = [ pkgs.mate.mate-settings-daemon ];
+      services.gvfs.enable = true;
+      services.upower.enable = config.powerManagement.enable;
+      services.xserver.libinput.enable = mkDefault true;
+
+      security.pam.services.mate-screensaver.unixAuth = true;
+
+      xdg.portal.configPackages = mkDefault [ pkgs.mate.mate-desktop ];
+
+      environment.pathsToLink = [ "/share" ];
+    })
+    (mkIf cfg.enableWaylandSession {
+      programs.wayfire.enable = true;
+      programs.wayfire.plugins = [ pkgs.wayfirePlugins.firedecor ];
+
+      environment.sessionVariables.NIX_GSETTINGS_OVERRIDES_DIR = "${pkgs.mate.mate-gsettings-overrides}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
+
+      environment.systemPackages = [ pkgs.mate.mate-wayland-session ];
+      services.xserver.displayManager.sessionPackages = [ pkgs.mate.mate-wayland-session ];
+    })
+  ];
 }
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index 7645b3070369..f516a29fb5db 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -336,6 +336,7 @@ in
         serif = [ "Noto Serif" ];
       };
 
+      programs.gnupg.agent.pinentryPackage = mkDefault pkgs.pinentry-qt;
       programs.ssh.askPassword = mkDefault "${pkgs.plasma5Packages.ksshaskpass.out}/bin/ksshaskpass";
 
       # Enable helpful DBus services.
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index e28486bcc12d..3ba27b201507 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -131,6 +131,7 @@ in
         xfdesktop
       ] ++ optional cfg.enableScreensaver xfce4-screensaver) excludePackages;
 
+    programs.gnupg.agent.pinentryPackage = mkDefault pkgs.pinentry-gtk2;
     programs.xfconf.enable = true;
     programs.thunar.enable = true;
 
diff --git a/nixos/modules/services/x11/window-managers/xmonad.nix b/nixos/modules/services/x11/window-managers/xmonad.nix
index c35446bf405b..2962f2851fa9 100644
--- a/nixos/modules/services/x11/window-managers/xmonad.nix
+++ b/nixos/modules/services/x11/window-managers/xmonad.nix
@@ -37,7 +37,7 @@ let
 
   xmonad = if (cfg.config != null) then xmonad-config else xmonad-vanilla;
 in {
-  meta.maintainers = with maintainers; [ lassulus xaverdh ivanbrennan ];
+  meta.maintainers = with maintainers; [ lassulus xaverdh ivanbrennan slotThe ];
 
   options = {
     services.xserver.windowManager.xmonad = {
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index 38fb1074fcdf..3d7474e18263 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -749,6 +749,8 @@ in
     boot.kernel.sysctl."fs.inotify.max_user_instances" = mkDefault 524288;
     boot.kernel.sysctl."fs.inotify.max_user_watches" = mkDefault 524288;
 
+    programs.gnupg.agent.pinentryPackage = lib.mkDefault pkgs.pinentry-gnome3;
+
     systemd.defaultUnit = mkIf cfg.autorun "graphical.target";
 
     systemd.services.display-manager =
diff --git a/nixos/modules/system/boot/binfmt.nix b/nixos/modules/system/boot/binfmt.nix
index 08e3dce70844..2242c9da62d0 100644
--- a/nixos/modules/system/boot/binfmt.nix
+++ b/nixos/modules/system/boot/binfmt.nix
@@ -331,6 +331,7 @@ in {
           "proc-sys-fs-binfmt_misc.mount"
           "systemd-binfmt.service"
         ];
+        services.systemd-binfmt.after = [ "systemd-tmpfiles-setup.service" ];
         services.systemd-binfmt.restartTriggers = [ (builtins.toJSON config.boot.binfmt.registrations) ];
       })
     ];
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index 88d6a2ded873..9b0d750d12ce 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -729,8 +729,8 @@ let
         (assertInt "FirewallMark")
         (assertRange "FirewallMark" 1 4294967295)
         (assertInt "Priority")
-        (assertPort "SourcePort")
-        (assertPort "DestinationPort")
+        (assertPortOrPortRange "SourcePort")
+        (assertPortOrPortRange "DestinationPort")
         (assertValueOneOf "InvertRule" boolValues)
         (assertValueOneOf "Family" ["ipv4" "ipv6" "both"])
         (assertInt "SuppressPrefixLength")
@@ -797,6 +797,7 @@ let
           "UseHostname"
           "Hostname"
           "UseDomains"
+          "UseGateway"
           "UseRoutes"
           "UseTimezone"
           "ClientIdentifier"
@@ -829,6 +830,7 @@ let
         (assertValueOneOf "SendHostname" boolValues)
         (assertValueOneOf "UseHostname" boolValues)
         (assertValueOneOf "UseDomains" (boolValues ++ ["route"]))
+        (assertValueOneOf "UseGateway" boolValues)
         (assertValueOneOf "UseRoutes" boolValues)
         (assertValueOneOf "UseTimezone" boolValues)
         (assertValueOneOf "ClientIdentifier" ["mac" "duid" "duid-only"])
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 90a74c0ac578..6462e4fd51fc 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -688,7 +688,7 @@ in
 
   config = mkIf config.boot.initrd.enable {
     assertions = [
-      { assertion = any (fs: fs.mountPoint == "/") fileSystems;
+      { assertion = !config.boot.initrd.systemd.enable -> any (fs: fs.mountPoint == "/") fileSystems;
         message = "The ‘fileSystems’ option does not specify your root file system.";
       }
       { assertion = let inherit (config.boot) resumeDevice; in
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 49090423e078..a8885aee78f2 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -97,7 +97,7 @@ let
 
       # Maintaining state across reboots.
       "systemd-random-seed.service"
-      "systemd-boot-random-seed.service"
+      ] ++ (optional cfg.package.withBootloader "systemd-boot-random-seed.service") ++ [
       "systemd-backlight@.service"
       "systemd-rfkill.service"
       "systemd-rfkill.socket"
diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix
index f83837fbc6d4..7a4648b45612 100644
--- a/nixos/modules/system/boot/systemd/initrd.nix
+++ b/nixos/modules/system/boot/systemd/initrd.nix
@@ -212,6 +212,19 @@ in {
       default = [];
     };
 
+    root = lib.mkOption {
+      type = lib.types.enum [ "fstab" "gpt-auto" ];
+      default = "fstab";
+      example = "gpt-auto";
+      description = ''
+        Controls how systemd will interpret the root FS in initrd. See
+        {manpage}`kernel-command-line(7)`. NixOS currently does not
+        allow specifying the root file system itself this
+        way. Instead, the `fstab` value is used in order to interpret
+        the root file system specified with the `fileSystems` option.
+      '';
+    };
+
     emergencyAccess = mkOption {
       type = with types; oneOf [ bool (nullOr (passwdEntry str)) ];
       description = lib.mdDoc ''
@@ -342,7 +355,12 @@ in {
   };
 
   config = mkIf (config.boot.initrd.enable && cfg.enable) {
-    assertions = map (name: {
+    assertions = [
+      {
+        assertion = cfg.root == "fstab" -> any (fs: fs.mountPoint == "/") (builtins.attrValues config.fileSystems);
+        message = "The ‘fileSystems’ option does not specify your root file system.";
+      }
+    ] ++ map (name: {
       assertion = lib.attrByPath name (throw "impossible") config.boot.initrd == "";
       message = ''
         systemd stage 1 does not support 'boot.initrd.${lib.concatStringsSep "." name}'. Please
@@ -371,7 +389,12 @@ in {
       "autofs"
       # systemd-cryptenroll
     ] ++ lib.optional cfg.enableTpm2 "tpm-tis"
-    ++ lib.optional (cfg.enableTpm2 && !(pkgs.stdenv.hostPlatform.isRiscV64 || pkgs.stdenv.hostPlatform.isArmv7)) "tpm-crb";
+    ++ lib.optional (cfg.enableTpm2 && !(pkgs.stdenv.hostPlatform.isRiscV64 || pkgs.stdenv.hostPlatform.isArmv7)) "tpm-crb"
+    ++ lib.optional cfg.package.withEfi "efivarfs";
+
+    boot.kernelParams = [
+      "root=${config.boot.initrd.systemd.root}"
+    ] ++ lib.optional (config.boot.resumeDevice != "") "resume=${config.boot.resumeDevice}";
 
     boot.initrd.systemd = {
       initrdBin = [pkgs.bash pkgs.coreutils cfg.package.kmod cfg.package];
@@ -495,7 +518,7 @@ in {
               case $o in
                   init=*)
                       IFS== read -r -a initParam <<< "$o"
-                      closure="$(dirname "''${initParam[1]}")"
+                      closure="''${initParam[1]}"
                       ;;
               esac
           done
@@ -506,6 +529,13 @@ in {
             exit 1
           fi
 
+          # Resolve symlinks in the init parameter. We need this for some boot loaders
+          # (e.g. boot.loader.generationsDir).
+          closure="$(chroot /sysroot ${pkgs.coreutils}/bin/realpath "$closure")"
+
+          # Assume the directory containing the init script is the closure.
+          closure="$(dirname "$closure")"
+
           # If we are not booting a NixOS closure (e.g. init=/bin/sh),
           # we don't know what root to prepare so we don't do anything
           if ! [ -x "/sysroot$(readlink "/sysroot$closure/prepare-root" || echo "$closure/prepare-root")" ]; then
@@ -554,7 +584,5 @@ in {
         serviceConfig.Type = "oneshot";
       };
     };
-
-    boot.kernelParams = lib.mkIf (config.boot.resumeDevice != "") [ "resume=${config.boot.resumeDevice}" ];
   };
 }
diff --git a/nixos/modules/system/boot/timesyncd.nix b/nixos/modules/system/boot/timesyncd.nix
index 2666e4cd6b28..ef17c1481abb 100644
--- a/nixos/modules/system/boot/timesyncd.nix
+++ b/nixos/modules/system/boot/timesyncd.nix
@@ -21,6 +21,9 @@ with lib;
         type = types.listOf types.str;
         description = lib.mdDoc ''
           The set of NTP servers from which to synchronise.
+          Note if this is set to an empty list, the defaults systemd itself is
+          compiled with ({0..4}.nixos.pool.ntp.org) apply,
+          In case you want to disable timesyncd altogether, use the `enable` option.
         '';
       };
       extraConfig = mkOption {
diff --git a/nixos/modules/system/boot/uki.nix b/nixos/modules/system/boot/uki.nix
index ce00ac8e6397..0965b887c12e 100644
--- a/nixos/modules/system/boot/uki.nix
+++ b/nixos/modules/system/boot/uki.nix
@@ -75,6 +75,8 @@ in
         OSRelease = lib.mkOptionDefault "@${config.system.build.etc}/etc/os-release";
         # This is needed for cross compiling.
         EFIArch = lib.mkOptionDefault efiArch;
+      } // lib.optionalAttrs (config.hardware.deviceTree.enable && config.hardware.deviceTree.name != null) {
+        DeviceTree = lib.mkOptionDefault "${config.hardware.deviceTree.package}/${config.hardware.deviceTree.name}";
       };
     };
 
diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix
index 6aa718c1975d..50a54a006415 100644
--- a/nixos/modules/testing/test-instrumentation.nix
+++ b/nixos/modules/testing/test-instrumentation.nix
@@ -42,8 +42,10 @@ let
         # Otherwise we get errors on the terminal because bash tries to
         # setup things like job control.
         # Note: calling bash explicitly here instead of sh makes sure that
-        # we can also run non-NixOS guests during tests.
-        PS1= exec /usr/bin/env bash --norc /dev/hvc0
+        # we can also run non-NixOS guests during tests. This, however, is
+        # mostly futureproofing as the test instrumentation is still very
+        # tightly coupled to NixOS.
+        PS1= exec ${pkgs.coreutils}/bin/env bash --norc /dev/hvc0
       '';
       serviceConfig.KillSignal = "SIGHUP";
   };
@@ -121,7 +123,9 @@ in
           }
         ];
 
-        contents."/usr/bin/env".source = "${pkgs.coreutils}/bin/env";
+        storePaths = [
+          "${pkgs.coreutils}/bin/env"
+        ];
       })
     ];
 
diff --git a/nixos/modules/virtualisation/amazon-ec2-amis.nix b/nixos/modules/virtualisation/amazon-ec2-amis.nix
index ff88f02e5d33..97636f4dcb2a 100644
--- a/nixos/modules/virtualisation/amazon-ec2-amis.nix
+++ b/nixos/modules/virtualisation/amazon-ec2-amis.nix
@@ -1,3 +1,6 @@
+# NOTE: this file will stop being updated.
+# please use https://nixos.github.io/amis/  and https://nixos.github.io/amis/images.json
+# instead.
 let self = {
   "14.04".ap-northeast-1.x86_64-linux.hvm-ebs = "ami-71c6f470";
   "14.04".ap-northeast-1.x86_64-linux.pv-ebs = "ami-4dcbf84c";
@@ -584,5 +587,68 @@ let self = {
   "23.05".us-west-1.aarch64-linux.hvm-ebs = "ami-0e75c8f3deb1f842b";
   "23.05".us-west-2.aarch64-linux.hvm-ebs = "ami-0d0979d889078d036";
 
-  latest = self."23.05";
+
+  # 23.11.4976.79baff8812a0
+
+  "23.11".eu-north-1.x86_64-linux.hvm-ebs = "ami-00e64007071666b9e";
+  "23.11".ap-south-2.x86_64-linux.hvm-ebs = "ami-0bbb8e5663f912455";
+  "23.11".ap-south-1.x86_64-linux.hvm-ebs = "ami-057ec482a7bc9cb87";
+  "23.11".eu-south-1.x86_64-linux.hvm-ebs = "ami-083f9740e86ab36b9";
+  "23.11".eu-south-2.x86_64-linux.hvm-ebs = "ami-0686a9ef630e6eeef";
+  "23.11".me-central-1.x86_64-linux.hvm-ebs = "ami-0475d5925ff0390f8";
+  "23.11".il-central-1.x86_64-linux.hvm-ebs = "ami-0997e21a353de1226";
+  "23.11".ca-central-1.x86_64-linux.hvm-ebs = "ami-0f9fc310496ea54ec";
+  "23.11".eu-central-1.x86_64-linux.hvm-ebs = "ami-0923e79b6f9b198fa";
+  "23.11".eu-central-2.x86_64-linux.hvm-ebs = "ami-0b02e6421cde609ff";
+  "23.11".us-west-1.x86_64-linux.hvm-ebs = "ami-0e94c086e49480566";
+  "23.11".us-west-2.x86_64-linux.hvm-ebs = "ami-0a2f8942a90eb233a";
+  "23.11".af-south-1.x86_64-linux.hvm-ebs = "ami-0c9ff564e4a503c56";
+  "23.11".eu-west-3.x86_64-linux.hvm-ebs = "ami-0955d4d89c446d5ff";
+  "23.11".eu-west-2.x86_64-linux.hvm-ebs = "ami-0c5834d32e6dce6c8";
+  "23.11".eu-west-1.x86_64-linux.hvm-ebs = "ami-0e7d1823ac80520e6";
+  "23.11".ap-northeast-3.x86_64-linux.hvm-ebs = "ami-06b3692ef87ef308a";
+  "23.11".ap-northeast-2.x86_64-linux.hvm-ebs = "ami-0fb1e23007bdc6083";
+  "23.11".me-south-1.x86_64-linux.hvm-ebs = "ami-0a4beeb2fc744c149";
+  "23.11".ap-northeast-1.x86_64-linux.hvm-ebs = "ami-0f60ab2288ac784c3";
+  "23.11".sa-east-1.x86_64-linux.hvm-ebs = "ami-058779e1d5c1cc6ae";
+  "23.11".ap-east-1.x86_64-linux.hvm-ebs = "ami-039879f1b367e167f";
+  "23.11".ca-west-1.x86_64-linux.hvm-ebs = "ami-07dc9bc5645a981f1";
+  "23.11".ap-southeast-1.x86_64-linux.hvm-ebs = "ami-0ee92af1fc4c4e5f3";
+  "23.11".ap-southeast-2.x86_64-linux.hvm-ebs = "ami-0814092ef52275887";
+  "23.11".ap-southeast-3.x86_64-linux.hvm-ebs = "ami-0d20b4b6529b6214c";
+  "23.11".ap-southeast-4.x86_64-linux.hvm-ebs = "ami-0aa7b8aa04e5ec741";
+  "23.11".us-east-1.x86_64-linux.hvm-ebs = "ami-0c2e37dc938ed9405";
+  "23.11".us-east-2.x86_64-linux.hvm-ebs = "ami-05c218c4a08c58296";
+
+  "23.11".eu-north-1.aarch64-linux.hvm-ebs = "ami-05e68ac90786e5ac0";
+  "23.11".ap-south-2.aarch64-linux.hvm-ebs = "ami-0a53356d3176a82af";
+  "23.11".ap-south-1.aarch64-linux.hvm-ebs = "ami-0cc335be202b53954";
+  "23.11".eu-south-1.aarch64-linux.hvm-ebs = "ami-05d387849385390c0";
+  "23.11".eu-south-2.aarch64-linux.hvm-ebs = "ami-0193deb9aa4b398bb";
+  "23.11".me-central-1.aarch64-linux.hvm-ebs = "ami-05bd96550451e131d";
+  "23.11".il-central-1.aarch64-linux.hvm-ebs = "ami-0264204c502a16f49";
+  "23.11".ca-central-1.aarch64-linux.hvm-ebs = "ami-08345537f80791b3c";
+  "23.11".eu-central-1.aarch64-linux.hvm-ebs = "ami-03b257130b2b01000";
+  "23.11".eu-central-2.aarch64-linux.hvm-ebs = "ami-0b4412d8a4d3fb7ae";
+  "23.11".us-west-1.aarch64-linux.hvm-ebs = "ami-0a2d70cd7a3b03e24";
+  "23.11".us-west-2.aarch64-linux.hvm-ebs = "ami-01b8e062c74311de0";
+  "23.11".af-south-1.aarch64-linux.hvm-ebs = "ami-011c296fee301596b";
+  "23.11".eu-west-3.aarch64-linux.hvm-ebs = "ami-024531ee8546d7ec7";
+  "23.11".eu-west-2.aarch64-linux.hvm-ebs = "ami-0a5dda5cf7e00b39b";
+  "23.11".eu-west-1.aarch64-linux.hvm-ebs = "ami-013f7a51b602dec7d";
+  "23.11".ap-northeast-3.aarch64-linux.hvm-ebs = "ami-0220fc0e06979c6ff";
+  "23.11".ap-northeast-2.aarch64-linux.hvm-ebs = "ami-0978048539bbad573";
+  "23.11".me-south-1.aarch64-linux.hvm-ebs = "ami-02057e1a9c901b506";
+  "23.11".ap-northeast-1.aarch64-linux.hvm-ebs = "ami-05616e07e227f9982";
+  "23.11".sa-east-1.aarch64-linux.hvm-ebs = "ami-0bf5255283cec803b";
+  "23.11".ap-east-1.aarch64-linux.hvm-ebs = "ami-00432470e52956e49";
+  "23.11".ca-west-1.aarch64-linux.hvm-ebs = "ami-0675649785473e1ac";
+  "23.11".ap-southeast-1.aarch64-linux.hvm-ebs = "ami-006494f0fa381ba53";
+  "23.11".ap-southeast-2.aarch64-linux.hvm-ebs = "ami-0d8c15d68266d6881";
+  "23.11".ap-southeast-3.aarch64-linux.hvm-ebs = "ami-0db38da4ed78d2a10";
+  "23.11".ap-southeast-4.aarch64-linux.hvm-ebs = "ami-098b3b942486b5e71";
+  "23.11".us-east-1.aarch64-linux.hvm-ebs = "ami-02d1d66bda50b9036";
+  "23.11".us-east-2.aarch64-linux.hvm-ebs = "ami-0aa62457617706386";
+
+  latest = self."23.11";
 }; in self
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index c7fe1bed5159..77730178422c 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -79,6 +79,10 @@ in
       serviceConfig.StandardOutput = "journal+console";
     };
 
+    # Amazon-issued AMIs include the SSM Agent by default, so we do the same.
+    # https://docs.aws.amazon.com/systems-manager/latest/userguide/ami-preinstalled-agent.html
+    services.amazon-ssm-agent.enable = true;
+
     # Allow root logins only using the SSH key that the user specified
     # at instance creation time.
     services.openssh.enable = true;
diff --git a/nixos/modules/virtualisation/incus.nix b/nixos/modules/virtualisation/incus.nix
index a561c5682ae5..da7873c7bec8 100644
--- a/nixos/modules/virtualisation/incus.nix
+++ b/nixos/modules/virtualisation/incus.nix
@@ -164,19 +164,24 @@ in
         "network-online.target"
         "lxcfs.service"
         "incus.socket"
-      ];
+      ]
+        ++ lib.optional config.virtualisation.vswitch.enable "ovs-vswitchd.service";
+
       requires = [
         "lxcfs.service"
         "incus.socket"
-      ];
+      ]
+        ++ lib.optional config.virtualisation.vswitch.enable "ovs-vswitchd.service";
+
       wants = [
         "network-online.target"
       ];
 
-      path = lib.mkIf config.boot.zfs.enabled [
+      path = lib.optionals config.boot.zfs.enabled [
         config.boot.zfs.package
         "${config.boot.zfs.package}/lib/udev"
-      ];
+      ]
+        ++ lib.optional config.virtualisation.vswitch.enable config.virtualisation.vswitch.package;
 
       environment = lib.mkMerge [ {
         # Override Path to the LXC template configuration directory
diff --git a/nixos/modules/virtualisation/oci-containers.nix b/nixos/modules/virtualisation/oci-containers.nix
index a88715587d65..5bffb3f04716 100644
--- a/nixos/modules/virtualisation/oci-containers.nix
+++ b/nixos/modules/virtualisation/oci-containers.nix
@@ -312,7 +312,7 @@ let
 
     preStop = if cfg.backend == "podman"
       then "podman stop --ignore --cidfile=/run/podman-${escapedName}.ctr-id"
-      else "${cfg.backend} stop ${name}";
+      else "${cfg.backend} stop ${name} || true";
 
     postStop = if cfg.backend == "podman"
       then "podman rm -f --ignore --cidfile=/run/podman-${escapedName}.ctr-id"
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 7376cd40b910..dd6c744a79ce 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -464,7 +464,7 @@ in {
   keymap = handleTest ./keymap.nix {};
   knot = handleTest ./knot.nix {};
   komga = handleTest ./komga.nix {};
-  krb5 = discoverTests (import ./krb5 {});
+  krb5 = discoverTests (import ./krb5);
   ksm = handleTest ./ksm.nix {};
   kthxbye = handleTest ./kthxbye.nix {};
   kubernetes = handleTestOn ["x86_64-linux"] ./kubernetes {};
@@ -513,6 +513,7 @@ in {
   mastodon = discoverTests (import ./web-apps/mastodon { inherit handleTestOn; });
   pixelfed = discoverTests (import ./web-apps/pixelfed { inherit handleTestOn; });
   mate = handleTest ./mate.nix {};
+  mate-wayland = handleTest ./mate-wayland.nix {};
   matter-server = handleTest ./matter-server.nix {};
   matomo = handleTest ./matomo.nix {};
   matrix-appservice-irc = handleTest ./matrix/appservice-irc.nix {};
@@ -613,6 +614,7 @@ in {
   nginx-variants = handleTest ./nginx-variants.nix {};
   nifi = handleTestOn ["x86_64-linux"] ./web-apps/nifi.nix {};
   nitter = handleTest ./nitter.nix {};
+  nix-config = handleTest ./nix-config.nix {};
   nix-ld = handleTest ./nix-ld.nix {};
   nix-serve = handleTest ./nix-serve.nix {};
   nix-serve-ssh = handleTest ./nix-serve-ssh.nix {};
@@ -640,6 +642,7 @@ in {
   nzbget = handleTest ./nzbget.nix {};
   nzbhydra2 = handleTest ./nzbhydra2.nix {};
   oh-my-zsh = handleTest ./oh-my-zsh.nix {};
+  ollama = handleTest ./ollama.nix {};
   ombi = handleTest ./ombi.nix {};
   openarena = handleTest ./openarena.nix {};
   openldap = handleTest ./openldap.nix {};
@@ -682,10 +685,12 @@ in {
   peering-manager = handleTest ./web-apps/peering-manager.nix {};
   peertube = handleTestOn ["x86_64-linux"] ./web-apps/peertube.nix {};
   peroxide = handleTest ./peroxide.nix {};
+  pg_anonymizer = handleTest ./pg_anonymizer.nix {};
   pgadmin4 = handleTest ./pgadmin4.nix {};
   pgbouncer = handleTest ./pgbouncer.nix {};
   pgjwt = handleTest ./pgjwt.nix {};
   pgmanage = handleTest ./pgmanage.nix {};
+  pgvecto-rs = handleTest ./pgvecto-rs.nix {};
   phosh = handleTest ./phosh.nix {};
   photoprism = handleTest ./photoprism.nix {};
   php = handleTest ./php {};
@@ -725,6 +730,7 @@ in {
   pppd = handleTest ./pppd.nix {};
   predictable-interface-names = handleTest ./predictable-interface-names.nix {};
   pretalx = runTest ./web-apps/pretalx.nix;
+  pretix = runTest ./web-apps/pretix.nix;
   printing-socket = handleTest ./printing.nix { socket = true; };
   printing-service = handleTest ./printing.nix { socket = false; };
   privoxy = handleTest ./privoxy.nix {};
diff --git a/nixos/tests/budgie.nix b/nixos/tests/budgie.nix
index fe0ed2cf80ed..99804303e397 100644
--- a/nixos/tests/budgie.nix
+++ b/nixos/tests/budgie.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "budgie";
 
-  meta.maintainers = [ lib.maintainers.federicoschonborn ];
+  meta.maintainers = lib.teams.budgie.members;
 
   nodes.machine = { ... }: {
     imports = [
@@ -29,6 +29,8 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
   testScript = { nodes, ... }:
     let
       user = nodes.machine.users.users.alice;
+      env = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${toString user.uid}/bus DISPLAY=:0";
+      su = command: "su - ${user.name} -c '${env} ${command}'";
     in
     ''
       with subtest("Wait for login"):
@@ -47,21 +49,45 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
           machine.succeed("getfacl -p /dev/snd/timer | grep -q ${user.name}")
 
       with subtest("Check if Budgie session components actually start"):
-          machine.wait_until_succeeds("pgrep budgie-daemon")
+          for i in ["budgie-daemon", "budgie-panel", "budgie-wm", "budgie-desktop-view", "gsd-media-keys"]:
+              machine.wait_until_succeeds(f"pgrep -f {i}")
+          # We don't check xwininfo for budgie-wm.
+          # See https://github.com/NixOS/nixpkgs/pull/216737#discussion_r1155312754
           machine.wait_for_window("budgie-daemon")
-          machine.wait_until_succeeds("pgrep budgie-panel")
           machine.wait_for_window("budgie-panel")
-          # We don't check xwininfo for this one.
-          # See https://github.com/NixOS/nixpkgs/pull/216737#discussion_r1155312754
-          machine.wait_until_succeeds("pgrep budgie-wm")
+
+      with subtest("Check if various environment variables are set"):
+          cmd = "xargs --null --max-args=1 echo < /proc/$(pgrep -xf /run/current-system/sw/bin/budgie-wm)/environ"
+          machine.succeed(f"{cmd} | grep 'XDG_CURRENT_DESKTOP' | grep 'Budgie:GNOME'")
+          machine.succeed(f"{cmd} | grep 'BUDGIE_PLUGIN_DATADIR' | grep '${pkgs.budgie.budgie-desktop-with-plugins.pname}'")
+
+      with subtest("Open Budgie Control Center"):
+          machine.send_key("alt-f2")
+          machine.wait_until_succeeds("pgrep -f budgie-run-dialog")
+          machine.wait_for_window("budgie-run-dialog")
+          machine.sleep(3)
+          machine.send_chars("Budgie Control Center", delay=0.5)
+          machine.screenshot("quick_search")
+          machine.send_chars("\n")
+          machine.wait_for_window("Budgie Control Center")
+
+      with subtest("Lock the screen"):
+          machine.succeed("${su "budgie-screensaver-command -l >&2 &"}")
+          machine.wait_until_succeeds("${su "budgie-screensaver-command -q"} | grep 'The screensaver is active'")
+          machine.sleep(2)
+          machine.send_chars("${user.password}", delay=0.5)
+          machine.screenshot("budgie_screensaver")
+          machine.send_chars("\n")
+          machine.wait_until_succeeds("${su "budgie-screensaver-command -q"} | grep 'The screensaver is inactive'")
+          machine.sleep(2)
 
       with subtest("Open MATE terminal"):
-          machine.succeed("su - ${user.name} -c 'DISPLAY=:0 mate-terminal >&2 &'")
+          machine.succeed("${su "mate-terminal >&2 &"}")
           machine.wait_for_window("Terminal")
 
-      with subtest("Check if budgie-wm has ever coredumped"):
-          machine.fail("coredumpctl --json=short | grep budgie-wm")
-          machine.sleep(20)
+      with subtest("Check if Budgie has ever coredumped"):
+          machine.fail("coredumpctl --json=short | grep budgie")
+          machine.sleep(10)
           machine.screenshot("screen")
     '';
 })
diff --git a/nixos/tests/freetube.nix b/nixos/tests/freetube.nix
index faa534938227..10f0773cb884 100644
--- a/nixos/tests/freetube.nix
+++ b/nixos/tests/freetube.nix
@@ -40,4 +40,4 @@ let
       '';
     });
 in
-builtins.mapAttrs (k: v: mkTest k v { }) tests
+builtins.mapAttrs (k: v: mkTest k v) tests
diff --git a/nixos/tests/hibernate.nix b/nixos/tests/hibernate.nix
index 296aa9ba68b9..6de287f63e08 100644
--- a/nixos/tests/hibernate.nix
+++ b/nixos/tests/hibernate.nix
@@ -24,8 +24,8 @@ makeTest {
       virtualisation.useNixStoreImage = true;
 
       swapDevices = lib.mkOverride 0 [ { device = "/dev/vdc"; options = [ "x-systemd.makefs" ]; } ];
-      boot.resumeDevice = "/dev/vdc";
       boot.initrd.systemd.enable = systemdStage1;
+      virtualisation.useEFIBoot = true;
     };
   };
 
diff --git a/nixos/tests/incus/container.nix b/nixos/tests/incus/container.nix
index eb00429e53fe..9260f70da98c 100644
--- a/nixos/tests/incus/container.nix
+++ b/nixos/tests/incus/container.nix
@@ -29,6 +29,7 @@ in
 
       incus.enable = true;
     };
+    networking.nftables.enable = true;
   };
 
   testScript = ''
diff --git a/nixos/tests/incus/default.nix b/nixos/tests/incus/default.nix
index ff36fe9d6730..32bc5396a164 100644
--- a/nixos/tests/incus/default.nix
+++ b/nixos/tests/incus/default.nix
@@ -11,8 +11,10 @@
     boot.initrd.systemd.enable = true;
   }; };
   lxd-to-incus = import ./lxd-to-incus.nix { inherit system pkgs; };
+  openvswitch = import ./openvswitch.nix { inherit system pkgs; };
   preseed = import ./preseed.nix { inherit system pkgs; };
   socket-activated = import ./socket-activated.nix { inherit system pkgs; };
+  storage = import ./storage.nix { inherit system pkgs; };
   ui = import ./ui.nix {inherit system pkgs;};
   virtual-machine = handleTestOn [ "x86_64-linux" ] ./virtual-machine.nix { inherit system pkgs; };
 }
diff --git a/nixos/tests/incus/lxd-to-incus.nix b/nixos/tests/incus/lxd-to-incus.nix
index c0fc98c224df..262f63c0f26f 100644
--- a/nixos/tests/incus/lxd-to-incus.nix
+++ b/nixos/tests/incus/lxd-to-incus.nix
@@ -67,6 +67,7 @@ import ../make-test-python.nix (
 
           incus.enable = true;
         };
+        networking.nftables.enable = true;
       };
 
     testScript = ''
diff --git a/nixos/tests/incus/openvswitch.nix b/nixos/tests/incus/openvswitch.nix
new file mode 100644
index 000000000000..5d4aef031ad0
--- /dev/null
+++ b/nixos/tests/incus/openvswitch.nix
@@ -0,0 +1,65 @@
+import ../make-test-python.nix ({ pkgs, lib, ... } :
+
+{
+  name = "incus-openvswitch";
+
+  meta = {
+    maintainers = lib.teams.lxc.members;
+  };
+
+  nodes.machine = { lib, ... }: {
+    virtualisation = {
+      incus.enable = true;
+      vswitch.enable = true;
+      incus.preseed = {
+        networks = [
+          {
+            name = "nixostestbr0";
+            type = "bridge";
+            config = {
+              "bridge.driver" = "openvswitch";
+              "ipv4.address" = "10.0.100.1/24";
+              "ipv4.nat" = "true";
+            };
+          }
+        ];
+        profiles = [
+          {
+            name = "nixostest_default";
+            devices = {
+              eth0 = {
+                name = "eth0";
+                network = "nixostestbr0";
+                type = "nic";
+              };
+              root = {
+                path = "/";
+                pool = "default";
+                size = "35GiB";
+                type = "disk";
+              };
+            };
+          }
+        ];
+        storage_pools = [
+          {
+            name = "nixostest_pool";
+            driver = "dir";
+          }
+        ];
+      };
+    };
+    networking.nftables.enable = true;
+  };
+
+  testScript = ''
+    machine.wait_for_unit("incus.service")
+    machine.wait_for_unit("incus-preseed.service")
+
+    with subtest("Verify openvswitch bridge"):
+      machine.succeed("incus network info nixostestbr0")
+
+    with subtest("Verify openvswitch bridge"):
+      machine.succeed("ovs-vsctl br-exists nixostestbr0")
+  '';
+})
diff --git a/nixos/tests/incus/preseed.nix b/nixos/tests/incus/preseed.nix
index a488d71f3c92..f2d928115f3e 100644
--- a/nixos/tests/incus/preseed.nix
+++ b/nixos/tests/incus/preseed.nix
@@ -48,6 +48,7 @@ import ../make-test-python.nix ({ pkgs, lib, ... } :
         ];
       };
     };
+    networking.nftables.enable = true;
   };
 
   testScript = ''
diff --git a/nixos/tests/incus/socket-activated.nix b/nixos/tests/incus/socket-activated.nix
index fca536b7054f..59caf1090fbd 100644
--- a/nixos/tests/incus/socket-activated.nix
+++ b/nixos/tests/incus/socket-activated.nix
@@ -12,6 +12,7 @@ import ../make-test-python.nix ({ pkgs, lib, ... } :
       incus.enable = true;
       incus.socketActivation = true;
     };
+    networking.nftables.enable = true;
   };
 
   testScript = ''
diff --git a/nixos/tests/incus/storage.nix b/nixos/tests/incus/storage.nix
new file mode 100644
index 000000000000..190f4f7451c2
--- /dev/null
+++ b/nixos/tests/incus/storage.nix
@@ -0,0 +1,46 @@
+import ../make-test-python.nix (
+  { pkgs, lib, ... }:
+
+  {
+    name = "incus-storage";
+
+    meta = {
+      maintainers = lib.teams.lxc.members;
+    };
+
+    nodes.machine =
+      { lib, ... }:
+      {
+        boot.supportedFilesystems = [ "zfs" ];
+        boot.zfs.forceImportRoot = false;
+        environment.systemPackages = [ pkgs.parted ];
+        networking.hostId = "01234567";
+        networking.nftables.enable = true;
+
+        virtualisation = {
+          emptyDiskImages = [ 2048 ];
+          incus.enable = true;
+        };
+      };
+
+    testScript = ''
+      machine.wait_for_unit("incus.service")
+
+      with subtest("Verify zfs pool created and usable"):
+        machine.succeed(
+            "zpool status",
+            "parted --script /dev/vdb mklabel gpt",
+            "zpool create zfs_pool /dev/vdb",
+        )
+
+        machine.succeed("incus storage create zfs_pool zfs source=zfs_pool/incus")
+        machine.succeed("zfs list zfs_pool/incus")
+        machine.succeed("incus storage volume create zfs_pool test_fs --type filesystem")
+        machine.succeed("incus storage volume create zfs_pool test_vol --type block")
+        machine.succeed("incus storage show zfs_pool")
+        machine.succeed("incus storage volume list zfs_pool")
+        machine.succeed("incus storage volume show zfs_pool test_fs")
+        machine.succeed("incus storage volume show zfs_pool test_vol")
+    '';
+  }
+)
diff --git a/nixos/tests/incus/ui.nix b/nixos/tests/incus/ui.nix
index 24ce1217d8df..837eb14844ce 100644
--- a/nixos/tests/incus/ui.nix
+++ b/nixos/tests/incus/ui.nix
@@ -10,6 +10,7 @@ import ../make-test-python.nix ({ pkgs, lib, ... }: {
       incus.enable = true;
       incus.ui.enable = true;
     };
+    networking.nftables.enable = true;
 
     environment.systemPackages =
       let
diff --git a/nixos/tests/incus/virtual-machine.nix b/nixos/tests/incus/virtual-machine.nix
index c76e4f448f2f..ab378c7b9490 100644
--- a/nixos/tests/incus/virtual-machine.nix
+++ b/nixos/tests/incus/virtual-machine.nix
@@ -32,6 +32,7 @@ in
 
       incus.enable = true;
     };
+    networking.nftables.enable = true;
   };
 
   testScript = ''
diff --git a/nixos/tests/installer-systemd-stage-1.nix b/nixos/tests/installer-systemd-stage-1.nix
index 662017935412..d10256d91d7f 100644
--- a/nixos/tests/installer-systemd-stage-1.nix
+++ b/nixos/tests/installer-systemd-stage-1.nix
@@ -37,6 +37,7 @@
     clevisLuksFallback
     clevisZfs
     clevisZfsFallback
+    gptAutoRoot
     ;
 
 }
diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix
index 97bb7f8def59..1de886d6a0d1 100644
--- a/nixos/tests/installer.nix
+++ b/nixos/tests/installer.nix
@@ -82,6 +82,7 @@ let
   testScriptFun = { bootLoader, createPartitions, grubDevice, grubUseEfi, grubIdentifier
                   , postInstallCommands, preBootCommands, postBootCommands, extraConfig
                   , testSpecialisationConfig, testFlakeSwitch, clevisTest, clevisFallbackTest
+                  , disableFileSystems
                   }:
     let
       qemu-common = import ../lib/qemu-common.nix { inherit (pkgs) lib pkgs; };
@@ -163,7 +164,7 @@ let
       ${createPartitions}
 
       with subtest("Create the NixOS configuration"):
-          machine.succeed("nixos-generate-config --root /mnt")
+          machine.succeed("nixos-generate-config ${optionalString disableFileSystems "--no-filesystems"} --root /mnt")
           machine.succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2")
           machine.copy_from_host(
               "${ makeConfig {
@@ -433,6 +434,7 @@ let
     , testFlakeSwitch ? false
     , clevisTest ? false
     , clevisFallbackTest ? false
+    , disableFileSystems ? false
     }:
     makeTest {
       inherit enableOCR;
@@ -541,7 +543,8 @@ let
       testScript = testScriptFun {
         inherit bootLoader createPartitions postInstallCommands preBootCommands postBootCommands
                 grubDevice grubIdentifier grubUseEfi extraConfig
-                testSpecialisationConfig testFlakeSwitch clevisTest clevisFallbackTest;
+                testSpecialisationConfig testFlakeSwitch clevisTest clevisFallbackTest
+                disableFileSystems;
       };
     };
 
@@ -1414,4 +1417,39 @@ in {
       };
     };
   };
+
+  gptAutoRoot = let
+    rootPartType = {
+      ia32 = "44479540-F297-41B2-9AF7-D131D5F0458A";
+      x64 = "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709";
+      arm = "69DAD710-2CE4-4E3C-B16C-21A1D49ABED3";
+      aa64 = "B921B045-1DF0-41C3-AF44-4C6F280D3FAE";
+    }.${pkgs.stdenv.hostPlatform.efiArch};
+  in makeInstallerTest "gptAutoRoot" {
+    disableFileSystems = true;
+    createPartitions = ''
+      machine.succeed(
+        "sgdisk --zap-all /dev/vda",
+        "sgdisk --new=1:0:+100M --typecode=0:ef00 /dev/vda", # /boot
+        "sgdisk --new=2:0:+1G --typecode=0:8200 /dev/vda", # swap
+        "sgdisk --new=3:0:+5G --typecode=0:${rootPartType} /dev/vda", # /
+        "udevadm settle",
+
+        "mkfs.vfat /dev/vda1",
+        "mkswap /dev/vda2 -L swap",
+        "swapon -L swap",
+        "mkfs.ext4 -L root /dev/vda3",
+        "udevadm settle",
+
+        "mount /dev/vda3 /mnt",
+        "mkdir -p /mnt/boot",
+        "mount /dev/vda1 /mnt/boot"
+      )
+    '';
+    bootLoader = "systemd-boot";
+    extraConfig = ''
+      boot.initrd.systemd.root = "gpt-auto";
+      boot.initrd.supportedFilesystems = ["ext4"];
+    '';
+  };
 }
diff --git a/nixos/tests/keycloak.nix b/nixos/tests/keycloak.nix
index 228e57d1cdd6..67b412c80961 100644
--- a/nixos/tests/keycloak.nix
+++ b/nixos/tests/keycloak.nix
@@ -6,8 +6,8 @@ let
   certs = import ./common/acme/server/snakeoil-certs.nix;
   frontendUrl = "https://${certs.domain}";
 
-  keycloakTest = import ./make-test-python.nix (
-    { pkgs, databaseType, ... }:
+  keycloakTest = databaseType: import ./make-test-python.nix (
+    { pkgs, ... }:
     let
       initialAdminPassword = "h4Iho\"JFn't2>iQIR9";
       adminPasswordFile = pkgs.writeText "admin-password" "${initialAdminPassword}";
@@ -76,16 +76,18 @@ let
             enabled = true;
             realm = "test-realm";
             clients = [ client ];
-            users = [(
-              user // {
-                enabled = true;
-                credentials = [{
-                  type = "password";
-                  temporary = false;
-                  value = password;
-                }];
-              }
-            )];
+            users = [
+              (
+                user // {
+                  enabled = true;
+                  credentials = [{
+                    type = "password";
+                    temporary = false;
+                    value = password;
+                  }];
+                }
+              )
+            ];
           };
 
           realmDataJson = pkgs.writeText "realm-data.json" (builtins.toJSON realm);
@@ -177,7 +179,7 @@ let
   );
 in
 {
-  postgres = keycloakTest { databaseType = "postgresql"; };
-  mariadb = keycloakTest { databaseType = "mariadb"; };
-  mysql = keycloakTest { databaseType = "mysql"; };
+  postgres = keycloakTest "postgresql";
+  mariadb = keycloakTest "mariadb";
+  mysql = keycloakTest "mysql";
 }
diff --git a/nixos/tests/knot.nix b/nixos/tests/knot.nix
index c5af8bf1edcc..eec94a22f2fa 100644
--- a/nixos/tests/knot.nix
+++ b/nixos/tests/knot.nix
@@ -66,6 +66,10 @@ in {
             "0.0.0.0@53"
             "::@53"
            ];
+          listen-quic = [
+            "0.0.0.0@853"
+            "::@853"
+           ];
           automatic-acl = true;
         };
 
@@ -129,8 +133,13 @@ in {
           key = "xfr_key";
         };
 
+        remote.primary-quic = {
+          address = "192.168.0.1@853";
+          key = "xfr_key";
+          quic = true;
+        };
+
         template.default = {
-          master = "primary";
           # zonefileless setup
           # https://www.knot-dns.cz/docs/2.8/html/operation.html#example-2
           zonefile-sync = "-1";
@@ -139,8 +148,14 @@ in {
         };
 
         zone = {
-          "example.com".file = "example.com.zone";
-          "sub.example.com".file = "sub.example.com.zone";
+          "example.com" = {
+            master = "primary";
+            file = "example.com.zone";
+          };
+          "sub.example.com" = {
+            master = "primary-quic";
+            file = "sub.example.com.zone";
+          };
         };
 
         log.syslog.any = "debug";
diff --git a/nixos/tests/krb5/default.nix b/nixos/tests/krb5/default.nix
index ede085632c63..274ad580cebc 100644
--- a/nixos/tests/krb5/default.nix
+++ b/nixos/tests/krb5/default.nix
@@ -1,4 +1,3 @@
-{ system ? builtins.currentSystem }:
 {
-  example-config = import ./example-config.nix { inherit system; };
+  example-config = import ./example-config.nix;
 }
diff --git a/nixos/tests/make-test-python.nix b/nixos/tests/make-test-python.nix
index 28569f1d2955..32531fffd2bf 100644
--- a/nixos/tests/make-test-python.nix
+++ b/nixos/tests/make-test-python.nix
@@ -1,5 +1,5 @@
 f: {
-  system ? builtins.currentSystem,
+  system,
   pkgs ? import ../.. { inherit system; config = {}; overlays = []; },
   ...
 } @ args:
diff --git a/nixos/tests/mate-wayland.nix b/nixos/tests/mate-wayland.nix
new file mode 100644
index 000000000000..df39ead286e1
--- /dev/null
+++ b/nixos/tests/mate-wayland.nix
@@ -0,0 +1,63 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "mate-wayland";
+
+  meta.maintainers = lib.teams.mate.members;
+
+  nodes.machine = { ... }: {
+    imports = [
+      ./common/user-account.nix
+    ];
+
+    services.xserver.enable = true;
+    services.xserver.displayManager = {
+      sddm.enable = true; # https://github.com/canonical/lightdm/issues/63
+      sddm.wayland.enable = true;
+      defaultSession = "MATE";
+      autoLogin = {
+        enable = true;
+        user = "alice";
+      };
+    };
+    services.xserver.desktopManager.mate.enableWaylandSession = true;
+
+    hardware.pulseaudio.enable = true;
+
+    # Need to switch to a different GPU driver than the default one (-vga std) so that wayfire can launch:
+    virtualisation.qemu.options = [ "-vga none -device virtio-gpu-pci" ];
+  };
+
+  enableOCR = true;
+
+  testScript = { nodes, ... }:
+    let
+      user = nodes.machine.users.users.alice;
+    in
+    ''
+      machine.wait_for_unit("display-manager.service")
+
+      with subtest("Wait for Wayland server"):
+          machine.wait_for_file("/run/user/${toString user.uid}/wayland-1")
+
+      with subtest("Check if MATE session components actually start"):
+          for i in ["wayfire", "mate-panel", "mate-wayland.sh", "mate-wayland-components.sh"]:
+              machine.wait_until_succeeds(f"pgrep -f {i}")
+          machine.wait_for_text('(Applications|Places|System)')
+          # It is expected that this applet doesn't work in Wayland
+          machine.wait_for_text('WorkspaceSwitcherApplet')
+
+      with subtest("Check if various environment variables are set"):
+          cmd = "xargs --null --max-args=1 echo < /proc/$(pgrep -xf mate-panel)/environ"
+          machine.succeed(f"{cmd} | grep 'XDG_SESSION_TYPE' | grep 'wayland'")
+          machine.succeed(f"{cmd} | grep 'XDG_SESSION_DESKTOP' | grep 'MATE'")
+          machine.succeed(f"{cmd} | grep 'MATE_PANEL_APPLETS_DIR' | grep '${pkgs.mate.mate-panel-with-applets.pname}'")
+
+      with subtest("Check if Wayfire config is properly configured"):
+          for i in ["button_style = mate", "firedecor", "mate-wayland-components.sh"]:
+              machine.wait_until_succeeds(f"cat /home/${user.name}/.config/mate/wayfire.ini | grep '{i}'")
+
+      with subtest("Check if Wayfire has ever coredumped"):
+          machine.fail("coredumpctl --json=short | grep wayfire")
+          machine.sleep(10)
+          machine.screenshot("screen")
+    '';
+})
diff --git a/nixos/tests/mate.nix b/nixos/tests/mate.nix
index 48582e18d520..1252ec43cf3d 100644
--- a/nixos/tests/mate.nix
+++ b/nixos/tests/mate.nix
@@ -54,6 +54,15 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
           machine.wait_for_text('(Applications|Places|System)')
           machine.wait_for_text('(Computer|Home|Trash)')
 
+      with subtest("Check if various environment variables are set"):
+          machine.succeed("xargs --null --max-args=1 echo < /proc/$(pgrep -xf marco)/environ | grep 'XDG_CURRENT_DESKTOP' | grep 'MATE'")
+          # From mate-panel-with-applets packaging
+          machine.succeed("xargs --null --max-args=1 echo < /proc/$(pgrep -xf mate-panel)/environ | grep 'MATE_PANEL_APPLETS_DIR' | grep '${pkgs.mate.mate-panel-with-applets.pname}'")
+
+      with subtest("Check if applets are built with in-process support"):
+          # This is needed for Wayland support
+          machine.fail("pgrep -fa clock-applet")
+
       with subtest("Lock the screen"):
           machine.wait_until_succeeds("su - ${user.name} -c '${env} mate-screensaver-command -q' | grep 'The screensaver is inactive'")
           machine.succeed("su - ${user.name} -c '${env} mate-screensaver-command -l >&2 &'")
diff --git a/nixos/tests/miriway.nix b/nixos/tests/miriway.nix
index a0987d9fc41b..24e6ec6367cd 100644
--- a/nixos/tests/miriway.nix
+++ b/nixos/tests/miriway.nix
@@ -100,7 +100,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     # Test Wayland
     # We let Miriway start the first terminal, as we might get stuck if it's not ready to process the first keybind
     # machine.send_key("ctrl-alt-t")
-    machine.wait_for_text("alice@machine")
+    machine.wait_for_text(r"(alice|machine)")
     machine.send_chars("test-wayland\n")
     machine.wait_for_file("/tmp/test-wayland-exit-ok")
     machine.copy_from_vm("/tmp/test-wayland.out")
@@ -112,7 +112,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
 
     # Test XWayland
     machine.send_key("ctrl-alt-a")
-    machine.wait_for_text("alice@machine")
+    machine.wait_for_text(r"(alice|machine)")
     machine.send_chars("test-x11\n")
     machine.wait_for_file("/tmp/test-x11-exit-ok")
     machine.copy_from_vm("/tmp/test-x11.out")
diff --git a/nixos/tests/nebula.nix b/nixos/tests/nebula.nix
index 89b91d89fcb3..6c468153d5b2 100644
--- a/nixos/tests/nebula.nix
+++ b/nixos/tests/nebula.nix
@@ -10,6 +10,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: let
       environment.systemPackages = [ pkgs.nebula ];
       users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
       services.openssh.enable = true;
+      networking.firewall.enable = true; # Implicitly true, but let's make sure.
       networking.interfaces.eth1.useDHCP = false;
 
       services.nebula.networks.smoke = {
@@ -17,7 +18,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: let
         ca = "/etc/nebula/ca.crt";
         cert = "/etc/nebula/${name}.crt";
         key = "/etc/nebula/${name}.key";
-        listen = { host = "0.0.0.0"; port = 4242; };
+        listen = {
+          host = "0.0.0.0";
+          port = if (config.services.nebula.networks.smoke.isLighthouse || config.services.nebula.networks.smoke.isRelay) then 4242 else 0;
+        };
       };
     }
     extraConfig
diff --git a/nixos/tests/nix-config.nix b/nixos/tests/nix-config.nix
new file mode 100644
index 000000000000..907e886def35
--- /dev/null
+++ b/nixos/tests/nix-config.nix
@@ -0,0 +1,18 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+{
+  name = "nix-config";
+  nodes.machine = { pkgs, ... }: {
+    nix.settings = {
+      nix-path = [ "nonextra=/etc/value.nix" ];
+      extra-nix-path = [ "extra=/etc/value.nix" ];
+    };
+    environment.etc."value.nix".text = "42";
+  };
+  testScript = ''
+    start_all()
+    machine.wait_for_unit("nix-daemon.socket")
+    # regression test for the workaround for https://github.com/NixOS/nix/issues/9487
+    print(machine.succeed("nix-instantiate --find-file extra"))
+    print(machine.succeed("nix-instantiate --find-file nonextra"))
+  '';
+})
diff --git a/nixos/tests/nixops/default.nix b/nixos/tests/nixops/default.nix
index 6501d13a2ed3..8477e5059fca 100644
--- a/nixos/tests/nixops/default.nix
+++ b/nixos/tests/nixops/default.nix
@@ -9,7 +9,7 @@ let
     #  - Alternatively, blocked on a NixOps 2 release
     #    https://github.com/NixOS/nixops/issues/1242
     # stable = testsLegacyNetwork { nixopsPkg = pkgs.nixops; };
-    unstable = testsForPackage { nixopsPkg = pkgs.nixops_unstable; };
+    unstable = testsForPackage { nixopsPkg = pkgs.nixops_unstable_minimal; };
 
     # inherit testsForPackage;
   };
@@ -32,6 +32,7 @@ let
           pkgs.hello
           pkgs.figlet
         ];
+        virtualisation.memorySize = 2048;
 
         # TODO: make this efficient, https://github.com/NixOS/nixpkgs/issues/180529
         system.includeBuildDependencies = true;
diff --git a/nixos/tests/ollama.nix b/nixos/tests/ollama.nix
new file mode 100644
index 000000000000..4b21f445cdbd
--- /dev/null
+++ b/nixos/tests/ollama.nix
@@ -0,0 +1,56 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }:
+let
+  mainPort = "11434";
+  altPort = "11435";
+
+  curlRequest = port: request:
+    "curl http://127.0.0.1:${port}/api/generate -d '${builtins.toJSON request}'";
+
+  prompt = {
+    model = "tinydolphin";
+    prompt = "lorem ipsum";
+    options = {
+      seed = 69;
+      temperature = 0;
+    };
+  };
+in
+{
+  name = "ollama";
+  meta = with lib.maintainers; {
+    maintainers = [ abysssol ];
+  };
+
+  nodes = {
+    cpu = { ... }: {
+      services.ollama.enable = true;
+    };
+
+    rocm = { ... }: {
+      services.ollama.enable = true;
+      services.ollama.acceleration = "rocm";
+    };
+
+    cuda = { ... }: {
+      services.ollama.enable = true;
+      services.ollama.acceleration = "cuda";
+    };
+
+    altAddress = { ... }: {
+      services.ollama.enable = true;
+      services.ollama.listenAddress = "127.0.0.1:${altPort}";
+    };
+  };
+
+  testScript = ''
+    vms = [ cpu, rocm, cuda, altAddress ];
+
+    start_all()
+    for vm in vms:
+        vm.wait_for_unit("multi-user.target")
+
+    stdout = cpu.succeed("""${curlRequest mainPort prompt}""", timeout=100)
+
+    stdout = altAddress.succeed("""${curlRequest altPort prompt}""", timeout=100)
+  '';
+})
diff --git a/nixos/tests/opensearch.nix b/nixos/tests/opensearch.nix
index 2887ac967765..7d37583464cb 100644
--- a/nixos/tests/opensearch.nix
+++ b/nixos/tests/opensearch.nix
@@ -1,7 +1,7 @@
 let
-  opensearchTest =
+  opensearchTest = extraSettings:
     import ./make-test-python.nix (
-      { pkgs, lib, extraSettings ? {} }: {
+      { pkgs, lib, ... }: {
         name = "opensearch";
         meta.maintainers = with pkgs.lib.maintainers; [ shyim ];
 
@@ -27,20 +27,18 @@ in
 {
   opensearch = opensearchTest {};
   opensearchCustomPathAndUser = opensearchTest {
-    extraSettings = {
-      services.opensearch.dataDir = "/var/opensearch_test";
-      services.opensearch.user = "open_search";
-      services.opensearch.group = "open_search";
-      systemd.tmpfiles.rules = [
-        "d /var/opensearch_test 0700 open_search open_search -"
-      ];
-      users = {
-        groups.open_search = {};
-        users.open_search = {
-          description = "OpenSearch daemon user";
-          group = "open_search";
-          isSystemUser = true;
-        };
+    services.opensearch.dataDir = "/var/opensearch_test";
+    services.opensearch.user = "open_search";
+    services.opensearch.group = "open_search";
+    systemd.tmpfiles.rules = [
+      "d /var/opensearch_test 0700 open_search open_search -"
+    ];
+    users = {
+      groups.open_search = { };
+      users.open_search = {
+        description = "OpenSearch daemon user";
+        group = "open_search";
+        isSystemUser = true;
       };
     };
   };
diff --git a/nixos/tests/pass-secret-service.nix b/nixos/tests/pass-secret-service.nix
index e0dddf0ad29e..cdbdaa52dbc0 100644
--- a/nixos/tests/pass-secret-service.nix
+++ b/nixos/tests/pass-secret-service.nix
@@ -26,7 +26,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
 
       programs.gnupg = {
         agent.enable = true;
-        agent.pinentryFlavor = "tty";
         dirmngr.enable = true;
       };
     };
diff --git a/nixos/tests/pg_anonymizer.nix b/nixos/tests/pg_anonymizer.nix
new file mode 100644
index 000000000000..2960108e37c3
--- /dev/null
+++ b/nixos/tests/pg_anonymizer.nix
@@ -0,0 +1,94 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "pg_anonymizer";
+  meta.maintainers = lib.teams.flyingcircus.members;
+
+  nodes.machine = { pkgs, ... }: {
+    environment.systemPackages = [ pkgs.pg-dump-anon ];
+    services.postgresql = {
+      enable = true;
+      extraPlugins = ps: [ ps.anonymizer ];
+      settings.shared_preload_libraries = "anon";
+    };
+  };
+
+  testScript = ''
+    start_all()
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_for_unit("postgresql.service")
+
+    with subtest("Setup"):
+        machine.succeed("sudo -u postgres psql --command 'create database demo'")
+        machine.succeed(
+            "sudo -u postgres psql -d demo -f ${pkgs.writeText "init.sql" ''
+              create extension anon cascade;
+              select anon.init();
+              create table player(id serial, name text, points int);
+              insert into player(id,name,points) values (1,'Foo', 23);
+              insert into player(id,name,points) values (2,'Bar',42);
+              security label for anon on column player.name is 'MASKED WITH FUNCTION anon.fake_last_name();';
+              security label for anon on column player.points is 'MASKED WITH VALUE NULL';
+            ''}"
+        )
+
+    def get_player_table_contents():
+        return [
+            x.split(',') for x in machine.succeed("sudo -u postgres psql -d demo --csv --command 'select * from player'").splitlines()[1:]
+        ]
+
+    def check_anonymized_row(row, id, original_name):
+        assert row[0] == id, f"Expected first row to have ID {id}, but got {row[0]}"
+        assert row[1] != original_name, f"Expected first row to have a name other than {original_name}"
+        assert not bool(row[2]), "Expected points to be NULL in first row"
+
+    def find_xsv_in_dump(dump, sep=','):
+        """
+        Expecting to find a CSV (for pg_dump_anon) or TSV (for pg_dump) structure, looking like
+
+            COPY public.player ...
+            1,Shields,
+            2,Salazar,
+            \.
+
+        in the given dump (the commas are tabs in case of pg_dump).
+              Extract the CSV lines and split by `sep`.
+        """
+
+        try:
+            from itertools import dropwhile, takewhile
+            return [x.split(sep) for x in list(takewhile(
+                lambda x: x != "\\.",
+                dropwhile(
+                    lambda x: not x.startswith("COPY public.player"),
+                    dump.splitlines()
+                )
+            ))[1:]]
+        except:
+            print(f"Dump to process: {dump}")
+            raise
+
+    def check_original_data(output):
+        assert output[0] == ['1','Foo','23'], f"Expected first row from player table to be 1,Foo,23; got {output[0]}"
+        assert output[1] == ['2','Bar','42'], f"Expected first row from player table to be 2,Bar,42; got {output[1]}"
+
+    def check_anonymized_rows(output):
+        check_anonymized_row(output[0], '1', 'Foo')
+        check_anonymized_row(output[1], '2', 'Bar')
+
+    with subtest("Check initial state"):
+        check_original_data(get_player_table_contents())
+
+    with subtest("Anonymous dumps"):
+        check_original_data(find_xsv_in_dump(
+            machine.succeed("sudo -u postgres pg_dump demo"),
+            sep='\t'
+        ))
+        check_anonymized_rows(find_xsv_in_dump(
+            machine.succeed("sudo -u postgres pg_dump_anon -U postgres -h /run/postgresql -d demo"),
+            sep=','
+        ))
+
+    with subtest("Anonymize"):
+        machine.succeed("sudo -u postgres psql -d demo --command 'select anon.anonymize_database();'")
+        check_anonymized_rows(get_player_table_contents())
+  '';
+})
diff --git a/nixos/tests/pgvecto-rs.nix b/nixos/tests/pgvecto-rs.nix
new file mode 100644
index 000000000000..cd871dab6a0f
--- /dev/null
+++ b/nixos/tests/pgvecto-rs.nix
@@ -0,0 +1,76 @@
+# mostly copied from ./timescaledb.nix which was copied from ./postgresql.nix
+# as it seemed unapproriate to test additional extensions for postgresql there.
+
+{ system ? builtins.currentSystem
+, config ? { }
+, pkgs ? import ../.. { inherit system config; }
+}:
+
+with import ../lib/testing-python.nix { inherit system pkgs; };
+with pkgs.lib;
+
+let
+  postgresql-versions = import ../../pkgs/servers/sql/postgresql pkgs;
+  # Test cases from https://docs.pgvecto.rs/use-cases/hybrid-search.html
+  test-sql = pkgs.writeText "postgresql-test" ''
+    CREATE EXTENSION vectors;
+
+    CREATE TABLE items (
+      id bigserial PRIMARY KEY,
+      content text NOT NULL,
+      embedding vectors.vector(3) NOT NULL -- 3 dimensions
+    );
+
+    INSERT INTO items (content, embedding) VALUES
+      ('a fat cat sat on a mat and ate a fat rat', '[1, 2, 3]'),
+      ('a fat dog sat on a mat and ate a fat rat', '[4, 5, 6]'),
+      ('a thin cat sat on a mat and ate a thin rat', '[7, 8, 9]'),
+      ('a thin dog sat on a mat and ate a thin rat', '[10, 11, 12]');
+  '';
+  make-postgresql-test = postgresql-name: postgresql-package: makeTest {
+    name = postgresql-name;
+    meta = with pkgs.lib.maintainers; {
+      maintainers = [ diogotcorreia ];
+    };
+
+    nodes.machine = { ... }:
+      {
+        services.postgresql = {
+          enable = true;
+          package = postgresql-package;
+          extraPlugins = ps: with ps; [
+            pgvecto-rs
+          ];
+          settings.shared_preload_libraries = "vectors";
+        };
+      };
+
+    testScript = ''
+      def check_count(statement, lines):
+          return 'test $(sudo -u postgres psql postgres -tAc "{}"|wc -l) -eq {}'.format(
+              statement, lines
+          )
+
+
+      machine.start()
+      machine.wait_for_unit("postgresql")
+
+      with subtest("Postgresql with extension vectors is available just after unit start"):
+          machine.succeed(check_count("SELECT * FROM pg_available_extensions WHERE name = 'vectors' AND default_version = '${postgresql-package.pkgs.pgvecto-rs.version}';", 1))
+
+      machine.succeed("sudo -u postgres psql -f ${test-sql}")
+
+      machine.succeed(check_count("SELECT content, embedding FROM items WHERE to_tsvector('english', content) @@ 'cat & rat'::tsquery;", 2))
+
+      machine.shutdown()
+    '';
+
+  };
+  applicablePostgresqlVersions = filterAttrs (_: value: versionAtLeast value.version "12") postgresql-versions;
+in
+mapAttrs'
+  (name: package: {
+    inherit name;
+    value = make-postgresql-test name package;
+  })
+  applicablePostgresqlVersions
diff --git a/nixos/tests/privoxy.nix b/nixos/tests/privoxy.nix
index 2d95c4522a01..2a18d332c877 100644
--- a/nixos/tests/privoxy.nix
+++ b/nixos/tests/privoxy.nix
@@ -77,6 +77,11 @@ in
     networking.proxy.httpsProxy = "http://localhost:8118";
   };
 
+  nodes.machine_socks4  = { ... }: { services.privoxy = { enable = true; settings.forward-socks4  = "/ 127.0.0.1:9050 ."; }; };
+  nodes.machine_socks4a = { ... }: { services.privoxy = { enable = true; settings.forward-socks4a = "/ 127.0.0.1:9050 ."; }; };
+  nodes.machine_socks5  = { ... }: { services.privoxy = { enable = true; settings.forward-socks5  = "/ 127.0.0.1:9050 ."; }; };
+  nodes.machine_socks5t = { ... }: { services.privoxy = { enable = true; settings.forward-socks5t = "/ 127.0.0.1:9050 ."; }; };
+
   testScript =
     ''
       with subtest("Privoxy is running"):
@@ -109,5 +114,13 @@ in
           machine.systemctl("start systemd-tmpfiles-clean")
           # ...and count again
           machine.succeed("test $(ls /run/privoxy/certs | wc -l) -eq 0")
+
+      with subtest("Privoxy supports socks upstream proxies"):
+          for m in [machine_socks4, machine_socks4a, machine_socks5, machine_socks5t]:
+              m.wait_for_unit("privoxy")
+              m.wait_for_open_port(8118)
+              # We expect a 503 error because the dummy upstream proxy is not reachable.
+              # In issue #265654, instead privoxy segfaulted causing curl to exit with "Empty reply from server".
+              m.succeed("http_proxy=http://localhost:8118 curl -v http://does-not-exist/ 2>&1 | grep 'HTTP/1.1 503'")
     '';
 })
diff --git a/nixos/tests/sanoid.nix b/nixos/tests/sanoid.nix
index 411ebcead9f6..1575634e6284 100644
--- a/nixos/tests/sanoid.nix
+++ b/nixos/tests/sanoid.nix
@@ -115,8 +115,11 @@ in {
     source.systemctl("start --wait syncoid-pool-sanoid.service")
     target.succeed("cat /mnt/pool/sanoid/test.txt")
     source.systemctl("start --wait syncoid-pool-syncoid.service")
+    source.systemctl("start --wait syncoid-pool-syncoid.service")
     target.succeed("cat /mnt/pool/syncoid/test.txt")
 
+    assert(len(source.succeed("zfs list -H -t snapshot pool/syncoid").splitlines()) == 1), "Syncoid should only retain one sync snapshot"
+
     source.systemctl("start --wait syncoid-pool.service")
     target.succeed("[[ -d /mnt/pool/full-pool/syncoid ]]")
 
diff --git a/nixos/tests/systemd-machinectl.nix b/nixos/tests/systemd-machinectl.nix
index b8ed0c33e8e4..02b4d9c590b5 100644
--- a/nixos/tests/systemd-machinectl.nix
+++ b/nixos/tests/systemd-machinectl.nix
@@ -42,8 +42,18 @@ import ./make-test-python.nix ({ pkgs, ... }:
 
       virtualisation.additionalPaths = [ containerSystem ];
 
-      # not needed, but we want to test the nspawn file generation
-      systemd.nspawn.${containerName} = { };
+      systemd.tmpfiles.rules = [
+        "d /var/lib/machines/shared-decl 0755 root root - -"
+      ];
+      systemd.nspawn.shared-decl = {
+        execConfig = {
+          Boot = false;
+          Parameters = "${containerSystem}/init";
+        };
+        filesConfig = {
+          BindReadOnly = "/nix/store";
+        };
+      };
 
       systemd.services."systemd-nspawn@${containerName}" = {
         serviceConfig.Environment = [
@@ -52,14 +62,33 @@ import ./make-test-python.nix ({ pkgs, ... }:
         ];
         overrideStrategy = "asDropin";
       };
+
+      # open DHCP for container
+      networking.firewall.extraCommands = ''
+        ${pkgs.iptables}/bin/iptables -A nixos-fw -i ve-+ -p udp -m udp --dport 67 -j nixos-fw-accept
+      '';
     };
 
     testScript = ''
       start_all()
       machine.wait_for_unit("default.target");
 
-      # Install container
+      # Test machinectl start stop of shared-decl
+      machine.succeed("machinectl start shared-decl");
+      machine.wait_until_succeeds("systemctl -M shared-decl is-active default.target");
+      machine.succeed("machinectl stop shared-decl");
+
+      # create containers root
       machine.succeed("mkdir -p ${containerRoot}");
+
+      # start container with shared nix store by using same arguments as for systemd-nspawn@.service
+      machine.succeed("systemd-run systemd-nspawn --machine=${containerName} --network-veth -U --bind-ro=/nix/store ${containerSystem}/init")
+      machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target");
+
+      # Test machinectl stop
+      machine.succeed("machinectl stop ${containerName}");
+
+      # Install container
       # Workaround for nixos-install
       machine.succeed("chmod o+rx /var/lib/machines");
       machine.succeed("nixos-install --root ${containerRoot} --system ${containerSystem} --no-channel-copy --no-root-passwd");
@@ -77,6 +106,12 @@ import ./make-test-python.nix ({ pkgs, ... }:
       # Test nss_mymachines via nscd
       machine.succeed("getent hosts ${containerName}");
 
+      # Test systemd-nspawn network configuration to container
+      machine.succeed("networkctl --json=short status ve-${containerName} | ${pkgs.jq}/bin/jq -e '.OperationalState == \"routable\"'");
+
+      # Test systemd-nspawn network configuration to host
+      machine.succeed("machinectl shell ${containerName} /run/current-system/sw/bin/networkctl --json=short status host0 | ${pkgs.jq}/bin/jq -r '.OperationalState == \"routable\"'");
+
       # Test systemd-nspawn network configuration
       machine.succeed("ping -n -c 1 ${containerName}");
 
diff --git a/nixos/tests/vscodium.nix b/nixos/tests/vscodium.nix
index d817ce927ff8..76d5244b3ee3 100644
--- a/nixos/tests/vscodium.nix
+++ b/nixos/tests/vscodium.nix
@@ -76,4 +76,4 @@ let
     });
 
 in
-builtins.mapAttrs (k: v: mkTest k v { }) tests
+builtins.mapAttrs (k: v: mkTest k v) tests
diff --git a/nixos/tests/web-apps/gotosocial.nix b/nixos/tests/web-apps/gotosocial.nix
index 6d279ab63a79..8c4e76b14e3b 100644
--- a/nixos/tests/web-apps/gotosocial.nix
+++ b/nixos/tests/web-apps/gotosocial.nix
@@ -1,7 +1,7 @@
 { lib, ... }:
 {
   name = "gotosocial";
-  meta.maintainers = with lib.maintainers; [ misuzu ];
+  meta.maintainers = with lib.maintainers; [ misuzu blakesmith ];
 
   nodes.machine = { pkgs, ... }: {
     environment.systemPackages = [ pkgs.jq ];
diff --git a/nixos/tests/web-apps/pretix.nix b/nixos/tests/web-apps/pretix.nix
new file mode 100644
index 000000000000..559316f9b85c
--- /dev/null
+++ b/nixos/tests/web-apps/pretix.nix
@@ -0,0 +1,47 @@
+{
+  lib,
+  pkgs,
+  ...
+}:
+
+{
+  name = "pretix";
+  meta.maintainers = with lib.maintainers; [ hexa ];
+
+  nodes = {
+    pretix = {
+      networking.extraHosts = ''
+        127.0.0.1 tickets.local
+      '';
+
+      services.pretix = {
+        enable = true;
+        nginx.domain = "tickets.local";
+        plugins = with pkgs.pretix.plugins; [
+          passbook
+          pages
+        ];
+        settings = {
+          pretix = {
+            instance_name = "NixOS Test";
+            url = "http://tickets.local";
+          };
+          mail.from = "hello@tickets.local";
+        };
+      };
+    };
+  };
+
+  testScript = ''
+    start_all()
+
+    pretix.wait_for_unit("pretix-web.service")
+    pretix.wait_for_unit("pretix-worker.service")
+
+    pretix.wait_until_succeeds("curl -q --fail http://tickets.local")
+
+    pretix.succeed("pretix-manage --help")
+
+    pretix.log(pretix.succeed("systemd-analyze security pretix-web.service"))
+  '';
+}