about summary refs log tree commit diff
path: root/nixpkgs/nixos
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2021-09-27 16:00:58 +0000
committerAlyssa Ross <hi@alyssa.is>2021-09-27 16:00:58 +0000
commitc504e5d19d940926b3ddcf62c983d66f49f3cbb2 (patch)
treeec955e58bcac2cb93b9f8c10786b23f61d40cd7e /nixpkgs/nixos
parent72789cefce7b17419815f600fbd18238d89afcc9 (diff)
parent1737f98af6667560e3e4f930312f9b5002649d04 (diff)
downloadnixlib-c504e5d19d940926b3ddcf62c983d66f49f3cbb2.tar
nixlib-c504e5d19d940926b3ddcf62c983d66f49f3cbb2.tar.gz
nixlib-c504e5d19d940926b3ddcf62c983d66f49f3cbb2.tar.bz2
nixlib-c504e5d19d940926b3ddcf62c983d66f49f3cbb2.tar.lz
nixlib-c504e5d19d940926b3ddcf62c983d66f49f3cbb2.tar.xz
nixlib-c504e5d19d940926b3ddcf62c983d66f49f3cbb2.tar.zst
nixlib-c504e5d19d940926b3ddcf62c983d66f49f3cbb2.zip
Merge commit '1737f98af6667560e3e4f930312f9b5002649d04'
Conflicts:
	nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
	nixpkgs/pkgs/applications/networking/irc/weechat/scripts/default.nix
	nixpkgs/pkgs/development/node-packages/default.nix
	nixpkgs/pkgs/development/python-modules/priority/deadline.patch
Diffstat (limited to 'nixpkgs/nixos')
-rw-r--r--nixpkgs/nixos/doc/manual/configuration/linux-kernel.chapter.md37
-rw-r--r--nixpkgs/nixos/doc/manual/from_md/configuration/linux-kernel.chapter.xml37
-rw-r--r--nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml205
-rw-r--r--nixpkgs/nixos/doc/manual/release-notes/rl-2111.section.md192
-rw-r--r--nixpkgs/nixos/lib/testing-python.nix105
-rw-r--r--nixpkgs/nixos/modules/config/console.nix6
-rw-r--r--nixpkgs/nixos/modules/config/krb5/default.nix2
-rw-r--r--nixpkgs/nixos/modules/config/malloc.nix14
-rw-r--r--nixpkgs/nixos/modules/config/users-groups.nix12
-rw-r--r--nixpkgs/nixos/modules/config/xdg/mime.nix66
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix2
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-pc.nix2
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix2
-rw-r--r--nixpkgs/nixos/modules/installer/sd-card/sd-image-raspberrypi.nix2
-rw-r--r--nixpkgs/nixos/modules/installer/tools/tools.nix15
-rw-r--r--nixpkgs/nixos/modules/misc/documentation.nix10
-rw-r--r--nixpkgs/nixos/modules/misc/ids.nix80
-rw-r--r--nixpkgs/nixos/modules/module-list.nix11
-rw-r--r--nixpkgs/nixos/modules/programs/atop.nix11
-rw-r--r--nixpkgs/nixos/modules/programs/bandwhich.nix4
-rw-r--r--nixpkgs/nixos/modules/programs/captive-browser.nix4
-rw-r--r--nixpkgs/nixos/modules/programs/ccache.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/firejail.nix7
-rw-r--r--nixpkgs/nixos/modules/programs/gamemode.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/iftop.nix4
-rw-r--r--nixpkgs/nixos/modules/programs/iotop.nix4
-rw-r--r--nixpkgs/nixos/modules/programs/kbdlight.nix7
-rw-r--r--nixpkgs/nixos/modules/programs/liboping.nix4
-rw-r--r--nixpkgs/nixos/modules/programs/msmtp.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/mtr.nix4
-rw-r--r--nixpkgs/nixos/modules/programs/noisetorch.nix4
-rw-r--r--nixpkgs/nixos/modules/programs/pantheon-tweaks.nix19
-rw-r--r--nixpkgs/nixos/modules/programs/plotinus.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/shadow.nix21
-rw-r--r--nixpkgs/nixos/modules/programs/singularity.nix7
-rw-r--r--nixpkgs/nixos/modules/programs/slock.nix7
-rw-r--r--nixpkgs/nixos/modules/programs/ssmtp.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/traceroute.nix4
-rw-r--r--nixpkgs/nixos/modules/programs/udevil.nix7
-rw-r--r--nixpkgs/nixos/modules/programs/wavemon.nix4
-rw-r--r--nixpkgs/nixos/modules/programs/weylus.nix47
-rw-r--r--nixpkgs/nixos/modules/programs/wshowkeys.nix7
-rw-r--r--nixpkgs/nixos/modules/security/chromium-suid-sandbox.nix7
-rw-r--r--nixpkgs/nixos/modules/security/doas.nix9
-rw-r--r--nixpkgs/nixos/modules/security/duosec.nix7
-rw-r--r--nixpkgs/nixos/modules/security/lock-kernel-modules.nix28
-rw-r--r--nixpkgs/nixos/modules/security/pam.nix5
-rw-r--r--nixpkgs/nixos/modules/security/pam_usb.nix14
-rw-r--r--nixpkgs/nixos/modules/security/polkit.nix14
-rw-r--r--nixpkgs/nixos/modules/security/rtkit.nix5
-rw-r--r--nixpkgs/nixos/modules/security/tpm2.nix3
-rw-r--r--nixpkgs/nixos/modules/security/wrappers/default.nix282
-rw-r--r--nixpkgs/nixos/modules/services/backup/automysqlbackup.nix1
-rw-r--r--nixpkgs/nixos/modules/services/backup/borgbackup.nix1
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix43
-rw-r--r--nixpkgs/nixos/modules/services/cluster/spark/default.nix162
-rw-r--r--nixpkgs/nixos/modules/services/databases/influxdb.nix1
-rw-r--r--nixpkgs/nixos/modules/services/databases/memcached.nix2
-rw-r--r--nixpkgs/nixos/modules/services/databases/mongodb.nix4
-rw-r--r--nixpkgs/nixos/modules/services/databases/neo4j.nix4
-rw-r--r--nixpkgs/nixos/modules/services/databases/redis.nix1
-rw-r--r--nixpkgs/nixos/modules/services/desktops/cpupower-gui.nix56
-rw-r--r--nixpkgs/nixos/modules/services/desktops/gnome/gnome-keyring.nix4
-rw-r--r--nixpkgs/nixos/modules/services/desktops/gsignond.nix2
-rw-r--r--nixpkgs/nixos/modules/services/desktops/pipewire/bluez-hardware.conf.json41
-rw-r--r--nixpkgs/nixos/modules/services/display-managers/greetd.nix7
-rw-r--r--nixpkgs/nixos/modules/services/games/minecraft-server.nix4
-rw-r--r--nixpkgs/nixos/modules/services/hardware/tcsd.nix6
-rw-r--r--nixpkgs/nixos/modules/services/logging/graylog.nix4
-rw-r--r--nixpkgs/nixos/modules/services/logging/logcheck.nix6
-rw-r--r--nixpkgs/nixos/modules/services/mail/exim.nix7
-rw-r--r--nixpkgs/nixos/modules/services/mail/mail.nix3
-rw-r--r--nixpkgs/nixos/modules/services/mail/opensmtpd.nix5
-rw-r--r--nixpkgs/nixos/modules/services/mail/postfix.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/airsonic.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/apache-kafka.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/cgminer.nix8
-rw-r--r--nixpkgs/nixos/modules/services/misc/docker-registry.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/etcd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/gammu-smsd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/gitlab.nix49
-rw-r--r--nixpkgs/nixos/modules/services/misc/gpsd.nix1
-rw-r--r--nixpkgs/nixos/modules/services/misc/home-assistant.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/mame.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/nix-ssh-serve.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/owncast.nix98
-rw-r--r--nixpkgs/nixos/modules/services/misc/ripple-data-api.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/rippled.nix8
-rw-r--r--nixpkgs/nixos/modules/services/misc/safeeyes.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/weechat.nix7
-rw-r--r--nixpkgs/nixos/modules/services/misc/zookeeper.nix4
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix6
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/graphite.nix1
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/heapster.nix4
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/incron.nix7
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/netdata.nix74
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/parsedmarc.md113
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/parsedmarc.nix537
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/parsedmarc.xml125
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/tuptime.nix1
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix7
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/orangefs/server.nix5
-rw-r--r--nixpkgs/nixos/modules/services/networking/bind.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/consul.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/coturn.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/dhcpd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/dnsmasq.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/flannel.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/git-daemon.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/iodine.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/morty.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/ncdns.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/networkmanager.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/ngircd.nix5
-rw-r--r--nixpkgs/nixos/modules/services/networking/nntp-proxy.nix14
-rw-r--r--nixpkgs/nixos/modules/services/networking/ntp/ntpd.nix12
-rw-r--r--nixpkgs/nixos/modules/services/networking/ntp/openntpd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/pleroma.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/pleroma.xml298
-rw-r--r--nixpkgs/nixos/modules/services/networking/radicale.nix7
-rw-r--r--nixpkgs/nixos/modules/services/networking/radvd.nix5
-rw-r--r--nixpkgs/nixos/modules/services/networking/rdnssd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/shout.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/smokeping.nix13
-rw-r--r--nixpkgs/nixos/modules/services/networking/ssh/sshd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/tinydns.nix6
-rw-r--r--nixpkgs/nixos/modules/services/networking/tox-bootstrapd.nix21
-rw-r--r--nixpkgs/nixos/modules/services/networking/toxvpn.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/tvheadend.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/unifi.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/vsftpd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/x2goserver.nix2
-rw-r--r--nixpkgs/nixos/modules/services/scheduling/atd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/scheduling/cron.nix7
-rw-r--r--nixpkgs/nixos/modules/services/scheduling/fcron.nix3
-rw-r--r--nixpkgs/nixos/modules/services/search/elasticsearch.nix15
-rw-r--r--nixpkgs/nixos/modules/services/search/kibana.nix4
-rw-r--r--nixpkgs/nixos/modules/services/search/meilisearch.md39
-rw-r--r--nixpkgs/nixos/modules/services/search/meilisearch.nix132
-rw-r--r--nixpkgs/nixos/modules/services/search/meilisearch.xml85
-rw-r--r--nixpkgs/nixos/modules/services/security/hockeypuck.nix2
-rw-r--r--nixpkgs/nixos/modules/services/security/opensnitch.nix24
-rw-r--r--nixpkgs/nixos/modules/services/security/physlock.nix10
-rw-r--r--nixpkgs/nixos/modules/services/security/tor.nix2
-rw-r--r--nixpkgs/nixos/modules/services/system/kerberos/heimdal.nix2
-rw-r--r--nixpkgs/nixos/modules/services/system/localtime.nix2
-rw-r--r--nixpkgs/nixos/modules/services/torrent/magnetico.nix2
-rw-r--r--nixpkgs/nixos/modules/services/torrent/peerflix.nix6
-rw-r--r--nixpkgs/nixos/modules/services/ttys/getty.nix8
-rw-r--r--nixpkgs/nixos/modules/services/video/replay-sorcery.nix4
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/discourse.nix32
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/dokuwiki.nix595
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/mastodon.nix35
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/node-red.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/wordpress.nix29
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/trafficserver/default.nix (renamed from nixpkgs/nixos/modules/services/web-servers/trafficserver.nix)16
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/trafficserver/ip_allow.json36
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/trafficserver/logging.json37
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/zope2.nix6
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/cde.nix5
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/enlightenment.nix21
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/gnome.nix2
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix28
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.xml10
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix24
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix4
-rw-r--r--nixpkgs/nixos/modules/services/x11/extra-layouts.nix52
-rw-r--r--nixpkgs/nixos/modules/services/x11/hardware/libinput.nix11
-rw-r--r--nixpkgs/nixos/modules/services/x11/touchegg.nix38
-rw-r--r--nixpkgs/nixos/modules/services/x11/xserver.nix3
-rw-r--r--nixpkgs/nixos/modules/system/activation/activation-script.nix14
-rw-r--r--nixpkgs/nixos/modules/system/activation/top-level.nix4
-rw-r--r--nixpkgs/nixos/modules/system/boot/kernel.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/networkd.nix9
-rw-r--r--nixpkgs/nixos/modules/system/boot/systemd.nix16
-rw-r--r--nixpkgs/nixos/modules/system/boot/tmp.nix17
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/ecryptfs.nix14
-rw-r--r--nixpkgs/nixos/modules/tasks/network-interfaces.nix9
-rw-r--r--nixpkgs/nixos/modules/virtualisation/containerd.nix7
-rw-r--r--nixpkgs/nixos/modules/virtualisation/libvirtd.nix3
-rw-r--r--nixpkgs/nixos/modules/virtualisation/lxd.nix2
-rw-r--r--nixpkgs/nixos/modules/virtualisation/qemu-vm.nix2
-rw-r--r--nixpkgs/nixos/modules/virtualisation/spice-usb-redirection.nix6
-rw-r--r--nixpkgs/nixos/modules/virtualisation/vmware-guest.nix22
-rw-r--r--nixpkgs/nixos/tests/all-tests.nix7
-rw-r--r--nixpkgs/nixos/tests/atop.nix2
-rw-r--r--nixpkgs/nixos/tests/cntr.nix2
-rw-r--r--nixpkgs/nixos/tests/disable-installer-tools.nix29
-rw-r--r--nixpkgs/nixos/tests/dokuwiki.nix85
-rw-r--r--nixpkgs/nixos/tests/ec2.nix5
-rw-r--r--nixpkgs/nixos/tests/enlightenment.nix4
-rw-r--r--nixpkgs/nixos/tests/hardened.nix5
-rw-r--r--nixpkgs/nixos/tests/herbstluftwm.nix1
-rw-r--r--nixpkgs/nixos/tests/kerberos/heimdal.nix2
-rw-r--r--nixpkgs/nixos/tests/meilisearch.nix60
-rw-r--r--nixpkgs/nixos/tests/minio.nix5
-rw-r--r--nixpkgs/nixos/tests/mpv.nix2
-rw-r--r--nixpkgs/nixos/tests/mysql/mariadb-galera-mariabackup.nix16
-rw-r--r--nixpkgs/nixos/tests/mysql/mariadb-galera-rsync.nix16
-rw-r--r--nixpkgs/nixos/tests/mysql/mysql.nix36
-rw-r--r--nixpkgs/nixos/tests/owncast.nix21
-rw-r--r--nixpkgs/nixos/tests/pantheon.nix10
-rw-r--r--nixpkgs/nixos/tests/parsedmarc/default.nix224
-rw-r--r--nixpkgs/nixos/tests/postfixadmin.nix2
-rw-r--r--nixpkgs/nixos/tests/prometheus-exporters.nix7
-rw-r--r--nixpkgs/nixos/tests/run-in-machine.nix23
-rw-r--r--nixpkgs/nixos/tests/spark/default.nix28
-rw-r--r--nixpkgs/nixos/tests/spark/spark_sample.py40
-rw-r--r--nixpkgs/nixos/tests/systemd-confinement.nix38
-rw-r--r--nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix2
-rw-r--r--nixpkgs/nixos/tests/tigervnc.nix2
-rw-r--r--nixpkgs/nixos/tests/unbound.nix11
-rw-r--r--nixpkgs/nixos/tests/user-activation-scripts.nix33
-rw-r--r--nixpkgs/nixos/tests/wasabibackend.nix2
-rw-r--r--nixpkgs/nixos/tests/wordpress.nix18
216 files changed, 4286 insertions, 1174 deletions
diff --git a/nixpkgs/nixos/doc/manual/configuration/linux-kernel.chapter.md b/nixpkgs/nixos/doc/manual/configuration/linux-kernel.chapter.md
index aad6d49c72c3..1d06543d4f1e 100644
--- a/nixpkgs/nixos/doc/manual/configuration/linux-kernel.chapter.md
+++ b/nixpkgs/nixos/doc/manual/configuration/linux-kernel.chapter.md
@@ -5,13 +5,18 @@ option `boot.kernelPackages`. For instance, this selects the Linux 3.10
 kernel:
 
 ```nix
-boot.kernelPackages = pkgs.linuxPackages_3_10;
+boot.kernelPackages = pkgs.linuxKernel.packages.linux_3_10;
 ```
 
 Note that this not only replaces the kernel, but also packages that are
 specific to the kernel version, such as the NVIDIA video drivers. This
 ensures that driver packages are consistent with the kernel.
 
+While `pkgs.linuxKernel.packages` contains all available kernel packages,
+you may want to use one of the unversioned `pkgs.linuxPackages_*` aliases
+such as `pkgs.linuxPackages_latest`, that are kept up to date with new
+versions.
+
 The default Linux kernel configuration should be fine for most users.
 You can see the configuration of your current kernel with the following
 command:
@@ -25,14 +30,13 @@ If you want to change the kernel configuration, you can use the
 instance, to enable support for the kernel debugger KGDB:
 
 ```nix
-nixpkgs.config.packageOverrides = pkgs:
-  { linux_3_4 = pkgs.linux_3_4.override {
-      extraConfig =
-        ''
-          KGDB y
-        '';
-    };
+nixpkgs.config.packageOverrides = pkgs: pkgs.lib.recursiveUpdate pkgs {
+  linuxKernel.kernels.linux_5_10 = pkgs.linuxKernel.kernels.linux_5_10.override {
+    extraConfig = ''
+      KGDB y
+    '';
   };
+};
 ```
 
 `extraConfig` takes a list of Linux kernel configuration options, one
@@ -72,16 +76,17 @@ available parameters, run `sysctl -a`.
 
 The first step before compiling the kernel is to generate an appropriate
 `.config` configuration. Either you pass your own config via the
-`configfile` setting of `linuxManualConfig`:
+`configfile` setting of `linuxKernel.manualConfig`:
 
 ```nix
-custom-kernel = super.linuxManualConfig {
-  inherit (super) stdenv hostPlatform;
-  inherit (linux_4_9) src;
-  version = "${linux_4_9.version}-custom";
-
-  configfile = /home/me/my_kernel_config;
-  allowImportFromDerivation = true;
+custom-kernel = let base_kernel = linuxKernel.kernels.linux_4_9;
+  in super.linuxKernel.manualConfig {
+    inherit (super) stdenv hostPlatform;
+    inherit (base_kernel) src;
+    version = "${base_kernel.version}-custom";
+
+    configfile = /home/me/my_kernel_config;
+    allowImportFromDerivation = true;
 };
 ```
 
diff --git a/nixpkgs/nixos/doc/manual/from_md/configuration/linux-kernel.chapter.xml b/nixpkgs/nixos/doc/manual/from_md/configuration/linux-kernel.chapter.xml
index f804d0a3b8c2..a1d6815af29c 100644
--- a/nixpkgs/nixos/doc/manual/from_md/configuration/linux-kernel.chapter.xml
+++ b/nixpkgs/nixos/doc/manual/from_md/configuration/linux-kernel.chapter.xml
@@ -6,7 +6,7 @@
     selects the Linux 3.10 kernel:
   </para>
   <programlisting language="bash">
-boot.kernelPackages = pkgs.linuxPackages_3_10;
+boot.kernelPackages = pkgs.linuxKernel.packages.linux_3_10;
 </programlisting>
   <para>
     Note that this not only replaces the kernel, but also packages that
@@ -15,6 +15,13 @@ boot.kernelPackages = pkgs.linuxPackages_3_10;
     kernel.
   </para>
   <para>
+    While <literal>pkgs.linuxKernel.packages</literal> contains all
+    available kernel packages, you may want to use one of the
+    unversioned <literal>pkgs.linuxPackages_*</literal> aliases such as
+    <literal>pkgs.linuxPackages_latest</literal>, that are kept up to
+    date with new versions.
+  </para>
+  <para>
     The default Linux kernel configuration should be fine for most
     users. You can see the configuration of your current kernel with the
     following command:
@@ -29,14 +36,13 @@ zcat /proc/config.gz
     enable support for the kernel debugger KGDB:
   </para>
   <programlisting language="bash">
-nixpkgs.config.packageOverrides = pkgs:
-  { linux_3_4 = pkgs.linux_3_4.override {
-      extraConfig =
-        ''
-          KGDB y
-        '';
-    };
+nixpkgs.config.packageOverrides = pkgs: pkgs.lib.recursiveUpdate pkgs {
+  linuxKernel.kernels.linux_5_10 = pkgs.linuxKernel.kernels.linux_5_10.override {
+    extraConfig = ''
+      KGDB y
+    '';
   };
+};
 </programlisting>
   <para>
     <literal>extraConfig</literal> takes a list of Linux kernel
@@ -82,16 +88,17 @@ boot.kernel.sysctl.&quot;net.ipv4.tcp_keepalive_time&quot; = 120;
       The first step before compiling the kernel is to generate an
       appropriate <literal>.config</literal> configuration. Either you
       pass your own config via the <literal>configfile</literal> setting
-      of <literal>linuxManualConfig</literal>:
+      of <literal>linuxKernel.manualConfig</literal>:
     </para>
     <programlisting language="bash">
-custom-kernel = super.linuxManualConfig {
-  inherit (super) stdenv hostPlatform;
-  inherit (linux_4_9) src;
-  version = &quot;${linux_4_9.version}-custom&quot;;
+custom-kernel = let base_kernel = linuxKernel.kernels.linux_4_9;
+  in super.linuxKernel.manualConfig {
+    inherit (super) stdenv hostPlatform;
+    inherit (base_kernel) src;
+    version = &quot;${base_kernel.version}-custom&quot;;
 
-  configfile = /home/me/my_kernel_config;
-  allowImportFromDerivation = true;
+    configfile = /home/me/my_kernel_config;
+    allowImportFromDerivation = true;
 };
 </programlisting>
     <para>
diff --git a/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml b/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
index b18e29191470..8af8f1dd6437 100644
--- a/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
+++ b/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
@@ -39,6 +39,13 @@
       </listitem>
       <listitem>
         <para>
+          spark now defaults to spark 3, updated from 2. A
+          <link xlink:href="https://spark.apache.org/docs/latest/core-migration-guide.html#upgrading-from-core-24-to-30">migration
+          guide</link> is available.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           Activation scripts can now opt int to be run when running
           <literal>nixos-rebuild dry-activate</literal> and detect the
           dry activation by reading <literal>$NIXOS_ACTION</literal>.
@@ -48,6 +55,32 @@
           actions.
         </para>
       </listitem>
+      <listitem>
+        <para>
+          bash now defaults to major version 5.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Systemd was updated to version 249 (from 247).
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Pantheon desktop has been updated to version 6. Due to changes
+          of screen locker, if locking doesn’t work for you, please try
+          <literal>gsettings set org.gnome.desktop.lockdown disable-lock-screen false</literal>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          <literal>kubernetes-helm</literal> now defaults to 3.7.0,
+          which introduced some breaking changes to the experimental OCI
+          manifest format. See
+          <link xlink:href="https://github.com/helm/community/blob/main/hips/hip-0006.md">HIP
+          6</link> for more details.
+        </para>
+      </listitem>
     </itemizedlist>
   </section>
   <section xml:id="sec-release-21.11-new-services">
@@ -85,6 +118,13 @@
       </listitem>
       <listitem>
         <para>
+          <link xlink:href="https://owncast.online/">owncast</link>,
+          self-hosted video live streaming solution. Available at
+          <link xlink:href="options.html#opt-services.owncast">services.owncast</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           <link xlink:href="https://sr.ht">sourcehut</link>, a
           collection of tools useful for software development. Available
           as
@@ -116,6 +156,13 @@
       </listitem>
       <listitem>
         <para>
+          <link xlink:href="https://github.com/evilsocket/opensnitch">opensnitch</link>,
+          an application firewall. Available as
+          <link linkend="opt-services.opensnitch.enable">services.opensnitch</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           <link xlink:href="https://www.snapraid.it/">snapraid</link>, a
           backup program for disk arrays. Available as
           <link linkend="opt-snapraid.enable">snapraid</link>.
@@ -182,8 +229,6 @@
           <link linkend="opt-services.isso.enable">isso</link>
         </para>
       </listitem>
-    </itemizedlist>
-    <itemizedlist spacing="compact">
       <listitem>
         <para>
           <link xlink:href="https://www.navidrome.org/">navidrome</link>,
@@ -192,8 +237,6 @@
           <link linkend="opt-services.navidrome.enable">navidrome</link>.
         </para>
       </listitem>
-    </itemizedlist>
-    <itemizedlist>
       <listitem>
         <para>
           <link xlink:href="https://docs.fluidd.xyz/">fluidd</link>, a
@@ -239,6 +282,37 @@
           <link xlink:href="options.html#opt-programs.git.enable">programs.git</link>.
         </para>
       </listitem>
+      <listitem>
+        <para>
+          <link xlink:href="https://domainaware.github.io/parsedmarc/">parsedmarc</link>,
+          a service which parses incoming
+          <link xlink:href="https://dmarc.org/">DMARC</link> reports and
+          stores or sends them to a downstream service for further
+          analysis. Documented in
+          <link linkend="module-services-parsedmarc">its manual
+          entry</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          <link xlink:href="https://spark.apache.org/">spark</link>, a
+          unified analytics engine for large-scale data processing.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          <link xlink:href="https://github.com/JoseExposito/touchegg">touchegg</link>,
+          a multi-touch gesture recognizer. Available as
+          <link linkend="opt-services.touchegg.enable">services.touchegg</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          <link xlink:href="https://github.com/pantheon-tweaks/pantheon-tweaks">pantheon-tweaks</link>,
+          an unofficial system settings panel for Pantheon. Available as
+          <link linkend="opt-programs.pantheon-tweaks.enable">programs.pantheon-tweaks</link>.
+        </para>
+      </listitem>
     </itemizedlist>
   </section>
   <section xml:id="sec-release-21.11-incompatibilities">
@@ -246,6 +320,16 @@
     <itemizedlist>
       <listitem>
         <para>
+          The <literal>security.wrappers</literal> option now requires
+          to always specify an owner, group and whether the
+          setuid/setgid bit should be set. This is motivated by the fact
+          that before NixOS 21.11, specifying either setuid or setgid
+          but not owner/group resulted in wrappers owned by
+          nobody/nogroup, which is unsafe.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           The <literal>paperless</literal> module and package have been
           removed. All users should migrate to the successor
           <literal>paperless-ng</literal> instead. The Paperless project
@@ -358,6 +442,33 @@ Superuser created successfully.
       </listitem>
       <listitem>
         <para>
+          <link xlink:href="options.html#opt-users.users._name_.group">users.users.&lt;name&gt;.group</link>
+          no longer defaults to <literal>nogroup</literal>, which was
+          insecure. Out-of-tree modules are likely to require
+          adaptation: instead of
+        </para>
+        <programlisting language="bash">
+{
+  users.users.foo = {
+    isSystemUser = true;
+  };
+}
+</programlisting>
+        <para>
+          also create a group for your user:
+        </para>
+        <programlisting language="bash">
+{
+  users.users.foo = {
+    isSystemUser = true;
+    group = &quot;foo&quot;;
+  };
+  users.groups.foo = {};
+}
+</programlisting>
+      </listitem>
+      <listitem>
+        <para>
           <literal>services.geoip-updater</literal> was broken and has
           been replaced by
           <link xlink:href="options.html#opt-services.geoipupdate.enable">services.geoipupdate</link>.
@@ -927,6 +1038,19 @@ Superuser created successfully.
           file</link> format.
         </para>
       </listitem>
+      <listitem>
+        <para>
+          The <literal>datadog-agent</literal>,
+          <literal>datadog-integrations-core</literal> and
+          <literal>datadog-process-agent</literal> packages were
+          upgraded from 6.11.2 to 7.30.2, git-2018-09-18 to 7.30.1 and
+          6.11.1 to 7.30.2, respectively. As a result
+          <literal>services.datadog-agent</literal> has had breaking
+          changes to the configuration file. For details, see the
+          <link xlink:href="https://github.com/DataDog/datadog-agent/blob/main/CHANGELOG.rst">upstream
+          changelog</link>.
+        </para>
+      </listitem>
     </itemizedlist>
   </section>
   <section xml:id="sec-release-21.11-notable-changes">
@@ -934,6 +1058,20 @@ Superuser created successfully.
     <itemizedlist>
       <listitem>
         <para>
+          The linux kernel package infrastructure was moved out of
+          <literal>all-packages.nix</literal>, and restructured. Linux
+          related functions and attributes now live under the
+          <literal>pkgs.linuxKernel</literal> attribute set. In
+          particular the versioned <literal>linuxPackages_*</literal>
+          package sets (such as <literal>linuxPackages_5_4</literal>)
+          and kernels from <literal>pkgs</literal> were moved there and
+          now live under <literal>pkgs.linuxKernel.packages.*</literal>.
+          The unversioned ones (such as
+          <literal>linuxPackages_latest</literal>) remain untouched.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           The setting
           <link xlink:href="options.html#opt-services.openssh.logLevel"><literal>services.openssh.logLevel</literal></link>
           <literal>&quot;VERBOSE&quot;</literal>
@@ -953,6 +1091,14 @@ Superuser created successfully.
       </listitem>
       <listitem>
         <para>
+          The
+          <link xlink:href="options.html#opt-services.xserver.extraLayouts"><literal>services.xserver.extraLayouts</literal></link>
+          no longer cause additional rebuilds when a layout is added or
+          modified.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           Sway: The terminal emulator <literal>rxvt-unicode</literal> is
           no longer installed by default via
           <literal>programs.sway.extraPackages</literal>. The current
@@ -991,8 +1137,8 @@ Superuser created successfully.
           The wordpress module provides a new interface which allows to
           use different webservers with the new option
           <link xlink:href="options.html#opt-services.wordpress.webserver"><literal>services.wordpress.webserver</literal></link>.
-          Currently <literal>httpd</literal> and
-          <literal>nginx</literal> are supported. The definitions of
+          Currently <literal>httpd</literal>, <literal>caddy</literal>
+          and <literal>nginx</literal> are supported. The definitions of
           wordpress sites should now be set in
           <link xlink:href="options.html#opt-services.wordpress.sites"><literal>services.wordpress.sites</literal></link>.
         </para>
@@ -1004,6 +1150,22 @@ Superuser created successfully.
       </listitem>
       <listitem>
         <para>
+          The dokuwiki module provides a new interface which allows to
+          use different webservers with the new option
+          <link xlink:href="options.html#opt-services.dokuwiki.webserver"><literal>services.dokuwiki.webserver</literal></link>.
+          Currently <literal>caddy</literal> and
+          <literal>nginx</literal> are supported. The definitions of
+          dokuwiki sites should now be set in
+          <link xlink:href="options.html#opt-services.dokuwiki.sites"><literal>services.dokuwiki.sites</literal></link>.
+        </para>
+        <para>
+          Sites definitions that use the old interface are automatically
+          migrated in the new option. This backward compatibility will
+          be removed in 22.05.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           The order of NSS (host) modules has been brought in line with
           upstream recommendations:
         </para>
@@ -1122,6 +1284,24 @@ Superuser created successfully.
       </listitem>
       <listitem>
         <para>
+          MariaDB was upgraded from 10.5.x to 10.6.x. Please read the
+          <link xlink:href="https://mariadb.com/kb/en/changes-improvements-in-mariadb-106/">upstream
+          release notes</link> for changes and upgrade instructions.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          The MariaDB C client library, also known as libmysqlclient or
+          mariadb-connector-c, was upgraded from 3.1.x to 3.2.x. While
+          this should hopefully not have any impact, this upgrade comes
+          with some changes to default behavior, so you might want to
+          review the
+          <link xlink:href="https://mariadb.com/kb/en/changes-and-improvements-in-mariadb-connector-c-32/">upstream
+          release notes</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           GNOME desktop environment now enables
           <literal>QGnomePlatform</literal> as the Qt platform theme,
           which should avoid crashes when opening file chooser dialogs
@@ -1157,6 +1337,19 @@ Superuser created successfully.
           directories, thus increasing the purity of the build.
         </para>
       </listitem>
+      <listitem>
+        <para>
+          Three new options,
+          <link linkend="opt-xdg.mime.addedAssociations">xdg.mime.addedAssociations</link>,
+          <link linkend="opt-xdg.mime.defaultApplications">xdg.mime.defaultApplications</link>,
+          and
+          <link linkend="opt-xdg.mime.removedAssociations">xdg.mime.removedAssociations</link>
+          have been added to the
+          <link linkend="opt-xdg.mime.enable">xdg.mime</link> module to
+          allow the configuration of
+          <literal>/etc/xdg/mimeapps.list</literal>.
+        </para>
+      </listitem>
     </itemizedlist>
   </section>
 </section>
diff --git a/nixpkgs/nixos/doc/manual/release-notes/rl-2111.section.md b/nixpkgs/nixos/doc/manual/release-notes/rl-2111.section.md
index 3dc15449c772..f22a532972be 100644
--- a/nixpkgs/nixos/doc/manual/release-notes/rl-2111.section.md
+++ b/nixpkgs/nixos/doc/manual/release-notes/rl-2111.section.md
@@ -14,21 +14,33 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - PostgreSQL now defaults to major version 13.
 
+- spark now defaults to spark 3, updated from 2. A [migration guide](https://spark.apache.org/docs/latest/core-migration-guide.html#upgrading-from-core-24-to-30) is available.
+
 - Activation scripts can now opt int to be run when running `nixos-rebuild dry-activate` and detect the dry activation by reading `$NIXOS_ACTION`.
   This allows activation scripts to output what they would change if the activation was really run.
   The users/modules activation script supports this and outputs some of is actions.
 
+- bash now defaults to major version 5.
+
+- Systemd was updated to version 249 (from 247).
+
+- Pantheon desktop has been updated to version 6. Due to changes of screen locker, if locking doesn't work for you, please try `gsettings set org.gnome.desktop.lockdown disable-lock-screen false`.
+
+- `kubernetes-helm` now defaults to 3.7.0, which introduced some breaking changes to the experimental OCI manifest format. See [HIP 6](https://github.com/helm/community/blob/main/hips/hip-0006.md) for more details.
+
 ## New Services {#sec-release-21.11-new-services}
 
 - [btrbk](https://digint.ch/btrbk/index.html), a backup tool for btrfs subvolumes, taking advantage of btrfs specific capabilities to create atomic snapshots and transfer them incrementally to your backup locations. Available as [services.btrbk](options.html#opt-services.brtbk.instances).
 
 - [clipcat](https://github.com/xrelkd/clipcat/), an X11 clipboard manager written in Rust. Available at [services.clipcat](options.html#o
-pt-services.clipcat.enable).
+  pt-services.clipcat.enable).
 
 - [geoipupdate](https://github.com/maxmind/geoipupdate), a GeoIP database updater from MaxMind. Available as [services.geoipupdate](options.html#opt-services.geoipupdate.enable).
 
 - [Kea](https://www.isc.org/kea/), ISCs 2nd generation DHCP and DDNS server suite. Available at [services.kea](options.html#opt-services.kea).
 
+- [owncast](https://owncast.online/), self-hosted video live streaming solution. Available at [services.owncast](options.html#opt-services.owncast).
+
 - [sourcehut](https://sr.ht), a collection of tools useful for software development. Available as [services.sourcehut](options.html#opt-services.sourcehut.enable).
 
 - [ucarp](https://download.pureftpd.org/pub/ucarp/README), an userspace implementation of the Common Address Redundancy Protocol (CARP). Available as [networking.ucarp](options.html#opt-networking.ucarp.enable).
@@ -37,6 +49,8 @@ pt-services.clipcat.enable).
 
 - [vikunja](https://vikunja.io), a to-do list app. Available as [services.vikunja](#opt-services.vikunja.enable).
 
+- [opensnitch](https://github.com/evilsocket/opensnitch), an application firewall. Available as [services.opensnitch](#opt-services.opensnitch.enable).
+
 - [snapraid](https://www.snapraid.it/), a backup program for disk arrays.
   Available as [snapraid](#opt-snapraid.enable).
 
@@ -58,8 +72,8 @@ pt-services.clipcat.enable).
 - [isso](https://posativ.org/isso/), a commenting server similar to Disqus.
   Available as [isso](#opt-services.isso.enable)
 
-* [navidrome](https://www.navidrome.org/), a personal music streaming server with
-subsonic-compatible api. Available as [navidrome](#opt-services.navidrome.enable).
+- [navidrome](https://www.navidrome.org/), a personal music streaming server with
+  subsonic-compatible api. Available as [navidrome](#opt-services.navidrome.enable).
 
 - [fluidd](https://docs.fluidd.xyz/), a Klipper web interface for managing 3d printers using moonraker. Available as [fluidd](#opt-services.fluidd.enable).
 
@@ -73,8 +87,21 @@ subsonic-compatible api. Available as [navidrome](#opt-services.navidrome.enable
 
 - [git](https://git-scm.com), a distributed version control system. Available as [programs.git](options.html#opt-programs.git.enable).
 
+- [parsedmarc](https://domainaware.github.io/parsedmarc/), a service
+  which parses incoming [DMARC](https://dmarc.org/) reports and stores
+  or sends them to a downstream service for further analysis.
+  Documented in [its manual entry](#module-services-parsedmarc).
+
+- [spark](https://spark.apache.org/), a unified analytics engine for large-scale data processing.
+
+- [touchegg](https://github.com/JoseExposito/touchegg), a multi-touch gesture recognizer. Available as [services.touchegg](#opt-services.touchegg.enable).
+
+- [pantheon-tweaks](https://github.com/pantheon-tweaks/pantheon-tweaks), an unofficial system settings panel for Pantheon. Available as [programs.pantheon-tweaks](#opt-programs.pantheon-tweaks.enable).
+
 ## Backward Incompatibilities {#sec-release-21.11-incompatibilities}
 
+- The `security.wrappers` option now requires to always specify an owner, group and whether the setuid/setgid bit should be set.
+  This is motivated by the fact that before NixOS 21.11, specifying either setuid or setgid but not owner/group resulted in wrappers owned by nobody/nogroup, which is unsafe.
 
 - The `paperless` module and package have been removed. All users should migrate to the
   successor `paperless-ng` instead. The Paperless project [has been
@@ -82,46 +109,49 @@ subsonic-compatible api. Available as [navidrome](#opt-services.navidrome.enable
   and advises all users to use `paperless-ng` instead.
 
   Users can use the `services.paperless-ng` module as a replacement while noting the following incompatibilities:
-    - `services.paperless.ocrLanguages` has no replacement. Users should migrate to [`services.paperless-ng.extraConfig`](options.html#opt-services.paperless-ng.extraConfig) instead:
-     ```nix
-     {
-       services.paperless-ng.extraConfig = {
-         # Provide languages as ISO 639-2 codes
-         # separated by a plus (+) sign.
-         # https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
-         PAPERLESS_OCR_LANGUAGE = "deu+eng+jpn"; # German & English & Japanse
-       };
-     }
-     ```
-
-    - If you previously specified `PAPERLESS_CONSUME_MAIL_*` settings in
-      `services.paperless.extraConfig` you should remove those options now. You
-      now *must* define those settings in the admin interface of paperless-ng.
-
-    - Option `services.paperless.manage` no longer exists.
-      Use the script at `${services.paperless-ng.dataDir}/paperless-ng-manage` instead.
-      Note that this script only exists after the `paperless-ng` service has been
-      started at least once.
-
-    - After switching to the new system configuration you should run the Django
-      management command to reindex your documents and optionally create a user,
-      if you don't have one already.
-
-      To do so, enter the data directory (the value of
-      `services.paperless-ng.dataDir`, `/var/lib/paperless` by default), switch
-      to the paperless user and execute the management command like below:
-      ```
-      $ cd /var/lib/paperless
-      $ su paperless -s /bin/sh
-      $ ./paperless-ng-manage document_index reindex
-      # if not already done create a user account, paperless-ng requires a login
-      $ ./paperless-ng-manage createsuperuser
-      Username (leave blank to use 'paperless'): my-user-name
-      Email address: me@example.com
-      Password: **********
-      Password (again): **********
-      Superuser created successfully.
-      ```
+
+  - `services.paperless.ocrLanguages` has no replacement. Users should migrate to [`services.paperless-ng.extraConfig`](options.html#opt-services.paperless-ng.extraConfig) instead:
+
+  ```nix
+  {
+    services.paperless-ng.extraConfig = {
+      # Provide languages as ISO 639-2 codes
+      # separated by a plus (+) sign.
+      # https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
+      PAPERLESS_OCR_LANGUAGE = "deu+eng+jpn"; # German & English & Japanse
+    };
+  }
+  ```
+
+  - If you previously specified `PAPERLESS_CONSUME_MAIL_*` settings in
+    `services.paperless.extraConfig` you should remove those options now. You
+    now _must_ define those settings in the admin interface of paperless-ng.
+
+  - Option `services.paperless.manage` no longer exists.
+    Use the script at `${services.paperless-ng.dataDir}/paperless-ng-manage` instead.
+    Note that this script only exists after the `paperless-ng` service has been
+    started at least once.
+
+  - After switching to the new system configuration you should run the Django
+    management command to reindex your documents and optionally create a user,
+    if you don't have one already.
+
+    To do so, enter the data directory (the value of
+    `services.paperless-ng.dataDir`, `/var/lib/paperless` by default), switch
+    to the paperless user and execute the management command like below:
+
+    ```
+    $ cd /var/lib/paperless
+    $ su paperless -s /bin/sh
+    $ ./paperless-ng-manage document_index reindex
+    # if not already done create a user account, paperless-ng requires a login
+    $ ./paperless-ng-manage createsuperuser
+    Username (leave blank to use 'paperless'): my-user-name
+    Email address: me@example.com
+    Password: **********
+    Password (again): **********
+    Superuser created successfully.
+    ```
 
 - The `staticjinja` package has been upgraded from 1.0.4 to 4.1.0
 
@@ -131,6 +161,25 @@ subsonic-compatible api. Available as [navidrome](#opt-services.navidrome.enable
 
 - The `erigon` ethereum node has moved it's database location in `2021-08-03`, users upgrading must manually move their chaindata (see [release notes](https://github.com/ledgerwatch/erigon/releases/tag/v2021.08.03)).
 
+- [users.users.&lt;name&gt;.group](options.html#opt-users.users._name_.group) no longer defaults to `nogroup`, which was insecure. Out-of-tree modules are likely to require adaptation: instead of
+  ```nix
+  {
+    users.users.foo = {
+      isSystemUser = true;
+    };
+  }
+  ```
+  also create a group for your user:
+  ```nix
+  {
+    users.users.foo = {
+      isSystemUser = true;
+      group = "foo";
+    };
+    users.groups.foo = {};
+  }
+  ```
+
 - `services.geoip-updater` was broken and has been replaced by [services.geoipupdate](options.html#opt-services.geoipupdate.enable).
 
 - PHP 7.3 is no longer supported due to upstream not supporting this version for the entire lifecycle of the 21.11 release.
@@ -199,28 +248,32 @@ subsonic-compatible api. Available as [navidrome](#opt-services.navidrome.enable
 * The `bitwarden_rs` packages and modules were renamed to `vaultwarden`
   [following upstream](https://github.com/dani-garcia/vaultwarden/discussions/1642). More specifically,
 
-  * `pkgs.bitwarden_rs`, `pkgs.bitwarden_rs-sqlite`, `pkgs.bitwarden_rs-mysql` and
+  - `pkgs.bitwarden_rs`, `pkgs.bitwarden_rs-sqlite`, `pkgs.bitwarden_rs-mysql` and
     `pkgs.bitwarden_rs-postgresql` were renamed to `pkgs.vaultwarden`, `pkgs.vaultwarden-sqlite`,
     `pkgs.vaultwarden-mysql` and `pkgs.vaultwarden-postgresql`, respectively.
-    * Old names are preserved as aliases for backwards compatibility, but may be removed in the future.
-    * The `bitwarden_rs` executable was also renamed to `vaultwarden` in all packages.
 
-  * `pkgs.bitwarden_rs-vault` was renamed to `pkgs.vaultwarden-vault`.
-    * `pkgs.bitwarden_rs-vault` is preserved as an alias for backwards compatibility, but may be removed in the future.
-    * The static files were moved from `/usr/share/bitwarden_rs` to `/usr/share/vaultwarden`.
+    - Old names are preserved as aliases for backwards compatibility, but may be removed in the future.
+    - The `bitwarden_rs` executable was also renamed to `vaultwarden` in all packages.
+
+  - `pkgs.bitwarden_rs-vault` was renamed to `pkgs.vaultwarden-vault`.
 
-  * The `services.bitwarden_rs` config module was renamed to `services.vaultwarden`.
-    * `services.bitwarden_rs` is preserved as an alias for backwards compatibility, but may be removed in the future.
+    - `pkgs.bitwarden_rs-vault` is preserved as an alias for backwards compatibility, but may be removed in the future.
+    - The static files were moved from `/usr/share/bitwarden_rs` to `/usr/share/vaultwarden`.
 
-  * `systemd.services.bitwarden_rs`, `systemd.services.backup-bitwarden_rs` and `systemd.timers.backup-bitwarden_rs`
+  - The `services.bitwarden_rs` config module was renamed to `services.vaultwarden`.
+
+    - `services.bitwarden_rs` is preserved as an alias for backwards compatibility, but may be removed in the future.
+
+  - `systemd.services.bitwarden_rs`, `systemd.services.backup-bitwarden_rs` and `systemd.timers.backup-bitwarden_rs`
     were renamed to `systemd.services.vaultwarden`, `systemd.services.backup-vaultwarden` and
     `systemd.timers.backup-vaultwarden`, respectively.
-    * Old names are preserved as aliases for backwards compatibility, but may be removed in the future.
 
-  * `users.users.bitwarden_rs` and `users.groups.bitwarden_rs` were renamed to `users.users.vaultwarden` and
+    - Old names are preserved as aliases for backwards compatibility, but may be removed in the future.
+
+  - `users.users.bitwarden_rs` and `users.groups.bitwarden_rs` were renamed to `users.users.vaultwarden` and
     `users.groups.vaultwarden`, respectively.
 
-  * The data directory remains located at `/var/lib/bitwarden_rs`, for backwards compatibility.
+  - The data directory remains located at `/var/lib/bitwarden_rs`, for backwards compatibility.
 
 - `yggdrasil` was upgraded to a new major release with breaking changes, see [upstream changelog](https://github.com/yggdrasil-network/yggdrasil-go/releases/tag/v0.4.0).
 
@@ -233,6 +286,7 @@ subsonic-compatible api. Available as [navidrome](#opt-services.navidrome.enable
 - `tt-rss` was upgraded to the commit on 2021-06-21, which has breaking changes. If you use `services.tt-rss.extraConfig` you should migrate to the `putenv`-style configuration. See [this Discourse post](https://community.tt-rss.org/t/rip-config-php-hello-classes-config-php/4337) in the tt-rss forums for more details.
 
 - The following Visual Studio Code extensions were renamed to keep the naming convention uniform.
+
   - `bbenoist.Nix` -> `bbenoist.nix`
   - `CoenraadS.bracket-pair-colorizer` -> `coenraads.bracket-pair-colorizer`
   - `golang.Go` -> `golang.go`
@@ -252,12 +306,12 @@ subsonic-compatible api. Available as [navidrome](#opt-services.navidrome.enable
 - The `yambar` package has been split into `yambar` and `yambar-wayland`, corresponding to the xorg and wayland backend respectively. Please switch to `yambar-wayland` if you are on wayland.
 
 - The `services.minio` module gained an additional option `consoleAddress`, that
-configures the address and port the web UI is listening, it defaults to `:9001`.
-To be able to access the web UI this port needs to be opened in the firewall.
+  configures the address and port the web UI is listening, it defaults to `:9001`.
+  To be able to access the web UI this port needs to be opened in the firewall.
 
 - The `varnish` package was upgraded from 6.3.x to 6.5.x. `varnish60` for the last LTS release is also still available.
 
-- The `kubernetes` package was upgraded to 1.22.  The `kubernetes.apiserver.kubeletHttps` option was removed and HTTPS is always used.
+- The `kubernetes` package was upgraded to 1.22. The `kubernetes.apiserver.kubeletHttps` option was removed and HTTPS is always used.
 
 - The attribute `linuxPackages_latest_hardened` was dropped because the hardened patches
   lag behind the upstream kernel which made version bumps harder. If you want to use
@@ -271,12 +325,22 @@ To be able to access the web UI this port needs to be opened in the firewall.
 
 - The `todoman` package was upgraded from 3.9.0 to 4.0.0. This introduces breaking changes in the [configuration file](https://todoman.readthedocs.io/en/stable/configure.html#configuration-file) format.
 
+- The `datadog-agent`, `datadog-integrations-core` and `datadog-process-agent` packages
+  were upgraded from 6.11.2 to 7.30.2, git-2018-09-18 to 7.30.1 and 6.11.1 to 7.30.2,
+  respectively. As a result `services.datadog-agent` has had breaking changes to the
+  configuration file. For details, see the [upstream changelog](https://github.com/DataDog/datadog-agent/blob/main/CHANGELOG.rst).
+
 ## Other Notable Changes {#sec-release-21.11-notable-changes}
 
+- The linux kernel package infrastructure was moved out of `all-packages.nix`, and restructured. Linux related functions and attributes now live under the `pkgs.linuxKernel` attribute set.
+  In particular the versioned `linuxPackages_*` package sets (such as `linuxPackages_5_4`) and kernels from `pkgs` were moved there and now live under `pkgs.linuxKernel.packages.*`. The unversioned ones (such as `linuxPackages_latest`) remain untouched.
+
 - The setting [`services.openssh.logLevel`](options.html#opt-services.openssh.logLevel) `"VERBOSE"` `"INFO"`. This brings NixOS in line with upstream and other Linux distributions, and reduces log spam on servers due to bruteforcing botnets.
 
   However, if [`services.fail2ban.enable`](options.html#opt-services.fail2ban.enable) is `true`, the `fail2ban` will override the verbosity to `"VERBOSE"`, so that `fail2ban` can observe the failed login attempts from the SSH logs.
 
+- The [`services.xserver.extraLayouts`](options.html#opt-services.xserver.extraLayouts) no longer cause additional rebuilds when a layout is added or modified.
+
 - Sway: The terminal emulator `rxvt-unicode` is no longer installed by default via `programs.sway.extraPackages`. The current default configuration uses `alacritty` (and soon `foot`) so this is only an issue when using a customized configuration and not installing `rxvt-unicode` explicitly.
 
 - `python3` now defaults to Python 3.9. Python 3.9 introduces many deprecation warnings, please look at the [What's New In Python 3.9 post](https://docs.python.org/3/whatsnew/3.9.html) for more information.
@@ -285,7 +349,11 @@ To be able to access the web UI this port needs to be opened in the firewall.
 
 - The `claws-mail` package now references the new GTK+ 3 release branch, major version 4. To use the GTK+ 2 releases, one can install the `claws-mail-gtk2` package.
 
-- The wordpress module provides a new interface which allows to use different webservers with the new option [`services.wordpress.webserver`](options.html#opt-services.wordpress.webserver).  Currently `httpd` and `nginx` are supported. The definitions of wordpress sites should now be set in [`services.wordpress.sites`](options.html#opt-services.wordpress.sites).
+- The wordpress module provides a new interface which allows to use different webservers with the new option [`services.wordpress.webserver`](options.html#opt-services.wordpress.webserver).  Currently `httpd`, `caddy` and `nginx` are supported. The definitions of wordpress sites should now be set in [`services.wordpress.sites`](options.html#opt-services.wordpress.sites).
+
+  Sites definitions that use the old interface are automatically migrated in the new option. This backward compatibility will be removed in 22.05.
+
+- The dokuwiki module provides a new interface which allows to use different webservers with the new option [`services.dokuwiki.webserver`](options.html#opt-services.dokuwiki.webserver).  Currently `caddy` and `nginx` are supported. The definitions of dokuwiki sites should now be set in [`services.dokuwiki.sites`](options.html#opt-services.dokuwiki.sites).
 
   Sites definitions that use the old interface are automatically migrated in the new option. This backward compatibility will be removed in 22.05.
 
@@ -323,6 +391,10 @@ To be able to access the web UI this port needs to be opened in the firewall.
 
 - `lib.formats.yaml`'s `generate` will not generate JSON anymore, but instead use more of the YAML-specific syntax.
 
+- MariaDB was upgraded from 10.5.x to 10.6.x. Please read the [upstream release notes](https://mariadb.com/kb/en/changes-improvements-in-mariadb-106/) for changes and upgrade instructions.
+
+- The MariaDB C client library, also known as libmysqlclient or mariadb-connector-c, was upgraded from 3.1.x to 3.2.x. While this should hopefully not have any impact, this upgrade comes with some changes to default behavior, so you might want to review the [upstream release notes](https://mariadb.com/kb/en/changes-and-improvements-in-mariadb-connector-c-32/).
+
 - GNOME desktop environment now enables `QGnomePlatform` as the Qt platform theme, which should avoid crashes when opening file chooser dialogs in Qt apps by using XDG desktop portal. Additionally, it will make the apps fit better visually.
 
 - `rofi` has been updated from '1.6.1' to '1.7.0', one important thing is the removal of the old xresources based configuration setup. Read more [in rofi's changelog](https://github.com/davatorium/rofi/blob/cb12e6fc058f4a0f4f/Changelog#L1).
@@ -331,3 +403,5 @@ To be able to access the web UI this port needs to be opened in the firewall.
 
 - `lua` and `luajit` interpreters have been patched to avoid looking into /usr/lib
   directories, thus increasing the purity of the build.
+
+- Three new options, [xdg.mime.addedAssociations](#opt-xdg.mime.addedAssociations), [xdg.mime.defaultApplications](#opt-xdg.mime.defaultApplications), and [xdg.mime.removedAssociations](#opt-xdg.mime.removedAssociations) have been added to the [xdg.mime](#opt-xdg.mime.enable) module to allow the configuration of `/etc/xdg/mimeapps.list`.
diff --git a/nixpkgs/nixos/lib/testing-python.nix b/nixpkgs/nixos/lib/testing-python.nix
index 43b4f9b159b2..7c8c64211f18 100644
--- a/nixpkgs/nixos/lib/testing-python.nix
+++ b/nixpkgs/nixos/lib/testing-python.nix
@@ -257,105 +257,18 @@ rec {
         inherit test driver driverInteractive nodes;
       };
 
-  runInMachine =
-    { drv
-    , machine
-    , preBuild ? ""
-    , postBuild ? ""
-    , qemu_pkg ? pkgs.qemu_test
-    , ... # ???
-    }:
-    let
-      build-vms = import ./build-vms.nix {
-        inherit system pkgs minimal specialArgs extraConfigurations;
-      };
-
-      vm = build-vms.buildVM { }
-        [
-          machine
-          {
-            key = "run-in-machine";
-            networking.hostName = "client";
-            nix.readOnlyStore = false;
-            virtualisation.writableStore = false;
-          }
-        ];
-
-      buildrunner = writeText "vm-build" ''
-        source $1
-
-        ${coreutils}/bin/mkdir -p $TMPDIR
-        cd $TMPDIR
-
-        exec $origBuilder $origArgs
-      '';
-
-      testScript = ''
-        start_all()
-        client.wait_for_unit("multi-user.target")
-        ${preBuild}
-        client.succeed("env -i ${bash}/bin/bash ${buildrunner} /tmp/xchg/saved-env >&2")
-        ${postBuild}
-        client.succeed("sync") # flush all data before pulling the plug
-      '';
-
-      testDriver = pythonTestDriver { inherit qemu_pkg; };
 
-      vmRunCommand = writeText "vm-run" ''
-        xchg=vm-state-client/xchg
-        ${coreutils}/bin/mkdir $out
-        ${coreutils}/bin/mkdir -p $xchg
+  abortForFunction = functionName: abort ''The ${functionName} function was
+    removed because it is not an essential part of the NixOS testing
+    infrastructure. It had no usage in NixOS or Nixpkgs and it had no designated
+    maintainer. You are free to reintroduce it by documenting it in the manual
+    and adding yourself as maintainer. It was removed in
+    https://github.com/NixOS/nixpkgs/pull/137013
+  '';
 
-        for i in $passAsFile; do
-          i2=''${i}Path
-          _basename=$(${coreutils}/bin/basename ''${!i2})
-          ${coreutils}/bin/cp ''${!i2} $xchg/$_basename
-          eval $i2=/tmp/xchg/$_basename
-          ${coreutils}/bin/ls -la $xchg
-        done
-
-        unset i i2 _basename
-        export | ${gnugrep}/bin/grep -v '^xchg=' > $xchg/saved-env
-        unset xchg
-
-        export tests='${testScript}'
-        ${testDriver}/bin/nixos-test-driver --keep-vm-state ${vm.config.system.build.vm}/bin/run-*-vm
-      ''; # */
-
-    in
-    lib.overrideDerivation drv (attrs: {
-      requiredSystemFeatures = [ "kvm" ];
-      builder = "${bash}/bin/sh";
-      args = [ "-e" vmRunCommand ];
-      origArgs = attrs.args;
-      origBuilder = attrs.builder;
-    });
-
-
-  runInMachineWithX = { require ? [ ], ... } @ args:
-    let
-      client =
-        { ... }:
-        {
-          inherit require;
-          imports = [
-            ../tests/common/auto.nix
-          ];
-          virtualisation.memorySize = 1024;
-          services.xserver.enable = true;
-          test-support.displayManager.auto.enable = true;
-          services.xserver.displayManager.defaultSession = "none+icewm";
-          services.xserver.windowManager.icewm.enable = true;
-        };
-    in
-    runInMachine ({
-      machine = client;
-      preBuild =
-        ''
-          client.wait_for_x()
-        '';
-    } // args);
+  runInMachine = abortForFunction "runInMachine";
 
+  runInMachineWithX = abortForFunction "runInMachineWithX";
 
   simpleTest = as: (makeTest as).test;
 
diff --git a/nixpkgs/nixos/modules/config/console.nix b/nixpkgs/nixos/modules/config/console.nix
index c5150305bd85..98f942ee63f5 100644
--- a/nixpkgs/nixos/modules/config/console.nix
+++ b/nixpkgs/nixos/modules/config/console.nix
@@ -116,7 +116,11 @@ in
     { console.keyMap = with config.services.xserver;
         mkIf cfg.useXkbConfig
           (pkgs.runCommand "xkb-console-keymap" { preferLocalBuild = true; } ''
-            '${pkgs.ckbcomp}/bin/ckbcomp' -model '${xkbModel}' -layout '${layout}' \
+            '${pkgs.ckbcomp}/bin/ckbcomp' \
+              ${optionalString (config.environment.sessionVariables ? XKB_CONFIG_ROOT)
+                "-I${config.environment.sessionVariables.XKB_CONFIG_ROOT}"
+              } \
+              -model '${xkbModel}' -layout '${layout}' \
               -option '${xkbOptions}' -variant '${xkbVariant}' > "$out"
           '');
     }
diff --git a/nixpkgs/nixos/modules/config/krb5/default.nix b/nixpkgs/nixos/modules/config/krb5/default.nix
index c2302451d702..6db2a7e40391 100644
--- a/nixpkgs/nixos/modules/config/krb5/default.nix
+++ b/nixpkgs/nixos/modules/config/krb5/default.nix
@@ -84,7 +84,7 @@ in {
         type = types.package;
         default = pkgs.krb5Full;
         defaultText = "pkgs.krb5Full";
-        example = literalExample "pkgs.heimdalFull";
+        example = literalExample "pkgs.heimdal";
         description = ''
           The Kerberos implementation that will be present in
           <literal>environment.systemPackages</literal> after enabling this
diff --git a/nixpkgs/nixos/modules/config/malloc.nix b/nixpkgs/nixos/modules/config/malloc.nix
index fc35993b5a81..84da5643004f 100644
--- a/nixpkgs/nixos/modules/config/malloc.nix
+++ b/nixpkgs/nixos/modules/config/malloc.nix
@@ -30,6 +30,15 @@ let
         vulnerabilities, while maintaining good performance.
       '';
     };
+
+    mimalloc = {
+      libPath = "${pkgs.mimalloc}/lib/libmimalloc.so";
+      description = ''
+        A compact and fast general purpose allocator, which may
+        optionally be built with mitigations against various heap
+        vulnerabilities.
+      '';
+    };
   };
 
   providerConf = providers.${cfg.provider};
@@ -91,7 +100,10 @@ in
       "abstractions/base" = ''
         r /etc/ld-nix.so.preload,
         r ${config.environment.etc."ld-nix.so.preload".source},
-        mr ${providerLibPath},
+        include "${pkgs.apparmorRulesFromClosure {
+            name = "mallocLib";
+            baseRules = ["mr $path/lib/**.so*"];
+          } [ mallocLib ] }"
       '';
     };
   };
diff --git a/nixpkgs/nixos/modules/config/users-groups.nix b/nixpkgs/nixos/modules/config/users-groups.nix
index d88162558e66..8e2db9107a11 100644
--- a/nixpkgs/nixos/modules/config/users-groups.nix
+++ b/nixpkgs/nixos/modules/config/users-groups.nix
@@ -123,7 +123,7 @@ let
       group = mkOption {
         type = types.str;
         apply = x: assert (builtins.stringLength x < 32 || abort "Group name '${x}' is longer than 31 characters which is not allowed!"); x;
-        default = "nogroup";
+        default = "";
         description = "The user's primary group.";
       };
 
@@ -640,6 +640,16 @@ in {
               Exactly one of users.users.${user.name}.isSystemUser and users.users.${user.name}.isNormalUser must be set.
             '';
           }
+          {
+            assertion = user.group != "";
+            message = ''
+              users.users.${user.name}.group is unset. This used to default to
+              nogroup, but this is unsafe. For example you can create a group
+              for this user with:
+              users.users.${user.name}.group = "${user.name}";
+              users.groups.${user.name} = {};
+            '';
+          }
         ]
     ));
 
diff --git a/nixpkgs/nixos/modules/config/xdg/mime.nix b/nixpkgs/nixos/modules/config/xdg/mime.nix
index 4cdb3f30994b..9b6dd4cab5f5 100644
--- a/nixpkgs/nixos/modules/config/xdg/mime.nix
+++ b/nixpkgs/nixos/modules/config/xdg/mime.nix
@@ -1,9 +1,17 @@
 { config, lib, pkgs, ... }:
 
 with lib;
+
+let
+  cfg = config.xdg.mime;
+  associationOptions = with types; attrsOf (
+    coercedTo (either (listOf str) str) (x: concatStringsSep ";" (toList x)) str
+  );
+in
+
 {
   meta = {
-    maintainers = teams.freedesktop.members;
+    maintainers = teams.freedesktop.members ++ (with maintainers; [ figsoda ]);
   };
 
   options = {
@@ -16,9 +24,63 @@ with lib;
         <link xlink:href="https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html">XDG MIME Applications specification</link>.
       '';
     };
+
+    xdg.mime.addedAssociations = mkOption {
+      type = associationOptions;
+      default = {};
+      example = {
+        "application/pdf" = "firefox.desktop";
+        "text/xml" = [ "nvim.desktop" "codium.desktop" ];
+      };
+      description = ''
+        Adds associations between mimetypes and applications. See the
+        <link xlink:href="https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html#associations">
+        specifications</link> for more information.
+      '';
+    };
+
+    xdg.mime.defaultApplications = mkOption {
+      type = associationOptions;
+      default = {};
+      example = {
+        "application/pdf" = "firefox.desktop";
+        "image/png" = [ "sxiv.desktop" "gimp.desktop" ];
+      };
+      description = ''
+        Sets the default applications for given mimetypes. See the
+        <link xlink:href="https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html#default">
+        specifications</link> for more information.
+      '';
+    };
+
+    xdg.mime.removedAssociations = mkOption {
+      type = associationOptions;
+      default = {};
+      example = {
+        "audio/mp3" = [ "mpv.desktop" "umpv.desktop" ];
+        "inode/directory" = "codium.desktop";
+      };
+      description = ''
+        Removes associations between mimetypes and applications. See the
+        <link xlink:href="https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html#associations">
+        specifications</link> for more information.
+      '';
+    };
   };
 
-  config = mkIf config.xdg.mime.enable {
+  config = mkIf cfg.enable {
+    environment.etc."xdg/mimeapps.list" = mkIf (
+      cfg.addedAssociations != {}
+      || cfg.defaultApplications != {}
+      || cfg.removedAssociations != {}
+    ) {
+      text = generators.toINI { } {
+        "Added Associations" = cfg.addedAssociations;
+        "Default Applications" = cfg.defaultApplications;
+        "Removed Associations" = cfg.removedAssociations;
+      };
+    };
+
     environment.pathsToLink = [ "/share/mime" ];
 
     environment.systemPackages = [
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix
index 123f487baf93..054c8c74a76b 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix
@@ -93,7 +93,7 @@ in
   boot.initrd.availableKernelModules =
     [ "vfat" "reiserfs" ];
 
-  boot.kernelPackages = pkgs.linuxPackages_3_10;
+  boot.kernelPackages = pkgs.linuxKernel.packages.linux_3_10;
   boot.kernelParams = [ "console=tty1" ];
 
   boot.postBootCommands =
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-pc.nix b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-pc.nix
index a79209d7dfef..674fb6c8a33c 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-pc.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-pc.nix
@@ -114,7 +114,7 @@ in
   # To be able to use the systemTarball to catch troubles.
   boot.crashDump = {
     enable = true;
-    kernelPackages = pkgs.linuxPackages_3_4;
+    kernelPackages = pkgs.linuxKernel.packages.linux_3_4;
   };
 
   # No grub for the tarball.
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
index 95579f3ca06d..458e313a3f75 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
@@ -111,7 +111,7 @@ in
       # "console=ttyS0,115200n8"  # serial console
     ];
 
-  boot.kernelPackages = pkgs.linuxPackages_3_4;
+  boot.kernelPackages = pkgs.linuxKernel.packages.linux_3_4;
 
   boot.supportedFilesystems = [ "reiserfs" ];
 
diff --git a/nixpkgs/nixos/modules/installer/sd-card/sd-image-raspberrypi.nix b/nixpkgs/nixos/modules/installer/sd-card/sd-image-raspberrypi.nix
index 83850f4c1158..103d6787a03c 100644
--- a/nixpkgs/nixos/modules/installer/sd-card/sd-image-raspberrypi.nix
+++ b/nixpkgs/nixos/modules/installer/sd-card/sd-image-raspberrypi.nix
@@ -12,7 +12,7 @@
   boot.loader.generic-extlinux-compatible.enable = true;
 
   boot.consoleLogLevel = lib.mkDefault 7;
-  boot.kernelPackages = pkgs.linuxPackages_rpi1;
+  boot.kernelPackages = pkgs.linuxKernel.packages.linux_rpi1;
 
   sdImage = {
     populateFirmwareCommands = let
diff --git a/nixpkgs/nixos/modules/installer/tools/tools.nix b/nixpkgs/nixos/modules/installer/tools/tools.nix
index f79ed3493dfb..2f3b0cdd48f2 100644
--- a/nixpkgs/nixos/modules/installer/tools/tools.nix
+++ b/nixpkgs/nixos/modules/installer/tools/tools.nix
@@ -104,7 +104,20 @@ in
     };
   };
 
-  config = {
+  options.system.disableInstallerTools = mkOption {
+    internal = true;
+    type = types.bool;
+    default = false;
+    description = ''
+      Disable nixos-rebuild, nixos-generate-config, nixos-installer
+      and other NixOS tools. This is useful to shrink embedded,
+      read-only systems which are not expected to be rebuild or
+      reconfigure themselves. Use at your own risk!
+    '';
+  };
+
+  config = lib.mkIf (!config.system.disableInstallerTools) {
+
     system.nixos-generate-config.configuration = mkDefault ''
       # Edit this configuration file to define what should be installed on
       # your system.  Help is available in the configuration.nix(5) man page
diff --git a/nixpkgs/nixos/modules/misc/documentation.nix b/nixpkgs/nixos/modules/misc/documentation.nix
index 51b310745604..233332e2d414 100644
--- a/nixpkgs/nixos/modules/misc/documentation.nix
+++ b/nixpkgs/nixos/modules/misc/documentation.nix
@@ -172,11 +172,11 @@ in
         description = ''
           Whether to install documentation targeted at developers.
           <itemizedlist>
-          <listitem><para>This includes man pages targeted at developers if <option>man.enable</option> is
+          <listitem><para>This includes man pages targeted at developers if <option>documentation.man.enable</option> is
                     set (this also includes "devman" outputs).</para></listitem>
-          <listitem><para>This includes info pages targeted at developers if <option>info.enable</option>
+          <listitem><para>This includes info pages targeted at developers if <option>documentation.info.enable</option>
                     is set (this also includes "devinfo" outputs).</para></listitem>
-          <listitem><para>This includes other pages targeted at developers if <option>doc.enable</option>
+          <listitem><para>This includes other pages targeted at developers if <option>documentation.doc.enable</option>
                     is set (this also includes "devdoc" outputs).</para></listitem>
           </itemizedlist>
         '';
@@ -190,10 +190,10 @@ in
           <itemizedlist>
           <listitem><para>This includes man pages like
                     <citerefentry><refentrytitle>configuration.nix</refentrytitle>
-                    <manvolnum>5</manvolnum></citerefentry> if <option>man.enable</option> is
+                    <manvolnum>5</manvolnum></citerefentry> if <option>documentation.man.enable</option> is
                     set.</para></listitem>
           <listitem><para>This includes the HTML manual and the <command>nixos-help</command> command if
-                    <option>doc.enable</option> is set.</para></listitem>
+                    <option>documentation.doc.enable</option> is set.</para></listitem>
           </itemizedlist>
         '';
       };
diff --git a/nixpkgs/nixos/modules/misc/ids.nix b/nixpkgs/nixos/modules/misc/ids.nix
index 93ea73f303cb..a3e491a38329 100644
--- a/nixpkgs/nixos/modules/misc/ids.nix
+++ b/nixpkgs/nixos/modules/misc/ids.nix
@@ -46,7 +46,7 @@ in
       messagebus = 4; # D-Bus
       haldaemon = 5;
       #disk = 6; # unused
-      vsftpd = 7;
+      #vsftpd = 7; # dynamically allocated ass of 2021-09-14
       ftp = 8;
       bitlbee = 9;
       #avahi = 10; # removed 2019-05-22
@@ -83,14 +83,14 @@ in
       #fourstore = 42; # dropped in 20.03
       #fourstorehttp = 43; # dropped in 20.03
       virtuoso = 44;
-      rtkit = 45;
+      #rtkit = 45; # dynamically allocated 2021-09-03
       dovecot2 = 46;
       dovenull2 = 47;
       prayer = 49;
       mpd = 50;
       clamav = 51;
       fprot = 52;
-      bind = 53;
+      # bind = 53; #dynamically allocated as of 2021-09-03
       wwwrun = 54;
       #adm = 55; # unused
       spamd = 56;
@@ -134,13 +134,13 @@ in
       firebird = 95;
       #keys = 96; # unused
       #haproxy = 97; # dynamically allocated as of 2020-03-11
-      mongodb = 98;
+      #mongodb = 98; #dynamically allocated as of 2021-09-03
       #openldap = 99; # dynamically allocated as of PR#94610
       #users = 100; # unused
-      cgminer = 101;
+      # cgminer = 101; #dynamically allocated as of 2021-09-17
       munin = 102;
-      logcheck = 103;
-      nix-ssh = 104;
+      #logcheck = 103; #dynamically allocated as of 2021-09-17
+      #nix-ssh = 104; #dynamically allocated as of 2021-09-03
       dictd = 105;
       couchdb = 106;
       #searx = 107; # dynamically allocated as of 2020-10-27
@@ -149,11 +149,11 @@ in
       systemd-journal-gateway = 110;
       #notbit = 111; # unused
       aerospike = 111;
-      ngircd = 112;
+      #ngircd = 112; #dynamically allocated as of 2021-09-03
       #btsync = 113; # unused
-      minecraft = 114;
+      #minecraft = 114; #dynamically allocated as of 2021-09-03
       vault = 115;
-      rippled = 116;
+      # rippled = 116; #dynamically allocated as of 2021-09-18
       murmur = 117;
       foundationdb = 118;
       newrelic = 119;
@@ -169,19 +169,19 @@ in
       mopidy = 130;
       #docker = 131; # unused
       gdm = 132;
-      dhcpd = 133;
+      #dhcpd = 133; # dynamically allocated as of 2021-09-03
       siproxd = 134;
       mlmmj = 135;
-      neo4j = 136;
+      #neo4j = 136;# dynamically allocated as of 2021-09-03
       riemann = 137;
       riemanndash = 138;
-      radvd = 139;
-      zookeeper = 140;
-      dnsmasq = 141;
+      #radvd = 139;# dynamically allocated as of 2021-09-03
+      #zookeeper = 140;# dynamically allocated as of 2021-09-03
+      #dnsmasq = 141;# dynamically allocated as of 2021-09-03
       #uhub = 142; # unused
       yandexdisk = 143;
       mxisd = 144; # was once collectd
-      consul = 145;
+      #consul = 145;# dynamically allocated as of 2021-09-03
       mailpile = 146;
       redmine = 147;
       #seeks = 148; # removed 2020-06-21
@@ -192,7 +192,7 @@ in
       systemd-resolve = 153;
       systemd-timesync = 154;
       liquidsoap = 155;
-      etcd = 156;
+      #etcd = 156;# dynamically allocated as of 2021-09-03
       hbase = 158;
       opentsdb = 159;
       scollector = 160;
@@ -201,26 +201,26 @@ in
       peerflix = 163;
       #chronos = 164; # removed 2020-08-15
       gitlab = 165;
-      tox-bootstrapd = 166;
+      # tox-bootstrapd = 166; removed 2021-09-15
       cadvisor = 167;
       nylon = 168;
-      apache-kafka = 169;
+      #apache-kafka = 169;# dynamically allocated as of 2021-09-03
       #panamax = 170; # unused
       exim = 172;
       #fleet = 173; # unused
       #input = 174; # unused
       sddm = 175;
-      tss = 176;
+      #tss = 176; # dynamically allocated as of 2021-09-17
       #memcached = 177; removed 2018-01-03
-      ntp = 179;
+      #ntp = 179; # dynamically allocated as of 2021-09-17
       zabbix = 180;
       #redis = 181; removed 2018-01-03
-      unifi = 183;
+      #unifi = 183; dynamically allocated as of 2021-09-17
       uptimed = 184;
-      zope2 = 185;
-      ripple-data-api = 186;
+      #zope2 = 185; # dynamically allocated as of 2021-09-18
+      #ripple-data-api = 186; dynamically allocated as of 2021-09-17
       mediatomb = 187;
-      rdnssd = 188;
+      #rdnssd = 188; #dynamically allocated as of 2021-09-18
       ihaskell = 189;
       i2p = 190;
       lambdabot = 191;
@@ -231,20 +231,20 @@ in
       skydns = 197;
       # ripple-rest = 198; # unused, removed 2017-08-12
       # nix-serve = 199; # unused, removed 2020-12-12
-      tvheadend = 200;
+      #tvheadend = 200; # dynamically allocated as of 2021-09-18
       uwsgi = 201;
       gitit = 202;
       riemanntools = 203;
       subsonic = 204;
       riak = 205;
-      shout = 206;
+      #shout = 206; # dynamically allocated as of 2021-09-18
       gateone = 207;
       namecoin = 208;
       #lxd = 210; # unused
-      kibana = 211;
+      #kibana = 211;# dynamically allocated as of 2021-09-03
       xtreemfs = 212;
       calibre-server = 213;
-      heapster = 214;
+      #heapster = 214; #dynamically allocated as of 2021-09-17
       bepasty = 215;
       # pumpio = 216; # unused, removed 2018-02-24
       nm-openvpn = 217;
@@ -258,13 +258,13 @@ in
       rspamd = 225;
       # rmilter = 226; # unused, removed 2019-08-22
       cfdyndns = 227;
-      gammu-smsd = 228;
+      # gammu-smsd = 228; #dynamically allocated as of 2021-09-17
       pdnsd = 229;
       octoprint = 230;
       avahi-autoipd = 231;
-      nntp-proxy = 232;
+      # nntp-proxy = 232; #dynamically allocated as of 2021-09-17
       mjpg-streamer = 233;
-      radicale = 234;
+      #radicale = 234;# dynamically allocated as of 2021-09-03
       hydra-queue-runner = 235;
       hydra-www = 236;
       syncthing = 237;
@@ -272,14 +272,14 @@ in
       taskd = 240;
       # factorio = 241; # DynamicUser = true
       # emby = 242; # unusued, removed 2019-05-01
-      graylog = 243;
+      #graylog = 243;# dynamically allocated as of 2021-09-03
       sniproxy = 244;
       nzbget = 245;
       mosquitto = 246;
-      toxvpn = 247;
+      #toxvpn = 247; # dynamically allocated as of 2021-09-18
       # squeezelite = 248; # DynamicUser = true
       turnserver = 249;
-      smokeping = 250;
+      #smokeping = 250;# dynamically allocated as of 2021-09-03
       gocd-agent = 251;
       gocd-server = 252;
       terraria = 253;
@@ -366,7 +366,7 @@ in
       messagebus = 4; # D-Bus
       haldaemon = 5;
       disk = 6;
-      vsftpd = 7;
+      #vsftpd = 7; # dynamically allocated as of 2021-09-14
       ftp = 8;
       bitlbee = 9;
       #avahi = 10; # removed 2019-05-22
@@ -524,7 +524,7 @@ in
       #fleet = 173; # unused
       input = 174;
       sddm = 175;
-      tss = 176;
+      #tss = 176; #dynamically allocateda as of 2021-09-20
       #memcached = 177; # unused, removed 2018-01-03
       #ntp = 179; # unused
       zabbix = 180;
@@ -554,7 +554,7 @@ in
       #shout = 206; #unused
       gateone = 207;
       namecoin = 208;
-      lxd = 210; # unused
+      #lxd = 210; # unused
       #kibana = 211;
       xtreemfs = 212;
       calibre-server = 213;
@@ -573,7 +573,7 @@ in
       cfdyndns = 227;
       pdnsd = 229;
       octoprint = 230;
-      radicale = 234;
+      #radicale = 234;# dynamically allocated as of 2021-09-03
       syncthing = 237;
       caddy = 239;
       taskd = 240;
@@ -585,7 +585,7 @@ in
       #toxvpn = 247; # unused
       #squeezelite = 248; #unused
       turnserver = 249;
-      smokeping = 250;
+      #smokeping = 250;# dynamically allocated as of 2021-09-03
       gocd-agent = 251;
       gocd-server = 252;
       terraria = 253;
diff --git a/nixpkgs/nixos/modules/module-list.nix b/nixpkgs/nixos/modules/module-list.nix
index d145df05da32..4bd6fc030fc8 100644
--- a/nixpkgs/nixos/modules/module-list.nix
+++ b/nixpkgs/nixos/modules/module-list.nix
@@ -171,6 +171,7 @@
   ./programs/npm.nix
   ./programs/noisetorch.nix
   ./programs/oblogout.nix
+  ./programs/pantheon-tweaks.nix
   ./programs/partition-manager.nix
   ./programs/plotinus.nix
   ./programs/proxychains.nix
@@ -201,6 +202,7 @@
   ./programs/vim.nix
   ./programs/wavemon.nix
   ./programs/waybar.nix
+  ./programs/weylus.nix
   ./programs/wireshark.nix
   ./programs/wshowkeys.nix
   ./programs/xfs_quota.nix
@@ -297,6 +299,7 @@
   ./services/cluster/kubernetes/pki.nix
   ./services/cluster/kubernetes/proxy.nix
   ./services/cluster/kubernetes/scheduler.nix
+  ./services/cluster/spark/default.nix
   ./services/computing/boinc/client.nix
   ./services/computing/foldingathome/client.nix
   ./services/computing/slurm/slurm.nix
@@ -341,6 +344,7 @@
   ./services/desktops/accountsservice.nix
   ./services/desktops/bamf.nix
   ./services/desktops/blueman.nix
+  ./services/desktops/cpupower-gui.nix
   ./services/desktops/dleyna-renderer.nix
   ./services/desktops/dleyna-server.nix
   ./services/desktops/pantheon/files.nix
@@ -558,6 +562,7 @@
   ./services/misc/octoprint.nix
   ./services/misc/ombi.nix
   ./services/misc/osrm.nix
+  ./services/misc/owncast.nix
   ./services/misc/packagekit.nix
   ./services/misc/paperless-ng.nix
   ./services/misc/parsoid.nix
@@ -623,6 +628,7 @@
   ./services/monitoring/munin.nix
   ./services/monitoring/nagios.nix
   ./services/monitoring/netdata.nix
+  ./services/monitoring/parsedmarc.nix
   ./services/monitoring/prometheus/default.nix
   ./services/monitoring/prometheus/alertmanager.nix
   ./services/monitoring/prometheus/exporters.nix
@@ -898,6 +904,7 @@
   ./services/search/elasticsearch-curator.nix
   ./services/search/hound.nix
   ./services/search/kibana.nix
+  ./services/search/meilisearch.nix
   ./services/search/solr.nix
   ./services/security/certmgr.nix
   ./services/security/cfssl.nix
@@ -914,6 +921,7 @@
   ./services/security/nginx-sso.nix
   ./services/security/oauth2_proxy.nix
   ./services/security/oauth2_proxy_nginx.nix
+  ./services/security/opensnitch.nix
   ./services/security/privacyidea.nix
   ./services/security/physlock.nix
   ./services/security/shibboleth-sp.nix
@@ -1026,7 +1034,7 @@
   ./services/web-servers/shellinabox.nix
   ./services/web-servers/tomcat.nix
   ./services/web-servers/traefik.nix
-  ./services/web-servers/trafficserver.nix
+  ./services/web-servers/trafficserver/default.nix
   ./services/web-servers/ttyd.nix
   ./services/web-servers/uwsgi.nix
   ./services/web-servers/varnish/default.nix
@@ -1055,6 +1063,7 @@
   ./services/x11/gdk-pixbuf.nix
   ./services/x11/imwheel.nix
   ./services/x11/redshift.nix
+  ./services/x11/touchegg.nix
   ./services/x11/urserver.nix
   ./services/x11/urxvtd.nix
   ./services/x11/window-managers/awesome.nix
diff --git a/nixpkgs/nixos/modules/programs/atop.nix b/nixpkgs/nixos/modules/programs/atop.nix
index b45eb16e3eaf..918c228b3f52 100644
--- a/nixpkgs/nixos/modules/programs/atop.nix
+++ b/nixpkgs/nixos/modules/programs/atop.nix
@@ -141,8 +141,15 @@ in
             // mkService cfg.atopgpu.enable "atopgpu" [ atop ];
           timers = mkTimer cfg.atopRotateTimer.enable "atop-rotate" [ atop ];
         };
-      security.wrappers =
-        lib.mkIf cfg.setuidWrapper.enable { atop = { source = "${atop}/bin/atop"; }; };
+
+      security.wrappers = lib.mkIf cfg.setuidWrapper.enable {
+        atop =
+          { setuid = true;
+            owner = "root";
+            group = "root";
+            source = "${atop}/bin/atop";
+          };
+      };
     }
   );
 }
diff --git a/nixpkgs/nixos/modules/programs/bandwhich.nix b/nixpkgs/nixos/modules/programs/bandwhich.nix
index 1cffb5fa2765..610d602ad2cc 100644
--- a/nixpkgs/nixos/modules/programs/bandwhich.nix
+++ b/nixpkgs/nixos/modules/programs/bandwhich.nix
@@ -22,8 +22,10 @@ in {
   config = mkIf cfg.enable {
     environment.systemPackages = with pkgs; [ bandwhich ];
     security.wrappers.bandwhich = {
-      source = "${pkgs.bandwhich}/bin/bandwhich";
+      owner = "root";
+      group = "root";
       capabilities = "cap_net_raw,cap_net_admin+ep";
+      source = "${pkgs.bandwhich}/bin/bandwhich";
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/captive-browser.nix b/nixpkgs/nixos/modules/programs/captive-browser.nix
index d7684d08c6c7..4e8abdeecf0b 100644
--- a/nixpkgs/nixos/modules/programs/captive-browser.nix
+++ b/nixpkgs/nixos/modules/programs/captive-browser.nix
@@ -105,11 +105,15 @@ in
       );
 
     security.wrappers.udhcpc = {
+      owner = "root";
+      group = "root";
       capabilities = "cap_net_raw+p";
       source = "${pkgs.busybox}/bin/udhcpc";
     };
 
     security.wrappers.captive-browser = {
+      owner = "root";
+      group = "root";
       capabilities = "cap_net_raw+p";
       source = pkgs.writeShellScript "captive-browser" ''
         export PREV_CONFIG_HOME="$XDG_CONFIG_HOME"
diff --git a/nixpkgs/nixos/modules/programs/ccache.nix b/nixpkgs/nixos/modules/programs/ccache.nix
index d672e1da017a..35a4373f6128 100644
--- a/nixpkgs/nixos/modules/programs/ccache.nix
+++ b/nixpkgs/nixos/modules/programs/ccache.nix
@@ -28,7 +28,9 @@ in {
 
       # "nix-ccache --show-stats" and "nix-ccache --clear"
       security.wrappers.nix-ccache = {
+        owner = "nobody";
         group = "nixbld";
+        setuid = false;
         setgid = true;
         source = pkgs.writeScript "nix-ccache.pl" ''
           #!${pkgs.perl}/bin/perl
diff --git a/nixpkgs/nixos/modules/programs/firejail.nix b/nixpkgs/nixos/modules/programs/firejail.nix
index ad4ef1a39459..9384b01b3674 100644
--- a/nixpkgs/nixos/modules/programs/firejail.nix
+++ b/nixpkgs/nixos/modules/programs/firejail.nix
@@ -81,7 +81,12 @@ in {
   };
 
   config = mkIf cfg.enable {
-    security.wrappers.firejail.source = "${lib.getBin pkgs.firejail}/bin/firejail";
+    security.wrappers.firejail =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${lib.getBin pkgs.firejail}/bin/firejail";
+      };
 
     environment.systemPackages = [ pkgs.firejail ] ++ [ wrappedBins ];
   };
diff --git a/nixpkgs/nixos/modules/programs/gamemode.nix b/nixpkgs/nixos/modules/programs/gamemode.nix
index 03949bf98df6..102788f5b019 100644
--- a/nixpkgs/nixos/modules/programs/gamemode.nix
+++ b/nixpkgs/nixos/modules/programs/gamemode.nix
@@ -56,6 +56,8 @@ in
       polkit.enable = true;
       wrappers = mkIf cfg.enableRenice {
         gamemoded = {
+          owner = "root";
+          group = "root";
           source = "${pkgs.gamemode}/bin/gamemoded";
           capabilities = "cap_sys_nice+ep";
         };
diff --git a/nixpkgs/nixos/modules/programs/iftop.nix b/nixpkgs/nixos/modules/programs/iftop.nix
index a98a9a8187d4..c74714a9a6d6 100644
--- a/nixpkgs/nixos/modules/programs/iftop.nix
+++ b/nixpkgs/nixos/modules/programs/iftop.nix
@@ -11,8 +11,10 @@ in {
   config = mkIf cfg.enable {
     environment.systemPackages = [ pkgs.iftop ];
     security.wrappers.iftop = {
-      source = "${pkgs.iftop}/bin/iftop";
+      owner = "root";
+      group = "root";
       capabilities = "cap_net_raw+p";
+      source = "${pkgs.iftop}/bin/iftop";
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/iotop.nix b/nixpkgs/nixos/modules/programs/iotop.nix
index 5512dbc62f72..b7c1c69f9ddd 100644
--- a/nixpkgs/nixos/modules/programs/iotop.nix
+++ b/nixpkgs/nixos/modules/programs/iotop.nix
@@ -10,8 +10,10 @@ in {
   };
   config = mkIf cfg.enable {
     security.wrappers.iotop = {
-      source = "${pkgs.iotop}/bin/iotop";
+      owner = "root";
+      group = "root";
       capabilities = "cap_net_admin+p";
+      source = "${pkgs.iotop}/bin/iotop";
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/kbdlight.nix b/nixpkgs/nixos/modules/programs/kbdlight.nix
index 58e45872fac8..8a2a0057cf2d 100644
--- a/nixpkgs/nixos/modules/programs/kbdlight.nix
+++ b/nixpkgs/nixos/modules/programs/kbdlight.nix
@@ -11,6 +11,11 @@ in
 
   config = mkIf cfg.enable {
     environment.systemPackages = [ pkgs.kbdlight ];
-    security.wrappers.kbdlight.source = "${pkgs.kbdlight.out}/bin/kbdlight";
+    security.wrappers.kbdlight =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${pkgs.kbdlight.out}/bin/kbdlight";
+      };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/liboping.nix b/nixpkgs/nixos/modules/programs/liboping.nix
index 4e4c235ccde4..4433f9767d6e 100644
--- a/nixpkgs/nixos/modules/programs/liboping.nix
+++ b/nixpkgs/nixos/modules/programs/liboping.nix
@@ -13,8 +13,10 @@ in {
     security.wrappers = mkMerge (map (
       exec: {
         "${exec}" = {
-          source = "${pkgs.liboping}/bin/${exec}";
+          owner = "root";
+          group = "root";
           capabilities = "cap_net_raw+p";
+          source = "${pkgs.liboping}/bin/${exec}";
         };
       }
     ) [ "oping" "noping" ]);
diff --git a/nixpkgs/nixos/modules/programs/msmtp.nix b/nixpkgs/nixos/modules/programs/msmtp.nix
index 217060e6b3b3..9c067bdc9695 100644
--- a/nixpkgs/nixos/modules/programs/msmtp.nix
+++ b/nixpkgs/nixos/modules/programs/msmtp.nix
@@ -78,6 +78,8 @@ in {
       source = "${pkgs.msmtp}/bin/sendmail";
       setuid = false;
       setgid = false;
+      owner = "root";
+      group = "root";
     };
 
     environment.etc."msmtprc".text = let
diff --git a/nixpkgs/nixos/modules/programs/mtr.nix b/nixpkgs/nixos/modules/programs/mtr.nix
index 75b710c1584f..63516c58440e 100644
--- a/nixpkgs/nixos/modules/programs/mtr.nix
+++ b/nixpkgs/nixos/modules/programs/mtr.nix
@@ -31,8 +31,10 @@ in {
     environment.systemPackages = with pkgs; [ cfg.package ];
 
     security.wrappers.mtr-packet = {
-      source = "${cfg.package}/bin/mtr-packet";
+      owner = "root";
+      group = "root";
       capabilities = "cap_net_raw+p";
+      source = "${cfg.package}/bin/mtr-packet";
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/noisetorch.nix b/nixpkgs/nixos/modules/programs/noisetorch.nix
index 5f3b0c8f5d1e..bca68b0064c0 100644
--- a/nixpkgs/nixos/modules/programs/noisetorch.nix
+++ b/nixpkgs/nixos/modules/programs/noisetorch.nix
@@ -18,8 +18,10 @@ in {
 
   config = mkIf cfg.enable {
     security.wrappers.noisetorch = {
-      source = "${cfg.package}/bin/noisetorch";
+      owner = "root";
+      group = "root";
       capabilities = "cap_sys_resource=+ep";
+      source = "${cfg.package}/bin/noisetorch";
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/pantheon-tweaks.nix b/nixpkgs/nixos/modules/programs/pantheon-tweaks.nix
new file mode 100644
index 000000000000..0b8a19ea22c0
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/pantheon-tweaks.nix
@@ -0,0 +1,19 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  meta = {
+    maintainers = teams.pantheon.members;
+  };
+
+  ###### interface
+  options = {
+    programs.pantheon-tweaks.enable = mkEnableOption "Pantheon Tweaks, an unofficial system settings panel for Pantheon";
+  };
+
+  ###### implementation
+  config = mkIf config.programs.pantheon-tweaks.enable {
+    services.xserver.desktopManager.pantheon.extraSwitchboardPlugs = [ pkgs.pantheon-tweaks ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/programs/plotinus.nix b/nixpkgs/nixos/modules/programs/plotinus.nix
index e3549c79588b..2c90a41ba029 100644
--- a/nixpkgs/nixos/modules/programs/plotinus.nix
+++ b/nixpkgs/nixos/modules/programs/plotinus.nix
@@ -30,7 +30,7 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
-    environment.variables.XDG_DATA_DIRS = [ "${pkgs.plotinus}/share/gsettings-schemas/${pkgs.plotinus.name}" ];
+    environment.sessionVariables.XDG_DATA_DIRS = [ "${pkgs.plotinus}/share/gsettings-schemas/${pkgs.plotinus.name}" ];
     environment.variables.GTK3_MODULES = [ "${pkgs.plotinus}/lib/libplotinus.so" ];
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/shadow.nix b/nixpkgs/nixos/modules/programs/shadow.nix
index 386ded9d98b6..e021f184179d 100644
--- a/nixpkgs/nixos/modules/programs/shadow.nix
+++ b/nixpkgs/nixos/modules/programs/shadow.nix
@@ -43,6 +43,13 @@ let
 
     '';
 
+  mkSetuidRoot = source:
+    { setuid = true;
+      owner = "root";
+      group = "root";
+      inherit source;
+    };
+
 in
 
 {
@@ -109,14 +116,14 @@ in
       };
 
     security.wrappers = {
-      su.source        = "${pkgs.shadow.su}/bin/su";
-      sg.source        = "${pkgs.shadow.out}/bin/sg";
-      newgrp.source    = "${pkgs.shadow.out}/bin/newgrp";
-      newuidmap.source = "${pkgs.shadow.out}/bin/newuidmap";
-      newgidmap.source = "${pkgs.shadow.out}/bin/newgidmap";
+      su        = mkSetuidRoot "${pkgs.shadow.su}/bin/su";
+      sg        = mkSetuidRoot "${pkgs.shadow.out}/bin/sg";
+      newgrp    = mkSetuidRoot "${pkgs.shadow.out}/bin/newgrp";
+      newuidmap = mkSetuidRoot "${pkgs.shadow.out}/bin/newuidmap";
+      newgidmap = mkSetuidRoot "${pkgs.shadow.out}/bin/newgidmap";
     } // lib.optionalAttrs config.users.mutableUsers {
-      chsh.source      = "${pkgs.shadow.out}/bin/chsh";
-      passwd.source    = "${pkgs.shadow.out}/bin/passwd";
+      chsh   = mkSetuidRoot "${pkgs.shadow.out}/bin/chsh";
+      passwd = mkSetuidRoot "${pkgs.shadow.out}/bin/passwd";
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/singularity.nix b/nixpkgs/nixos/modules/programs/singularity.nix
index 6ac64a81fc24..db935abe4bb4 100644
--- a/nixpkgs/nixos/modules/programs/singularity.nix
+++ b/nixpkgs/nixos/modules/programs/singularity.nix
@@ -16,7 +16,12 @@ in {
 
   config = mkIf cfg.enable {
       environment.systemPackages = [ singularity ];
-      security.wrappers.singularity-suid.source = "${singularity}/libexec/singularity/bin/starter-suid.orig";
+      security.wrappers.singularity-suid =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${singularity}/libexec/singularity/bin/starter-suid.orig";
+      };
       systemd.tmpfiles.rules = [
         "d /var/singularity/mnt/session 0770 root root -"
         "d /var/singularity/mnt/final 0770 root root -"
diff --git a/nixpkgs/nixos/modules/programs/slock.nix b/nixpkgs/nixos/modules/programs/slock.nix
index 0e1281e62cd7..ce80fcc5d4a8 100644
--- a/nixpkgs/nixos/modules/programs/slock.nix
+++ b/nixpkgs/nixos/modules/programs/slock.nix
@@ -21,6 +21,11 @@ in
 
   config = mkIf cfg.enable {
     environment.systemPackages = [ pkgs.slock ];
-    security.wrappers.slock.source = "${pkgs.slock.out}/bin/slock";
+    security.wrappers.slock =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${pkgs.slock.out}/bin/slock";
+      };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/ssmtp.nix b/nixpkgs/nixos/modules/programs/ssmtp.nix
index 8b500f0383f4..e28a14538ecd 100644
--- a/nixpkgs/nixos/modules/programs/ssmtp.nix
+++ b/nixpkgs/nixos/modules/programs/ssmtp.nix
@@ -181,6 +181,8 @@ in
       source = "${pkgs.ssmtp}/bin/sendmail";
       setuid = false;
       setgid = false;
+      owner = "root";
+      group = "root";
     };
 
   };
diff --git a/nixpkgs/nixos/modules/programs/traceroute.nix b/nixpkgs/nixos/modules/programs/traceroute.nix
index 4eb0be3f0e0b..6e04057ac503 100644
--- a/nixpkgs/nixos/modules/programs/traceroute.nix
+++ b/nixpkgs/nixos/modules/programs/traceroute.nix
@@ -19,8 +19,10 @@ in {
 
   config = mkIf cfg.enable {
     security.wrappers.traceroute = {
-      source = "${pkgs.traceroute}/bin/traceroute";
+      owner = "root";
+      group = "root";
       capabilities = "cap_net_raw+p";
+      source = "${pkgs.traceroute}/bin/traceroute";
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/udevil.nix b/nixpkgs/nixos/modules/programs/udevil.nix
index ba5670f9dfe9..0dc08c435df4 100644
--- a/nixpkgs/nixos/modules/programs/udevil.nix
+++ b/nixpkgs/nixos/modules/programs/udevil.nix
@@ -9,6 +9,11 @@ in {
   options.programs.udevil.enable = mkEnableOption "udevil";
 
   config = mkIf cfg.enable {
-    security.wrappers.udevil.source = "${lib.getBin pkgs.udevil}/bin/udevil";
+    security.wrappers.udevil =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${lib.getBin pkgs.udevil}/bin/udevil";
+      };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/wavemon.nix b/nixpkgs/nixos/modules/programs/wavemon.nix
index ac665fe4a023..e5ccacba75d4 100644
--- a/nixpkgs/nixos/modules/programs/wavemon.nix
+++ b/nixpkgs/nixos/modules/programs/wavemon.nix
@@ -21,8 +21,10 @@ in {
   config = mkIf cfg.enable {
     environment.systemPackages = with pkgs; [ wavemon ];
     security.wrappers.wavemon = {
-      source = "${pkgs.wavemon}/bin/wavemon";
+      owner = "root";
+      group = "root";
       capabilities = "cap_net_admin+ep";
+      source = "${pkgs.wavemon}/bin/wavemon";
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/weylus.nix b/nixpkgs/nixos/modules/programs/weylus.nix
new file mode 100644
index 000000000000..ea92c77e7c32
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/weylus.nix
@@ -0,0 +1,47 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.weylus;
+in
+{
+  options.programs.weylus = with types; {
+    enable = mkEnableOption "weylus";
+
+    openFirewall = mkOption {
+      type = bool;
+      default = false;
+      description = ''
+        Open ports needed for the functionality of the program.
+      '';
+    };
+
+     users = mkOption {
+      type = listOf str;
+      default = [ ];
+      description = ''
+        To enable stylus and multi-touch support, the user you're going to use must be added to this list.
+        These users can synthesize input events system-wide, even when another user is logged in - untrusted users should not be added.
+      '';
+    };
+
+    package = mkOption {
+      type = package;
+      default = pkgs.weylus;
+      defaultText = "pkgs.weylus";
+      description = "Weylus package to install.";
+    };
+  };
+  config = mkIf cfg.enable {
+    networking.firewall = mkIf cfg.openFirewall {
+      allowedTCPPorts = [ 1701 9001 ];
+    };
+
+    hardware.uinput.enable = true;
+
+    users.groups.uinput.members = cfg.users;
+
+    environment.systemPackages = [ cfg.package ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/programs/wshowkeys.nix b/nixpkgs/nixos/modules/programs/wshowkeys.nix
index 09b008af1d5d..f7b71d2bb0c8 100644
--- a/nixpkgs/nixos/modules/programs/wshowkeys.nix
+++ b/nixpkgs/nixos/modules/programs/wshowkeys.nix
@@ -17,6 +17,11 @@ in {
   };
 
   config = mkIf cfg.enable {
-    security.wrappers.wshowkeys.source = "${pkgs.wshowkeys}/bin/wshowkeys";
+    security.wrappers.wshowkeys =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${pkgs.wshowkeys}/bin/wshowkeys";
+      };
   };
 }
diff --git a/nixpkgs/nixos/modules/security/chromium-suid-sandbox.nix b/nixpkgs/nixos/modules/security/chromium-suid-sandbox.nix
index b83dbc4202a8..bb99c053f718 100644
--- a/nixpkgs/nixos/modules/security/chromium-suid-sandbox.nix
+++ b/nixpkgs/nixos/modules/security/chromium-suid-sandbox.nix
@@ -28,6 +28,11 @@ in
 
   config = mkIf cfg.enable {
     environment.systemPackages = [ sandbox ];
-    security.wrappers.${sandbox.passthru.sandboxExecutableName}.source = "${sandbox}/bin/${sandbox.passthru.sandboxExecutableName}";
+    security.wrappers.${sandbox.passthru.sandboxExecutableName} =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${sandbox}/bin/${sandbox.passthru.sandboxExecutableName}";
+      };
   };
 }
diff --git a/nixpkgs/nixos/modules/security/doas.nix b/nixpkgs/nixos/modules/security/doas.nix
index 27f6870aaf37..35f618b03e8e 100644
--- a/nixpkgs/nixos/modules/security/doas.nix
+++ b/nixpkgs/nixos/modules/security/doas.nix
@@ -241,9 +241,12 @@ in
       }
     ];
 
-    security.wrappers = {
-      doas.source = "${doas}/bin/doas";
-    };
+    security.wrappers.doas =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${doas}/bin/doas";
+      };
 
     environment.systemPackages = [
       doas
diff --git a/nixpkgs/nixos/modules/security/duosec.nix b/nixpkgs/nixos/modules/security/duosec.nix
index c47be80b9dc3..bbe246fe229e 100644
--- a/nixpkgs/nixos/modules/security/duosec.nix
+++ b/nixpkgs/nixos/modules/security/duosec.nix
@@ -186,7 +186,12 @@ in
   config = mkIf (cfg.ssh.enable || cfg.pam.enable) {
     environment.systemPackages = [ pkgs.duo-unix ];
 
-    security.wrappers.login_duo.source = "${pkgs.duo-unix.out}/bin/login_duo";
+    security.wrappers.login_duo =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${pkgs.duo-unix.out}/bin/login_duo";
+      };
 
     system.activationScripts = {
       login_duo = mkIf cfg.ssh.enable ''
diff --git a/nixpkgs/nixos/modules/security/lock-kernel-modules.nix b/nixpkgs/nixos/modules/security/lock-kernel-modules.nix
index fc9e7939d814..065587bc286e 100644
--- a/nixpkgs/nixos/modules/security/lock-kernel-modules.nix
+++ b/nixpkgs/nixos/modules/security/lock-kernel-modules.nix
@@ -1,4 +1,4 @@
-{ config, lib, ... }:
+{ config, pkgs, lib, ... }:
 
 with lib;
 
@@ -13,7 +13,7 @@ with lib;
       default = false;
       description = ''
         Disable kernel module loading once the system is fully initialised.
-        Module loading is disabled until the next reboot.  Problems caused
+        Module loading is disabled until the next reboot. Problems caused
         by delayed module loading can be fixed by adding the module(s) in
         question to <option>boot.kernelModules</option>.
       '';
@@ -29,20 +29,30 @@ with lib;
             else [ x.fsType ]
         else []) config.system.build.fileSystems;
 
-    systemd.services.disable-kernel-module-loading = rec {
+    systemd.services.disable-kernel-module-loading = {
       description = "Disable kernel module loading";
 
+      wants = [ "systemd-udevd.service" ];
       wantedBy = [ config.systemd.defaultUnit ];
 
-      after = [ "systemd-udev-settle.service" "firewall.service" "systemd-modules-load.service" ] ++ wantedBy;
+      after =
+        [ "firewall.service"
+          "systemd-modules-load.service"
+           config.systemd.defaultUnit
+        ];
 
       unitConfig.ConditionPathIsReadWrite = "/proc/sys/kernel";
 
-      serviceConfig = {
-        Type = "oneshot";
-        RemainAfterExit = true;
-        ExecStart = "/bin/sh -c 'echo -n 1 >/proc/sys/kernel/modules_disabled'";
-      };
+      serviceConfig =
+        { Type = "oneshot";
+          RemainAfterExit = true;
+          TimeoutSec = 180;
+        };
+
+      script = ''
+        ${pkgs.udev}/bin/udevadm settle
+        echo -n 1 >/proc/sys/kernel/modules_disabled
+      '';
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/security/pam.nix b/nixpkgs/nixos/modules/security/pam.nix
index 163d75d7caf2..8b1f653d4e2c 100644
--- a/nixpkgs/nixos/modules/security/pam.nix
+++ b/nixpkgs/nixos/modules/security/pam.nix
@@ -869,9 +869,10 @@ in
 
     security.wrappers = {
       unix_chkpwd = {
-        source = "${pkgs.pam}/sbin/unix_chkpwd.orig";
-        owner = "root";
         setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${pkgs.pam}/sbin/unix_chkpwd.orig";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/security/pam_usb.nix b/nixpkgs/nixos/modules/security/pam_usb.nix
index c695ba075ca9..51d81e823f86 100644
--- a/nixpkgs/nixos/modules/security/pam_usb.nix
+++ b/nixpkgs/nixos/modules/security/pam_usb.nix
@@ -32,8 +32,18 @@ in
 
     # Make sure pmount and pumount are setuid wrapped.
     security.wrappers = {
-      pmount.source = "${pkgs.pmount.out}/bin/pmount";
-      pumount.source = "${pkgs.pmount.out}/bin/pumount";
+      pmount =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.pmount.out}/bin/pmount";
+        };
+      pumount =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.pmount.out}/bin/pumount";
+        };
     };
 
     environment.systemPackages = [ pkgs.pmount ];
diff --git a/nixpkgs/nixos/modules/security/polkit.nix b/nixpkgs/nixos/modules/security/polkit.nix
index f556cca23cdc..d9c58152f1fa 100644
--- a/nixpkgs/nixos/modules/security/polkit.nix
+++ b/nixpkgs/nixos/modules/security/polkit.nix
@@ -83,8 +83,18 @@ in
     security.pam.services.polkit-1 = {};
 
     security.wrappers = {
-      pkexec.source = "${pkgs.polkit.bin}/bin/pkexec";
-      polkit-agent-helper-1.source = "${pkgs.polkit.out}/lib/polkit-1/polkit-agent-helper-1";
+      pkexec =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.polkit.bin}/bin/pkexec";
+        };
+      polkit-agent-helper-1 =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.polkit.out}/lib/polkit-1/polkit-agent-helper-1";
+        };
     };
 
     systemd.tmpfiles.rules = [
diff --git a/nixpkgs/nixos/modules/security/rtkit.nix b/nixpkgs/nixos/modules/security/rtkit.nix
index a7b27cbcf215..ad8746808e85 100644
--- a/nixpkgs/nixos/modules/security/rtkit.nix
+++ b/nixpkgs/nixos/modules/security/rtkit.nix
@@ -35,9 +35,12 @@ with lib;
     services.dbus.packages = [ pkgs.rtkit ];
 
     users.users.rtkit =
-      { uid = config.ids.uids.rtkit;
+      {
+        isSystemUser = true;
+        group = "rtkit";
         description = "RealtimeKit daemon";
       };
+    users.groups.rtkit = {};
 
   };
 
diff --git a/nixpkgs/nixos/modules/security/tpm2.nix b/nixpkgs/nixos/modules/security/tpm2.nix
index 27f9b58c9755..d37425166f88 100644
--- a/nixpkgs/nixos/modules/security/tpm2.nix
+++ b/nixpkgs/nixos/modules/security/tpm2.nix
@@ -146,6 +146,7 @@ in {
       # Create the tss user and group only if the default value is used
       users.users.${cfg.tssUser} = lib.mkIf (cfg.tssUser == "tss") {
         isSystemUser = true;
+        group = "tss";
       };
       users.groups.${cfg.tssGroup} = lib.mkIf (cfg.tssGroup == "tss") {};
 
@@ -172,7 +173,7 @@ in {
           BusName = "com.intel.tss2.Tabrmd";
           ExecStart = "${cfg.abrmd.package}/bin/tpm2-abrmd";
           User = "tss";
-          Group = "nogroup";
+          Group = "tss";
         };
       };
 
diff --git a/nixpkgs/nixos/modules/security/wrappers/default.nix b/nixpkgs/nixos/modules/security/wrappers/default.nix
index 1e65f4515155..2697ab0bde8f 100644
--- a/nixpkgs/nixos/modules/security/wrappers/default.nix
+++ b/nixpkgs/nixos/modules/security/wrappers/default.nix
@@ -5,85 +5,140 @@ let
 
   parentWrapperDir = dirOf wrapperDir;
 
-  programs =
-    (lib.mapAttrsToList
-      (n: v: (if v ? program then v else v // {program=n;}))
-      wrappers);
-
   securityWrapper = pkgs.callPackage ./wrapper.nix {
     inherit parentWrapperDir;
   };
 
+  fileModeType =
+    let
+      # taken from the chmod(1) man page
+      symbolic = "[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=][0-7]+";
+      numeric = "[-+=]?[0-7]{0,4}";
+      mode = "((${symbolic})(,${symbolic})*)|(${numeric})";
+    in
+     lib.types.strMatching mode
+     // { description = "file mode string"; };
+
+  wrapperType = lib.types.submodule ({ name, config, ... }: {
+    options.source = lib.mkOption
+      { type = lib.types.path;
+        description = "The absolute path to the program to be wrapped.";
+      };
+    options.program = lib.mkOption
+      { type = with lib.types; nullOr str;
+        default = name;
+        description = ''
+          The name of the wrapper program. Defaults to the attribute name.
+        '';
+      };
+    options.owner = lib.mkOption
+      { type = lib.types.str;
+        description = "The owner of the wrapper program.";
+      };
+    options.group = lib.mkOption
+      { type = lib.types.str;
+        description = "The group of the wrapper program.";
+      };
+    options.permissions = lib.mkOption
+      { type = fileModeType;
+        default  = "u+rx,g+x,o+x";
+        example = "a+rx";
+        description = ''
+          The permissions of the wrapper program. The format is that of a
+          symbolic or numeric file mode understood by <command>chmod</command>.
+        '';
+      };
+    options.capabilities = lib.mkOption
+      { type = lib.types.commas;
+        default = "";
+        description = ''
+          A comma-separated list of capabilities to be given to the wrapper
+          program. For capabilities supported by the system check the
+          <citerefentry>
+            <refentrytitle>capabilities</refentrytitle>
+            <manvolnum>7</manvolnum>
+          </citerefentry>
+          manual page.
+
+          <note><para>
+            <literal>cap_setpcap</literal>, which is required for the wrapper
+            program to be able to raise caps into the Ambient set is NOT raised
+            to the Ambient set so that the real program cannot modify its own
+            capabilities!! This may be too restrictive for cases in which the
+            real program needs cap_setpcap but it at least leans on the side
+            security paranoid vs. too relaxed.
+          </para></note>
+        '';
+      };
+    options.setuid = lib.mkOption
+      { type = lib.types.bool;
+        default = false;
+        description = "Whether to add the setuid bit the wrapper program.";
+      };
+    options.setgid = lib.mkOption
+      { type = lib.types.bool;
+        default = false;
+        description = "Whether to add the setgid bit the wrapper program.";
+      };
+  });
+
   ###### Activation script for the setcap wrappers
   mkSetcapProgram =
     { program
     , capabilities
     , source
-    , owner  ? "nobody"
-    , group  ? "nogroup"
-    , permissions ? "u+rx,g+x,o+x"
+    , owner
+    , group
+    , permissions
     , ...
     }:
     assert (lib.versionAtLeast (lib.getVersion config.boot.kernelPackages.kernel) "4.3");
     ''
-      cp ${securityWrapper}/bin/security-wrapper $wrapperDir/${program}
-      echo -n "${source}" > $wrapperDir/${program}.real
+      cp ${securityWrapper}/bin/security-wrapper "$wrapperDir/${program}"
+      echo -n "${source}" > "$wrapperDir/${program}.real"
 
       # Prevent races
-      chmod 0000 $wrapperDir/${program}
-      chown ${owner}.${group} $wrapperDir/${program}
+      chmod 0000 "$wrapperDir/${program}"
+      chown ${owner}.${group} "$wrapperDir/${program}"
 
       # Set desired capabilities on the file plus cap_setpcap so
       # the wrapper program can elevate the capabilities set on
       # its file into the Ambient set.
-      ${pkgs.libcap.out}/bin/setcap "cap_setpcap,${capabilities}" $wrapperDir/${program}
+      ${pkgs.libcap.out}/bin/setcap "cap_setpcap,${capabilities}" "$wrapperDir/${program}"
 
       # Set the executable bit
-      chmod ${permissions} $wrapperDir/${program}
+      chmod ${permissions} "$wrapperDir/${program}"
     '';
 
   ###### Activation script for the setuid wrappers
   mkSetuidProgram =
     { program
     , source
-    , owner  ? "nobody"
-    , group  ? "nogroup"
-    , setuid ? false
-    , setgid ? false
-    , permissions ? "u+rx,g+x,o+x"
+    , owner
+    , group
+    , setuid
+    , setgid
+    , permissions
     , ...
     }:
     ''
-      cp ${securityWrapper}/bin/security-wrapper $wrapperDir/${program}
-      echo -n "${source}" > $wrapperDir/${program}.real
+      cp ${securityWrapper}/bin/security-wrapper "$wrapperDir/${program}"
+      echo -n "${source}" > "$wrapperDir/${program}.real"
 
       # Prevent races
-      chmod 0000 $wrapperDir/${program}
-      chown ${owner}.${group} $wrapperDir/${program}
+      chmod 0000 "$wrapperDir/${program}"
+      chown ${owner}.${group} "$wrapperDir/${program}"
 
-      chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" $wrapperDir/${program}
+      chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" "$wrapperDir/${program}"
     '';
 
   mkWrappedPrograms =
     builtins.map
-      (s: if (s ? capabilities)
-          then mkSetcapProgram
-                 ({ owner = "root";
-                    group = "root";
-                  } // s)
-          else if
-             (s ? setuid && s.setuid) ||
-             (s ? setgid && s.setgid) ||
-             (s ? permissions)
-          then mkSetuidProgram s
-          else mkSetuidProgram
-                 ({ owner  = "root";
-                    group  = "root";
-                    setuid = true;
-                    setgid = false;
-                    permissions = "u+rx,g+x,o+x";
-                  } // s)
-      ) programs;
+      (opts:
+        if opts.capabilities != ""
+        then mkSetcapProgram opts
+        else mkSetuidProgram opts
+      ) (lib.attrValues wrappers);
 in
 {
   imports = [
@@ -95,45 +150,42 @@ in
 
   options = {
     security.wrappers = lib.mkOption {
-      type = lib.types.attrs;
+      type = lib.types.attrsOf wrapperType;
       default = {};
       example = lib.literalExample
         ''
-          { sendmail.source = "/nix/store/.../bin/sendmail";
-            ping = {
-              source  = "${pkgs.iputils.out}/bin/ping";
-              owner   = "nobody";
-              group   = "nogroup";
-              capabilities = "cap_net_raw+ep";
-            };
+          {
+            # a setuid root program
+            doas =
+              { setuid = true;
+                owner = "root";
+                group = "root";
+                source = "''${pkgs.doas}/bin/doas";
+              };
+
+            # a setgid program
+            locate =
+              { setgid = true;
+                owner = "root";
+                group = "mlocate";
+                source = "''${pkgs.locate}/bin/locate";
+              };
+
+            # a program with the CAP_NET_RAW capability
+            ping =
+              { owner = "root";
+                group = "root";
+                capabilities = "cap_net_raw+ep";
+                source = "''${pkgs.iputils.out}/bin/ping";
+              };
           }
         '';
       description = ''
-        This option allows the ownership and permissions on the setuid
-        wrappers for specific programs to be overridden from the
-        default (setuid root, but not setgid root).
-
-        <note>
-          <para>The sub-attribute <literal>source</literal> is mandatory,
-          it must be the absolute path to the program to be wrapped.
-          </para>
-
-          <para>The sub-attribute <literal>program</literal> is optional and
-          can give the wrapper program a new name. The default name is the same
-          as the attribute name itself.</para>
-
-          <para>Additionally, this option can set capabilities on a
-          wrapper program that propagates those capabilities down to the
-          wrapped, real program.</para>
-
-          <para>NOTE: cap_setpcap, which is required for the wrapper
-          program to be able to raise caps into the Ambient set is NOT
-          raised to the Ambient set so that the real program cannot
-          modify its own capabilities!! This may be too restrictive for
-          cases in which the real program needs cap_setpcap but it at
-          least leans on the side security paranoid vs. too
-          relaxed.</para>
-        </note>
+        This option effectively allows adding setuid/setgid bits, capabilities,
+        changing file ownership and permissions of a program without directly
+        modifying it. This works by creating a wrapper program under the
+        <option>security.wrapperDir</option> directory, which is then added to
+        the shell <literal>PATH</literal>.
       '';
     };
 
@@ -151,13 +203,31 @@ in
   ###### implementation
   config = {
 
-    security.wrappers = {
-      # These are mount related wrappers that require the +s permission.
-      fusermount.source = "${pkgs.fuse}/bin/fusermount";
-      fusermount3.source = "${pkgs.fuse3}/bin/fusermount3";
-      mount.source = "${lib.getBin pkgs.util-linux}/bin/mount";
-      umount.source = "${lib.getBin pkgs.util-linux}/bin/umount";
-    };
+    assertions = lib.mapAttrsToList
+      (name: opts:
+        { assertion = opts.setuid || opts.setgid -> opts.capabilities == "";
+          message = ''
+            The security.wrappers.${name} wrapper is not valid:
+                setuid/setgid and capabilities are mutually exclusive.
+          '';
+        }
+      ) wrappers;
+
+    security.wrappers =
+      let
+        mkSetuidRoot = source:
+          { setuid = true;
+            owner = "root";
+            group = "root";
+            inherit source;
+          };
+      in
+      { # These are mount related wrappers that require the +s permission.
+        fusermount  = mkSetuidRoot "${pkgs.fuse}/bin/fusermount";
+        fusermount3 = mkSetuidRoot "${pkgs.fuse3}/bin/fusermount3";
+        mount  = mkSetuidRoot "${lib.getBin pkgs.util-linux}/bin/mount";
+        umount = mkSetuidRoot "${lib.getBin pkgs.util-linux}/bin/umount";
+      };
 
     boot.specialFileSystems.${parentWrapperDir} = {
       fsType = "tmpfs";
@@ -179,19 +249,15 @@ in
       ]}"
     '';
 
-    ###### setcap activation script
+    ###### wrappers activation script
     system.activationScripts.wrappers =
       lib.stringAfter [ "specialfs" "users" ]
         ''
-          # Look in the system path and in the default profile for
-          # programs to be wrapped.
-          WRAPPER_PATH=${config.system.path}/bin:${config.system.path}/sbin
-
           chmod 755 "${parentWrapperDir}"
 
           # We want to place the tmpdirs for the wrappers to the parent dir.
           wrapperDir=$(mktemp --directory --tmpdir="${parentWrapperDir}" wrappers.XXXXXXXXXX)
-          chmod a+rx $wrapperDir
+          chmod a+rx "$wrapperDir"
 
           ${lib.concatStringsSep "\n" mkWrappedPrograms}
 
@@ -199,16 +265,44 @@ in
             # Atomically replace the symlink
             # See https://axialcorps.com/2013/07/03/atomically-replacing-files-and-directories/
             old=$(readlink -f ${wrapperDir})
-            if [ -e ${wrapperDir}-tmp ]; then
-              rm --force --recursive ${wrapperDir}-tmp
+            if [ -e "${wrapperDir}-tmp" ]; then
+              rm --force --recursive "${wrapperDir}-tmp"
             fi
-            ln --symbolic --force --no-dereference $wrapperDir ${wrapperDir}-tmp
-            mv --no-target-directory ${wrapperDir}-tmp ${wrapperDir}
-            rm --force --recursive $old
+            ln --symbolic --force --no-dereference "$wrapperDir" "${wrapperDir}-tmp"
+            mv --no-target-directory "${wrapperDir}-tmp" "${wrapperDir}"
+            rm --force --recursive "$old"
           else
             # For initial setup
-            ln --symbolic $wrapperDir ${wrapperDir}
+            ln --symbolic "$wrapperDir" "${wrapperDir}"
           fi
         '';
+
+    ###### wrappers consistency checks
+    system.extraDependencies = lib.singleton (pkgs.runCommandLocal
+      "ensure-all-wrappers-paths-exist" { }
+      ''
+        # make sure we produce output
+        mkdir -p $out
+
+        echo -n "Checking that Nix store paths of all wrapped programs exist... "
+
+        declare -A wrappers
+        ${lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v:
+          "wrappers['${n}']='${v.source}'") wrappers)}
+
+        for name in "''${!wrappers[@]}"; do
+          path="''${wrappers[$name]}"
+          if [[ "$path" =~ /nix/store ]] && [ ! -e "$path" ]; then
+            test -t 1 && echo -ne '\033[1;31m'
+            echo "FAIL"
+            echo "The path $path does not exist!"
+            echo 'Please, check the value of `security.wrappers."'$name'".source`.'
+            test -t 1 && echo -ne '\033[0m'
+            exit 1
+          fi
+        done
+
+        echo "OK"
+      '');
   };
 }
diff --git a/nixpkgs/nixos/modules/services/backup/automysqlbackup.nix b/nixpkgs/nixos/modules/services/backup/automysqlbackup.nix
index e3a8d1f79934..4fcaf9eb9301 100644
--- a/nixpkgs/nixos/modules/services/backup/automysqlbackup.nix
+++ b/nixpkgs/nixos/modules/services/backup/automysqlbackup.nix
@@ -73,6 +73,7 @@ in
     services.automysqlbackup.config = mapAttrs (name: mkDefault) {
       mysql_dump_username = user;
       mysql_dump_host = "localhost";
+      mysql_dump_socket = "/run/mysqld/mysqld.sock";
       backup_dir = "/var/backup/mysql";
       db_exclude = [ "information_schema" "performance_schema" ];
       mailcontent = "stdout";
diff --git a/nixpkgs/nixos/modules/services/backup/borgbackup.nix b/nixpkgs/nixos/modules/services/backup/borgbackup.nix
index ccbc7726392d..c4174286fc0b 100644
--- a/nixpkgs/nixos/modules/services/backup/borgbackup.nix
+++ b/nixpkgs/nixos/modules/services/backup/borgbackup.nix
@@ -169,6 +169,7 @@ let
         (map (mkAuthorizedKey cfg false) cfg.authorizedKeys
         ++ map (mkAuthorizedKey cfg true) cfg.authorizedKeysAppendOnly);
       useDefaultShell = true;
+      group = cfg.group;
       isSystemUser = true;
     };
     groups.${cfg.group} = { };
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix
index 33d217ba60ed..08b214181806 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix
@@ -5,28 +5,33 @@ with lib;
 let
   cfg = config.services.kubernetes;
 
-  defaultContainerdConfigFile = pkgs.writeText "containerd.toml" ''
-    version = 2
-    root = "/var/lib/containerd"
-    state = "/run/containerd"
-    oom_score = 0
-
-    [grpc]
-      address = "/run/containerd/containerd.sock"
+  defaultContainerdSettings = {
+    version = 2;
+    root = "/var/lib/containerd";
+    state = "/run/containerd";
+    oom_score = 0;
+
+    grpc = {
+      address = "/run/containerd/containerd.sock";
+    };
 
-    [plugins."io.containerd.grpc.v1.cri"]
-      sandbox_image = "pause:latest"
+    plugins."io.containerd.grpc.v1.cri" = {
+      sandbox_image = "pause:latest";
 
-    [plugins."io.containerd.grpc.v1.cri".cni]
-      bin_dir = "/opt/cni/bin"
-      max_conf_num = 0
+      cni = {
+        bin_dir = "/opt/cni/bin";
+        max_conf_num = 0;
+      };
 
-    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
-      runtime_type = "io.containerd.runc.v2"
+      containerd.runtimes.runc = {
+        runtime_type = "io.containerd.runc.v2";
+      };
 
-    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes."io.containerd.runc.v2".options]
-      SystemdCgroup = true
-  '';
+      containerd.runtimes."io.containerd.runc.v2".options = {
+        SystemdCgroup = true;
+      };
+    };
+  };
 
   mkKubeConfig = name: conf: pkgs.writeText "${name}-kubeconfig" (builtins.toJSON {
     apiVersion = "v1";
@@ -248,7 +253,7 @@ in {
     (mkIf cfg.kubelet.enable {
       virtualisation.containerd = {
         enable = mkDefault true;
-        configFile = mkDefault defaultContainerdConfigFile;
+        settings = mapAttrsRecursive (name: mkDefault) defaultContainerdSettings;
       };
     })
 
diff --git a/nixpkgs/nixos/modules/services/cluster/spark/default.nix b/nixpkgs/nixos/modules/services/cluster/spark/default.nix
new file mode 100644
index 000000000000..bbfe0489f115
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/cluster/spark/default.nix
@@ -0,0 +1,162 @@
+{config, pkgs, lib, ...}:
+let
+  cfg = config.services.spark;
+in
+with lib;
+{
+  options = {
+    services.spark = {
+      master = {
+        enable = mkEnableOption "Spark master service";
+        bind = mkOption {
+          type = types.str;
+          description = "Address the spark master binds to.";
+          default = "127.0.0.1";
+          example = "0.0.0.0";
+        };
+        restartIfChanged  = mkOption {
+          type = types.bool;
+          description = ''
+            Automatically restart master service on config change.
+            This can be set to false to defer restarts on clusters running critical applications.
+            Please consider the security implications of inadvertently running an older version,
+            and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option.
+          '';
+          default = true;
+        };
+        extraEnvironment = mkOption {
+          type = types.attrsOf types.str;
+          description = "Extra environment variables to pass to spark master. See spark-standalone documentation.";
+          default = {};
+          example = {
+            SPARK_MASTER_WEBUI_PORT = 8181;
+            SPARK_MASTER_OPTS = "-Dspark.deploy.defaultCores=5";
+          };
+        };
+      };
+      worker = {
+        enable = mkEnableOption "Spark worker service";
+        workDir = mkOption {
+          type = types.path;
+          description = "Spark worker work dir.";
+          default = "/var/lib/spark";
+        };
+        master = mkOption {
+          type = types.str;
+          description = "Address of the spark master.";
+          default = "127.0.0.1:7077";
+        };
+        restartIfChanged  = mkOption {
+          type = types.bool;
+          description = ''
+            Automatically restart worker service on config change.
+            This can be set to false to defer restarts on clusters running critical applications.
+            Please consider the security implications of inadvertently running an older version,
+            and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option.
+          '';
+          default = true;
+        };
+        extraEnvironment = mkOption {
+          type = types.attrsOf types.str;
+          description = "Extra environment variables to pass to spark worker.";
+          default = {};
+          example = {
+            SPARK_WORKER_CORES = 5;
+            SPARK_WORKER_MEMORY = "2g";
+          };
+        };
+      };
+      confDir = mkOption {
+        type = types.path;
+        description = "Spark configuration directory. Spark will use the configuration files (spark-defaults.conf, spark-env.sh, log4j.properties, etc) from this directory.";
+        default = "${cfg.package}/lib/${cfg.package.untarDir}/conf";
+        defaultText = literalExample "\${cfg.package}/lib/\${cfg.package.untarDir}/conf";
+      };
+      logDir = mkOption {
+        type = types.path;
+        description = "Spark log directory.";
+        default = "/var/log/spark";
+      };
+      package = mkOption {
+        type = types.package;
+        description = "Spark package.";
+        default = pkgs.spark;
+        defaultText = "pkgs.spark";
+        example = literalExample ''pkgs.spark.overrideAttrs (super: rec {
+          pname = "spark";
+          version = "2.4.4";
+
+          src = pkgs.fetchzip {
+            url    = "mirror://apache/spark/"''${pname}-''${version}/''${pname}-''${version}-bin-without-hadoop.tgz";
+            sha256 = "1a9w5k0207fysgpxx6db3a00fs5hdc2ncx99x4ccy2s0v5ndc66g";
+          };
+        })'';
+      };
+    };
+  };
+  config = lib.mkIf (cfg.worker.enable || cfg.master.enable) {
+    environment.systemPackages = [ cfg.package ];
+    systemd = {
+      services = {
+        spark-master = lib.mkIf cfg.master.enable {
+          path = with pkgs; [ procps openssh nettools ];
+          description = "spark master service.";
+          after = [ "network.target" ];
+          wantedBy = [ "multi-user.target" ];
+          restartIfChanged = cfg.master.restartIfChanged;
+          environment = cfg.master.extraEnvironment // {
+            SPARK_MASTER_HOST = cfg.master.bind;
+            SPARK_CONF_DIR = cfg.confDir;
+            SPARK_LOG_DIR = cfg.logDir;
+          };
+          serviceConfig = {
+            Type = "forking";
+            User = "spark";
+            Group = "spark";
+            WorkingDirectory = "${cfg.package}/lib/${cfg.package.untarDir}";
+            ExecStart = "${cfg.package}/lib/${cfg.package.untarDir}/sbin/start-master.sh";
+            ExecStop  = "${cfg.package}/lib/${cfg.package.untarDir}/sbin/stop-master.sh";
+            TimeoutSec = 300;
+            StartLimitBurst=10;
+            Restart = "always";
+          };
+        };
+        spark-worker = lib.mkIf cfg.worker.enable {
+          path = with pkgs; [ procps openssh nettools rsync ];
+          description = "spark master service.";
+          after = [ "network.target" ];
+          wantedBy = [ "multi-user.target" ];
+          restartIfChanged = cfg.worker.restartIfChanged;
+          environment = cfg.worker.extraEnvironment // {
+            SPARK_MASTER = cfg.worker.master;
+            SPARK_CONF_DIR = cfg.confDir;
+            SPARK_LOG_DIR = cfg.logDir;
+            SPARK_WORKER_DIR = cfg.worker.workDir;
+          };
+          serviceConfig = {
+            Type = "forking";
+            User = "spark";
+            WorkingDirectory = "${cfg.package}/lib/${cfg.package.untarDir}";
+            ExecStart = "${cfg.package}/lib/${cfg.package.untarDir}/sbin/start-worker.sh spark://${cfg.worker.master}";
+            ExecStop  = "${cfg.package}/lib/${cfg.package.untarDir}/sbin/stop-worker.sh";
+            TimeoutSec = 300;
+            StartLimitBurst=10;
+            Restart = "always";
+          };
+        };
+      };
+      tmpfiles.rules = [
+        "d '${cfg.worker.workDir}' - spark spark - -"
+        "d '${cfg.logDir}' - spark spark - -"
+      ];
+    };
+    users = {
+      users.spark = {
+        description = "spark user.";
+        group = "spark";
+        isSystemUser = true;
+      };
+      groups.spark = { };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/databases/influxdb.nix b/nixpkgs/nixos/modules/services/databases/influxdb.nix
index dd5d69b1147a..3b8c00929ba9 100644
--- a/nixpkgs/nixos/modules/services/databases/influxdb.nix
+++ b/nixpkgs/nixos/modules/services/databases/influxdb.nix
@@ -185,6 +185,7 @@ in
     users.users = optionalAttrs (cfg.user == "influxdb") {
       influxdb = {
         uid = config.ids.uids.influxdb;
+        group = "influxdb";
         description = "Influxdb daemon user";
       };
     };
diff --git a/nixpkgs/nixos/modules/services/databases/memcached.nix b/nixpkgs/nixos/modules/services/databases/memcached.nix
index ca7b20eb049a..1c06937e2f30 100644
--- a/nixpkgs/nixos/modules/services/databases/memcached.nix
+++ b/nixpkgs/nixos/modules/services/databases/memcached.nix
@@ -67,7 +67,9 @@ in
     users.users = optionalAttrs (cfg.user == "memcached") {
       memcached.description = "Memcached server user";
       memcached.isSystemUser = true;
+      memcached.group = "memcached";
     };
+    users.groups = optionalAttrs (cfg.user == "memcached") { memcached = {}; };
 
     environment.systemPackages = [ memcached ];
 
diff --git a/nixpkgs/nixos/modules/services/databases/mongodb.nix b/nixpkgs/nixos/modules/services/databases/mongodb.nix
index db1e5fedf50d..5121e0415db1 100644
--- a/nixpkgs/nixos/modules/services/databases/mongodb.nix
+++ b/nixpkgs/nixos/modules/services/databases/mongodb.nix
@@ -123,9 +123,11 @@ in
 
     users.users.mongodb = mkIf (cfg.user == "mongodb")
       { name = "mongodb";
-        uid = config.ids.uids.mongodb;
+        isSystemUser = true;
+        group = "mongodb";
         description = "MongoDB server user";
       };
+    users.groups.mongodb = mkIf (cfg.user == "mongodb") {};
 
     environment.systemPackages = [ mongodb ];
 
diff --git a/nixpkgs/nixos/modules/services/databases/neo4j.nix b/nixpkgs/nixos/modules/services/databases/neo4j.nix
index 53760bb24c4a..2a30923538db 100644
--- a/nixpkgs/nixos/modules/services/databases/neo4j.nix
+++ b/nixpkgs/nixos/modules/services/databases/neo4j.nix
@@ -651,10 +651,12 @@ in {
       environment.systemPackages = [ cfg.package ];
 
       users.users.neo4j = {
-        uid = config.ids.uids.neo4j;
+        isSystemUser = true;
+        group = "neo4j";
         description = "Neo4j daemon user";
         home = cfg.directories.home;
       };
+      users.groups.neo4j = {};
     };
 
   meta = {
diff --git a/nixpkgs/nixos/modules/services/databases/redis.nix b/nixpkgs/nixos/modules/services/databases/redis.nix
index 8873f6d00e0b..1b9358c81a12 100644
--- a/nixpkgs/nixos/modules/services/databases/redis.nix
+++ b/nixpkgs/nixos/modules/services/databases/redis.nix
@@ -246,6 +246,7 @@ in {
 
     users.users.redis = {
       description = "Redis database user";
+      group = "redis";
       isSystemUser = true;
     };
     users.groups.redis = {};
diff --git a/nixpkgs/nixos/modules/services/desktops/cpupower-gui.nix b/nixpkgs/nixos/modules/services/desktops/cpupower-gui.nix
new file mode 100644
index 000000000000..f66afc0a3dc1
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/desktops/cpupower-gui.nix
@@ -0,0 +1,56 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.cpupower-gui;
+in {
+  options = {
+    services.cpupower-gui = {
+      enable = mkOption {
+        type = lib.types.bool;
+        default = false;
+        example = true;
+        description = ''
+          Enables dbus/systemd service needed by cpupower-gui.
+          These services are responsible for retrieving and modifying cpu power
+          saving settings.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.cpupower-gui ];
+    services.dbus.packages = [ pkgs.cpupower-gui ];
+    systemd.user = {
+      services.cpupower-gui-user = {
+        description = "Apply cpupower-gui config at user login";
+        wantedBy = [ "graphical-session.target" ];
+        serviceConfig = {
+          Type = "oneshot";
+          ExecStart = "${pkgs.cpupower-gui}/bin/cpupower-gui config";
+        };
+      };
+    };
+    systemd.services = {
+      cpupower-gui = {
+        description = "Apply cpupower-gui config at boot";
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          Type = "oneshot";
+          ExecStart = "${pkgs.cpupower-gui}/bin/cpupower-gui config";
+        };
+      };
+      cpupower-gui-helper = {
+        description = "cpupower-gui system helper";
+        aliases = [ "dbus-org.rnd2.cpupower_gui.helper.service" ];
+        serviceConfig = {
+          Type = "dbus";
+          BusName = "org.rnd2.cpupower_gui.helper";
+          ExecStart = "${pkgs.cpupower-gui}/lib/cpupower-gui/cpupower-gui-helper";
+        };
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/desktops/gnome/gnome-keyring.nix b/nixpkgs/nixos/modules/services/desktops/gnome/gnome-keyring.nix
index cda44bab8bfa..d821da164beb 100644
--- a/nixpkgs/nixos/modules/services/desktops/gnome/gnome-keyring.nix
+++ b/nixpkgs/nixos/modules/services/desktops/gnome/gnome-keyring.nix
@@ -52,8 +52,10 @@ with lib;
     security.pam.services.login.enableGnomeKeyring = true;
 
     security.wrappers.gnome-keyring-daemon = {
-      source = "${pkgs.gnome.gnome-keyring}/bin/gnome-keyring-daemon";
+      owner = "root";
+      group = "root";
       capabilities = "cap_ipc_lock=ep";
+      source = "${pkgs.gnome.gnome-keyring}/bin/gnome-keyring-daemon";
     };
 
   };
diff --git a/nixpkgs/nixos/modules/services/desktops/gsignond.nix b/nixpkgs/nixos/modules/services/desktops/gsignond.nix
index 5ab9add9f32d..465acd73fa64 100644
--- a/nixpkgs/nixos/modules/services/desktops/gsignond.nix
+++ b/nixpkgs/nixos/modules/services/desktops/gsignond.nix
@@ -9,7 +9,7 @@ let
 in
 {
 
-  meta.maintainers = pkgs.pantheon.maintainers;
+  meta.maintainers = teams.pantheon.members;
 
   ###### interface
 
diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/bluez-hardware.conf.json b/nixpkgs/nixos/modules/services/desktops/pipewire/bluez-hardware.conf.json
index 46697ece4483..e5e7517e38d4 100644
--- a/nixpkgs/nixos/modules/services/desktops/pipewire/bluez-hardware.conf.json
+++ b/nixpkgs/nixos/modules/services/desktops/pipewire/bluez-hardware.conf.json
@@ -34,6 +34,13 @@
       ]
     },
     {
+      "name": "D50s",
+      "address": "~^00:13:ef:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
       "name": "JBL Endurance RUN BT",
       "no-features": [
         "msbc-alt1",
@@ -45,6 +52,18 @@
       "name": "JBL LIVE650BTNC"
     },
     {
+      "name": "Motorola DC800",
+      "no-features": [
+        "sbc-xq"
+      ]
+    },
+    {
+      "name": "Motorola S305",
+      "no-features": [
+        "sbc-xq"
+      ]
+    },
+    {
       "name": "Soundcore Life P2-L",
       "no-features": [
         "msbc-alt1",
@@ -191,47 +210,35 @@
     },
     {
       "sysname": "Linux",
-      "release": "~^5\\.(8|9|10)\\.",
+      "release": "~^5\\.(8|9)\\.",
       "no-features": [
         "msbc-alt1"
       ]
     },
     {
       "sysname": "Linux",
-      "release": "~^5\\.10\\.(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50)($|[^0-9])"
-    },
-    {
-      "sysname": "Linux",
-      "release": "~^5\\.10\\.",
+      "release": "~^5\\.10\\.(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|51|52|53|54|55|56|57|58|59|60|61)($|[^0-9])",
       "no-features": [
         "msbc-alt1"
       ]
     },
     {
       "sysname": "Linux",
-      "release": "~^5\\.12\\.(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17)($|[^0-9])"
-    },
-    {
-      "sysname": "Linux",
-      "release": "~^5\\.12\\.",
+      "release": "~^5\\.12\\.(18|19)($|[^0-9])",
       "no-features": [
         "msbc-alt1"
       ]
     },
     {
       "sysname": "Linux",
-      "release": "~^5\\.13\\.(1|2)($|[^0-9])"
-    },
-    {
-      "sysname": "Linux",
-      "release": "~^5\\.13\\.",
+      "release": "~^5\\.13\\.(3|4|5|6|7|8|9|10|11|12|13)($|[^0-9])",
       "no-features": [
         "msbc-alt1"
       ]
     },
     {
       "sysname": "Linux",
-      "release": "~^5\\.14\\.",
+      "release": "~^5\\.14($|[^0-9])",
       "no-features": [
         "msbc-alt1"
       ]
diff --git a/nixpkgs/nixos/modules/services/display-managers/greetd.nix b/nixpkgs/nixos/modules/services/display-managers/greetd.nix
index c3072bf09964..d4f5dc267d09 100644
--- a/nixpkgs/nixos/modules/services/display-managers/greetd.nix
+++ b/nixpkgs/nixos/modules/services/display-managers/greetd.nix
@@ -99,7 +99,12 @@ in
 
     systemd.defaultUnit = "graphical.target";
 
-    users.users.greeter.isSystemUser = true;
+    users.users.greeter = {
+      isSystemUser = true;
+      group = "greeter";
+    };
+
+    users.groups.greeter = {};
   };
 
   meta.maintainers = with maintainers; [ queezle ];
diff --git a/nixpkgs/nixos/modules/services/games/minecraft-server.nix b/nixpkgs/nixos/modules/services/games/minecraft-server.nix
index eb9288fca586..458e57fef846 100644
--- a/nixpkgs/nixos/modules/services/games/minecraft-server.nix
+++ b/nixpkgs/nixos/modules/services/games/minecraft-server.nix
@@ -167,8 +167,10 @@ in {
       description     = "Minecraft server service user";
       home            = cfg.dataDir;
       createHome      = true;
-      uid             = config.ids.uids.minecraft;
+      isSystemUser    = true;
+      group           = "minecraft";
     };
+    users.groups.minecraft = {};
 
     systemd.services.minecraft-server = {
       description   = "Minecraft Server Service";
diff --git a/nixpkgs/nixos/modules/services/hardware/tcsd.nix b/nixpkgs/nixos/modules/services/hardware/tcsd.nix
index 0d36bce357ba..c549a6775013 100644
--- a/nixpkgs/nixos/modules/services/hardware/tcsd.nix
+++ b/nixpkgs/nixos/modules/services/hardware/tcsd.nix
@@ -149,12 +149,10 @@ in
     users.users = optionalAttrs (cfg.user == "tss") {
       tss = {
         group = "tss";
-        uid = config.ids.uids.tss;
+        isSystemUser = true;
       };
     };
 
-    users.groups = optionalAttrs (cfg.group == "tss") {
-      tss.gid = config.ids.gids.tss;
-    };
+    users.groups = optionalAttrs (cfg.group == "tss") { tss = {}; };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/logging/graylog.nix b/nixpkgs/nixos/modules/services/logging/graylog.nix
index af70d27fcf99..5e20a10f2490 100644
--- a/nixpkgs/nixos/modules/services/logging/graylog.nix
+++ b/nixpkgs/nixos/modules/services/logging/graylog.nix
@@ -128,10 +128,12 @@ in
 
     users.users = mkIf (cfg.user == "graylog") {
       graylog = {
-        uid = config.ids.uids.graylog;
+        isSystemUser = true;
+        group = "graylog";
         description = "Graylog server daemon user";
       };
     };
+    users.groups = mkIf (cfg.user == "graylog") {};
 
     systemd.tmpfiles.rules = [
       "d '${cfg.messageJournalDir}' - ${cfg.user} - - -"
diff --git a/nixpkgs/nixos/modules/services/logging/logcheck.nix b/nixpkgs/nixos/modules/services/logging/logcheck.nix
index 4296b2270c29..348ed8adf903 100644
--- a/nixpkgs/nixos/modules/services/logging/logcheck.nix
+++ b/nixpkgs/nixos/modules/services/logging/logcheck.nix
@@ -215,12 +215,16 @@ in
 
     users.users = optionalAttrs (cfg.user == "logcheck") {
       logcheck = {
-        uid = config.ids.uids.logcheck;
+        group = "logcheck";
+        isSystemUser = true;
         shell = "/bin/sh";
         description = "Logcheck user account";
         extraGroups = cfg.extraGroups;
       };
     };
+    users.groups = optionalAttrs (cfg.user == "logcheck") {
+      logcheck = {};
+    };
 
     system.activationScripts.logcheck = ''
       mkdir -m 700 -p /var/{lib,lock}/logcheck
diff --git a/nixpkgs/nixos/modules/services/mail/exim.nix b/nixpkgs/nixos/modules/services/mail/exim.nix
index 8927d84b478c..25b533578c94 100644
--- a/nixpkgs/nixos/modules/services/mail/exim.nix
+++ b/nixpkgs/nixos/modules/services/mail/exim.nix
@@ -104,7 +104,12 @@ in
       gid = config.ids.gids.exim;
     };
 
-    security.wrappers.exim.source = "${cfg.package}/bin/exim";
+    security.wrappers.exim =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${cfg.package}/bin/exim";
+      };
 
     systemd.services.exim = {
       description = "Exim Mail Daemon";
diff --git a/nixpkgs/nixos/modules/services/mail/mail.nix b/nixpkgs/nixos/modules/services/mail/mail.nix
index fed313e4738e..fcc7ff6db91b 100644
--- a/nixpkgs/nixos/modules/services/mail/mail.nix
+++ b/nixpkgs/nixos/modules/services/mail/mail.nix
@@ -1,4 +1,4 @@
-{ config, lib, ... }:
+{ config, options, lib, ... }:
 
 with lib;
 
@@ -11,6 +11,7 @@ with lib;
     services.mail = {
 
       sendmailSetuidWrapper = mkOption {
+        type = types.nullOr options.security.wrappers.type.nestedTypes.elemType;
         default = null;
         internal = true;
         description = ''
diff --git a/nixpkgs/nixos/modules/services/mail/opensmtpd.nix b/nixpkgs/nixos/modules/services/mail/opensmtpd.nix
index c838d3b949db..ef7d53e7d927 100644
--- a/nixpkgs/nixos/modules/services/mail/opensmtpd.nix
+++ b/nixpkgs/nixos/modules/services/mail/opensmtpd.nix
@@ -103,12 +103,15 @@ in {
     };
 
     security.wrappers.smtpctl = {
+      owner = "nobody";
       group = "smtpq";
+      setuid = false;
       setgid = true;
       source = "${cfg.package}/bin/smtpctl";
     };
 
-    services.mail.sendmailSetuidWrapper = mkIf cfg.setSendmail security.wrappers.smtpctl;
+    services.mail.sendmailSetuidWrapper = mkIf cfg.setSendmail
+      (security.wrappers.smtpctl // { program = "sendmail"; });
 
     systemd.tmpfiles.rules = [
       "d /var/spool/smtpd 711 root - - -"
diff --git a/nixpkgs/nixos/modules/services/mail/postfix.nix b/nixpkgs/nixos/modules/services/mail/postfix.nix
index 9b0a5bba2feb..2b8edb9c51f8 100644
--- a/nixpkgs/nixos/modules/services/mail/postfix.nix
+++ b/nixpkgs/nixos/modules/services/mail/postfix.nix
@@ -673,6 +673,7 @@ in
       services.mail.sendmailSetuidWrapper = mkIf config.services.postfix.setSendmail {
         program = "sendmail";
         source = "${pkgs.postfix}/bin/sendmail";
+        owner = "nobody";
         group = setgidGroup;
         setuid = false;
         setgid = true;
@@ -681,6 +682,7 @@ in
       security.wrappers.mailq = {
         program = "mailq";
         source = "${pkgs.postfix}/bin/mailq";
+        owner = "nobody";
         group = setgidGroup;
         setuid = false;
         setgid = true;
@@ -689,6 +691,7 @@ in
       security.wrappers.postqueue = {
         program = "postqueue";
         source = "${pkgs.postfix}/bin/postqueue";
+        owner = "nobody";
         group = setgidGroup;
         setuid = false;
         setgid = true;
@@ -697,6 +700,7 @@ in
       security.wrappers.postdrop = {
         program = "postdrop";
         source = "${pkgs.postfix}/bin/postdrop";
+        owner = "nobody";
         group = setgidGroup;
         setuid = false;
         setgid = true;
diff --git a/nixpkgs/nixos/modules/services/misc/airsonic.nix b/nixpkgs/nixos/modules/services/misc/airsonic.nix
index 490f6c5a5c06..c1ce515750b0 100644
--- a/nixpkgs/nixos/modules/services/misc/airsonic.nix
+++ b/nixpkgs/nixos/modules/services/misc/airsonic.nix
@@ -165,10 +165,12 @@ in {
 
     users.users.airsonic = {
       description = "Airsonic service user";
+      group = "airsonic";
       name = cfg.user;
       home = cfg.home;
       createHome = true;
       isSystemUser = true;
     };
+    users.groups.airsonic = {};
   };
 }
diff --git a/nixpkgs/nixos/modules/services/misc/apache-kafka.nix b/nixpkgs/nixos/modules/services/misc/apache-kafka.nix
index 69dfadfe54e0..8bc307311a42 100644
--- a/nixpkgs/nixos/modules/services/misc/apache-kafka.nix
+++ b/nixpkgs/nixos/modules/services/misc/apache-kafka.nix
@@ -120,10 +120,12 @@ in {
     environment.systemPackages = [cfg.package];
 
     users.users.apache-kafka = {
-      uid = config.ids.uids.apache-kafka;
+      isSystemUser = true;
+      group = "apache-kafka";
       description = "Apache Kafka daemon user";
       home = head cfg.logDirs;
     };
+    users.groups.apache-kafka = {};
 
     systemd.tmpfiles.rules = map (logDir: "d '${logDir}' 0700 apache-kafka - - -") cfg.logDirs;
 
diff --git a/nixpkgs/nixos/modules/services/misc/cgminer.nix b/nixpkgs/nixos/modules/services/misc/cgminer.nix
index 662570f9451f..5afc1546efa9 100644
--- a/nixpkgs/nixos/modules/services/misc/cgminer.nix
+++ b/nixpkgs/nixos/modules/services/misc/cgminer.nix
@@ -86,7 +86,7 @@ in
 
       config = mkOption {
         default = {};
-        type = (types.either types.bool types.int);
+        type = types.attrsOf (types.either types.bool types.int);
         description = "Additional config";
         example = {
           auto-fan = true;
@@ -110,10 +110,14 @@ in
 
     users.users = optionalAttrs (cfg.user == "cgminer") {
       cgminer = {
-        uid = config.ids.uids.cgminer;
+        isSystemUser = true;
+        group = "cgminer";
         description = "Cgminer user";
       };
     };
+    users.groups = optionalAttrs (cfg.user == "cgminer") {
+      cgminer = {};
+    };
 
     environment.systemPackages = [ cfg.package ];
 
diff --git a/nixpkgs/nixos/modules/services/misc/docker-registry.nix b/nixpkgs/nixos/modules/services/misc/docker-registry.nix
index e212f581c28a..cb68a29c530b 100644
--- a/nixpkgs/nixos/modules/services/misc/docker-registry.nix
+++ b/nixpkgs/nixos/modules/services/misc/docker-registry.nix
@@ -151,7 +151,9 @@ in {
         home = cfg.storagePath;
       }
       else {}) // {
+        group = "docker-registry";
         isSystemUser = true;
       };
+    users.groups.docker-registry = {};
   };
 }
diff --git a/nixpkgs/nixos/modules/services/misc/etcd.nix b/nixpkgs/nixos/modules/services/misc/etcd.nix
index eb266f043ebc..2b667fab6b04 100644
--- a/nixpkgs/nixos/modules/services/misc/etcd.nix
+++ b/nixpkgs/nixos/modules/services/misc/etcd.nix
@@ -187,9 +187,11 @@ in {
     environment.systemPackages = [ pkgs.etcd ];
 
     users.users.etcd = {
-      uid = config.ids.uids.etcd;
+      isSystemUser = true;
+      group = "etcd";
       description = "Etcd daemon user";
       home = cfg.dataDir;
     };
+    users.groups.etcd = {};
   };
 }
diff --git a/nixpkgs/nixos/modules/services/misc/gammu-smsd.nix b/nixpkgs/nixos/modules/services/misc/gammu-smsd.nix
index 552725f1384d..d4bb58d81dde 100644
--- a/nixpkgs/nixos/modules/services/misc/gammu-smsd.nix
+++ b/nixpkgs/nixos/modules/services/misc/gammu-smsd.nix
@@ -202,8 +202,8 @@ in {
   config = mkIf cfg.enable {
     users.users.${cfg.user} = {
       description = "gammu-smsd user";
-      uid = config.ids.uids.gammu-smsd;
-      extraGroups = [ "${cfg.device.group}" ];
+      isSystemUser = true;
+      group = cfg.device.group;
     };
 
     environment.systemPackages = with cfg.backend; [ gammuPackage ]
diff --git a/nixpkgs/nixos/modules/services/misc/gitlab.nix b/nixpkgs/nixos/modules/services/misc/gitlab.nix
index 805deeee0c04..c1a1491b3cee 100644
--- a/nixpkgs/nixos/modules/services/misc/gitlab.nix
+++ b/nixpkgs/nixos/modules/services/misc/gitlab.nix
@@ -821,6 +821,40 @@ in {
         '';
       };
 
+      logrotate = {
+        enable = mkOption {
+          type = types.bool;
+          default = true;
+          description = ''
+            Enable rotation of log files.
+          '';
+        };
+
+        frequency = mkOption {
+          type = types.str;
+          default = "daily";
+          description = "How often to rotate the logs.";
+        };
+
+        keep = mkOption {
+          type = types.int;
+          default = 30;
+          description = "How many rotations to keep.";
+        };
+
+        extraConfig = mkOption {
+          type = types.lines;
+          default = ''
+            copytruncate
+            compress
+          '';
+          description = ''
+            Extra logrotate config options for this path. Refer to
+            <link xlink:href="https://linux.die.net/man/8/logrotate"/> for details.
+          '';
+        };
+      };
+
       extraConfig = mkOption {
         type = types.attrs;
         default = {};
@@ -932,6 +966,21 @@ in {
       ensureUsers = singleton { name = cfg.databaseUsername; };
     };
 
+    # Enable rotation of log files
+    services.logrotate = {
+      enable = cfg.logrotate.enable;
+      paths = {
+        gitlab = {
+          path = "${cfg.statePath}/log/*.log";
+          user = cfg.user;
+          group = cfg.group;
+          frequency = cfg.logrotate.frequency;
+          keep = cfg.logrotate.keep;
+          extraConfig = cfg.logrotate.extraConfig;
+        };
+      };
+    };
+
     # The postgresql module doesn't currently support concepts like
     # objects owners and extensions; for now we tack on what's needed
     # here.
diff --git a/nixpkgs/nixos/modules/services/misc/gpsd.nix b/nixpkgs/nixos/modules/services/misc/gpsd.nix
index fafea10daba7..6494578f7647 100644
--- a/nixpkgs/nixos/modules/services/misc/gpsd.nix
+++ b/nixpkgs/nixos/modules/services/misc/gpsd.nix
@@ -88,6 +88,7 @@ in
 
     users.users.gpsd =
       { inherit uid;
+        group = "gpsd";
         description = "gpsd daemon user";
         home = "/var/empty";
       };
diff --git a/nixpkgs/nixos/modules/services/misc/home-assistant.nix b/nixpkgs/nixos/modules/services/misc/home-assistant.nix
index 73ec3b9a17a2..800bea4ff571 100644
--- a/nixpkgs/nixos/modules/services/misc/home-assistant.nix
+++ b/nixpkgs/nixos/modules/services/misc/home-assistant.nix
@@ -310,11 +310,13 @@ in {
           "serial_pm"
           "sms"
           "upb"
+          "usb"
           "velbus"
           "w800rf32"
           "xbee"
           "zha"
           "zwave"
+          "zwave_js"
         ];
       in {
         ExecStart = "${package}/bin/hass --runner --config '${cfg.configDir}'";
diff --git a/nixpkgs/nixos/modules/services/misc/mame.nix b/nixpkgs/nixos/modules/services/misc/mame.nix
index 4b9a04be7c29..dd6c5ef9aa00 100644
--- a/nixpkgs/nixos/modules/services/misc/mame.nix
+++ b/nixpkgs/nixos/modules/services/misc/mame.nix
@@ -45,8 +45,10 @@ in
     environment.systemPackages = [ pkgs.mame ];
 
     security.wrappers."${mame}" = {
-      source = "${pkgs.mame}/bin/${mame}";
+      owner = "root";
+      group = "root";
       capabilities = "cap_net_admin,cap_net_raw+eip";
+      source = "${pkgs.mame}/bin/${mame}";
     };
 
     systemd.services.mame = {
diff --git a/nixpkgs/nixos/modules/services/misc/nix-ssh-serve.nix b/nixpkgs/nixos/modules/services/misc/nix-ssh-serve.nix
index 1764c6d79649..d5c64fdb2647 100644
--- a/nixpkgs/nixos/modules/services/misc/nix-ssh-serve.nix
+++ b/nixpkgs/nixos/modules/services/misc/nix-ssh-serve.nix
@@ -44,9 +44,11 @@ in {
 
     users.users.nix-ssh = {
       description = "Nix SSH store user";
-      uid = config.ids.uids.nix-ssh;
+      isSystemUser = true;
+      group = "nix-ssh";
       useDefaultShell = true;
     };
+    users.groups.nix-ssh = {};
 
     services.openssh.enable = true;
 
diff --git a/nixpkgs/nixos/modules/services/misc/owncast.nix b/nixpkgs/nixos/modules/services/misc/owncast.nix
new file mode 100644
index 000000000000..0852335238fd
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/misc/owncast.nix
@@ -0,0 +1,98 @@
+{ lib, pkgs, config, ... }:
+with lib;
+let cfg = config.services.owncast;
+in {
+
+  options.services.owncast = {
+
+    enable = mkEnableOption "owncast";
+
+    dataDir = mkOption {
+      type = types.str;
+      default = "/var/lib/owncast";
+      description = ''
+        The directory where owncast stores its data files. If left as the default value this directory will automatically be created before the owncast server starts, otherwise the sysadmin is responsible for ensuring the directory exists with appropriate ownership and permissions.
+      '';
+    };
+
+    openFirewall = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Open the appropriate ports in the firewall for owncast.
+      '';
+    };
+
+    user = mkOption {
+      type = types.str;
+      default = "owncast";
+      description = "User account under which owncast runs.";
+    };
+
+    group = mkOption {
+      type = types.str;
+      default = "owncast";
+      description = "Group under which owncast runs.";
+    };
+
+    listen = mkOption {
+      type = types.str;
+      default = "127.0.0.1";
+      example = "0.0.0.0";
+      description = "The IP address to bind the owncast web server to.";
+    };
+
+    port = mkOption {
+      type = types.port;
+      default = 8080;
+      description = ''
+        TCP port where owncast web-gui listens.
+      '';
+    };
+
+    rtmp-port = mkOption {
+      type = types.port;
+      default = 1935;
+      description = ''
+        TCP port where owncast rtmp service listens.
+      '';
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd.services.owncast = {
+      description = "A self-hosted live video and web chat server";
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = mkMerge [
+        {
+          User = cfg.user;
+          Group = cfg.group;
+          WorkingDirectory = cfg.dataDir;
+          ExecStart = "${pkgs.owncast}/bin/owncast -webserverport ${toString cfg.port} -rtmpport ${toString cfg.rtmp-port} -webserverip ${cfg.listen}";
+          Restart = "on-failure";
+        }
+        (mkIf (cfg.dataDir == "/var/lib/owncast") {
+          StateDirectory = "owncast";
+        })
+      ];
+    };
+
+    users.users = mkIf (cfg.user == "owncast") {
+      owncast = {
+        isSystemUser = true;
+        group = cfg.group;
+        description = "owncast system user";
+      };
+    };
+
+    users.groups = mkIf (cfg.group == "owncast") { owncast = { }; };
+
+    networking.firewall =
+      mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.rtmp-port ] ++ optional (cfg.listen != "127.0.0.1") cfg.port; };
+
+  };
+  meta = { maintainers = with lib.maintainers; [ MayNiklas ]; };
+}
diff --git a/nixpkgs/nixos/modules/services/misc/ripple-data-api.nix b/nixpkgs/nixos/modules/services/misc/ripple-data-api.nix
index 9fab462f7e3b..93eba98b7d30 100644
--- a/nixpkgs/nixos/modules/services/misc/ripple-data-api.nix
+++ b/nixpkgs/nixos/modules/services/misc/ripple-data-api.nix
@@ -187,7 +187,9 @@ in {
 
     users.users.ripple-data-api =
       { description = "Ripple data api user";
-        uid = config.ids.uids.ripple-data-api;
+        isSystemUser = true;
+        group = "ripple-data-api";
       };
+    users.groups.ripple-data-api = {};
   };
 }
diff --git a/nixpkgs/nixos/modules/services/misc/rippled.nix b/nixpkgs/nixos/modules/services/misc/rippled.nix
index 2fce3b9dc94c..8cdfe0875d89 100644
--- a/nixpkgs/nixos/modules/services/misc/rippled.nix
+++ b/nixpkgs/nixos/modules/services/misc/rippled.nix
@@ -407,12 +407,14 @@ in
 
   config = mkIf cfg.enable {
 
-    users.users.rippled =
-      { description = "Ripple server user";
-        uid = config.ids.uids.rippled;
+    users.users.rippled = {
+        description = "Ripple server user";
+        isSystemUser = true;
+        group = "rippled";
         home = cfg.databasePath;
         createHome = true;
       };
+    users.groups.rippled = {};
 
     systemd.services.rippled = {
       after = [ "network.target" ];
diff --git a/nixpkgs/nixos/modules/services/misc/safeeyes.nix b/nixpkgs/nixos/modules/services/misc/safeeyes.nix
index 1e748195e41a..638218d8bb00 100644
--- a/nixpkgs/nixos/modules/services/misc/safeeyes.nix
+++ b/nixpkgs/nixos/modules/services/misc/safeeyes.nix
@@ -26,12 +26,16 @@ in
 
   config = mkIf cfg.enable {
 
+    environment.systemPackages = [ pkgs.safeeyes ];
+
     systemd.user.services.safeeyes = {
       description = "Safeeyes";
 
       wantedBy = [ "graphical-session.target" ];
       partOf   = [ "graphical-session.target" ];
 
+      path = [ pkgs.alsa-utils ];
+
       startLimitIntervalSec = 350;
       startLimitBurst = 10;
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/misc/weechat.nix b/nixpkgs/nixos/modules/services/misc/weechat.nix
index b71250f62e0f..9ac2b0ea490c 100644
--- a/nixpkgs/nixos/modules/services/misc/weechat.nix
+++ b/nixpkgs/nixos/modules/services/misc/weechat.nix
@@ -52,7 +52,12 @@ in
       wants = [ "network.target" ];
     };
 
-    security.wrappers.screen.source = "${pkgs.screen}/bin/screen";
+    security.wrappers.screen =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${pkgs.screen}/bin/screen";
+      };
   };
 
   meta.doc = ./weechat.xml;
diff --git a/nixpkgs/nixos/modules/services/misc/zookeeper.nix b/nixpkgs/nixos/modules/services/misc/zookeeper.nix
index 1d12e81a9eca..0e5880983e44 100644
--- a/nixpkgs/nixos/modules/services/misc/zookeeper.nix
+++ b/nixpkgs/nixos/modules/services/misc/zookeeper.nix
@@ -148,9 +148,11 @@ in {
     };
 
     users.users.zookeeper = {
-      uid = config.ids.uids.zookeeper;
+      isSystemUser = true;
+      group = "zookeeper";
       description = "Zookeeper daemon user";
       home = cfg.dataDir;
     };
+    users.groups.zookeeper = {};
   };
 }
diff --git a/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix b/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix
index b25a53435d06..ea9eca180902 100644
--- a/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix
@@ -51,7 +51,7 @@ in {
   options.services.datadog-agent = {
     enable = mkOption {
       description = ''
-        Whether to enable the datadog-agent v6 monitoring service
+        Whether to enable the datadog-agent v7 monitoring service
       '';
       default = false;
       type = types.bool;
@@ -61,7 +61,7 @@ in {
       default = pkgs.datadog-agent;
       defaultText = "pkgs.datadog-agent";
       description = ''
-        Which DataDog v6 agent package to use. Note that the provided
+        Which DataDog v7 agent package to use. Note that the provided
         package is expected to have an overridable `pythonPackages`-attribute
         which configures the Python environment with the Datadog
         checks.
@@ -274,7 +274,7 @@ in {
         path = [ ];
         script = ''
           export DD_API_KEY=$(head -n 1 ${cfg.apiKeyFile})
-          ${pkgs.datadog-process-agent}/bin/agent --config /etc/datadog-agent/datadog.yaml
+          ${pkgs.datadog-process-agent}/bin/process-agent --config /etc/datadog-agent/datadog.yaml
         '';
       });
 
diff --git a/nixpkgs/nixos/modules/services/monitoring/graphite.nix b/nixpkgs/nixos/modules/services/monitoring/graphite.nix
index 9213748d3c9a..502afce5233b 100644
--- a/nixpkgs/nixos/modules/services/monitoring/graphite.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/graphite.nix
@@ -561,6 +561,7 @@ in {
      ) {
       users.users.graphite = {
         uid = config.ids.uids.graphite;
+        group = "graphite";
         description = "Graphite daemon user";
         home = dataDir;
       };
diff --git a/nixpkgs/nixos/modules/services/monitoring/heapster.nix b/nixpkgs/nixos/modules/services/monitoring/heapster.nix
index 0a9dfa12eaa5..1bf7203d6823 100644
--- a/nixpkgs/nixos/modules/services/monitoring/heapster.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/heapster.nix
@@ -50,8 +50,10 @@ in {
     };
 
     users.users.heapster = {
-      uid = config.ids.uids.heapster;
+      isSystemUser = true;
+      group = "heapster";
       description = "Heapster user";
     };
+    users.groups.heapster = {};
   };
 }
diff --git a/nixpkgs/nixos/modules/services/monitoring/incron.nix b/nixpkgs/nixos/modules/services/monitoring/incron.nix
index dc97af58562e..255e1d9e30ba 100644
--- a/nixpkgs/nixos/modules/services/monitoring/incron.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/incron.nix
@@ -71,7 +71,12 @@ in
 
     environment.systemPackages = [ pkgs.incron ];
 
-    security.wrappers.incrontab.source = "${pkgs.incron}/bin/incrontab";
+    security.wrappers.incrontab =
+    { setuid = true;
+      owner = "root";
+      group = "root";
+      source = "${pkgs.incron}/bin/incrontab";
+    };
 
     # incron won't read symlinks
     environment.etc."incron.d/system" = {
diff --git a/nixpkgs/nixos/modules/services/monitoring/netdata.nix b/nixpkgs/nixos/modules/services/monitoring/netdata.nix
index 561ce3eec625..3ea84ca815f4 100644
--- a/nixpkgs/nixos/modules/services/monitoring/netdata.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/netdata.nix
@@ -9,9 +9,9 @@ let
     mkdir -p $out/libexec/netdata/plugins.d
     ln -s /run/wrappers/bin/apps.plugin $out/libexec/netdata/plugins.d/apps.plugin
     ln -s /run/wrappers/bin/cgroup-network $out/libexec/netdata/plugins.d/cgroup-network
-    ln -s /run/wrappers/bin/freeipmi.plugin $out/libexec/netdata/plugins.d/freeipmi.plugin
     ln -s /run/wrappers/bin/perf.plugin $out/libexec/netdata/plugins.d/perf.plugin
     ln -s /run/wrappers/bin/slabinfo.plugin $out/libexec/netdata/plugins.d/slabinfo.plugin
+    ln -s /run/wrappers/bin/freeipmi.plugin $out/libexec/netdata/plugins.d/freeipmi.plugin
   '';
 
   plugins = [
@@ -211,44 +211,47 @@ in {
 
     systemd.enableCgroupAccounting = true;
 
-    security.wrappers."apps.plugin" = {
-      source = "${cfg.package}/libexec/netdata/plugins.d/apps.plugin.org";
-      capabilities = "cap_dac_read_search,cap_sys_ptrace+ep";
-      owner = cfg.user;
-      group = cfg.group;
-      permissions = "u+rx,g+x,o-rwx";
-    };
+    security.wrappers = {
+      "apps.plugin" = {
+        source = "${cfg.package}/libexec/netdata/plugins.d/apps.plugin.org";
+        capabilities = "cap_dac_read_search,cap_sys_ptrace+ep";
+        owner = cfg.user;
+        group = cfg.group;
+        permissions = "u+rx,g+x,o-rwx";
+      };
 
-    security.wrappers."cgroup-network" = {
-      source = "${cfg.package}/libexec/netdata/plugins.d/cgroup-network.org";
-      capabilities = "cap_setuid+ep";
-      owner = cfg.user;
-      group = cfg.group;
-      permissions = "u+rx,g+x,o-rwx";
-    };
+      "cgroup-network" = {
+        source = "${cfg.package}/libexec/netdata/plugins.d/cgroup-network.org";
+        capabilities = "cap_setuid+ep";
+        owner = cfg.user;
+        group = cfg.group;
+        permissions = "u+rx,g+x,o-rwx";
+      };
 
-    security.wrappers."freeipmi.plugin" = {
-      source = "${cfg.package}/libexec/netdata/plugins.d/freeipmi.plugin.org";
-      capabilities = "cap_dac_override,cap_fowner+ep";
-      owner = cfg.user;
-      group = cfg.group;
-      permissions = "u+rx,g+x,o-rwx";
-    };
+      "perf.plugin" = {
+        source = "${cfg.package}/libexec/netdata/plugins.d/perf.plugin.org";
+        capabilities = "cap_sys_admin+ep";
+        owner = cfg.user;
+        group = cfg.group;
+        permissions = "u+rx,g+x,o-rwx";
+      };
 
-    security.wrappers."perf.plugin" = {
-      source = "${cfg.package}/libexec/netdata/plugins.d/perf.plugin.org";
-      capabilities = "cap_sys_admin+ep";
-      owner = cfg.user;
-      group = cfg.group;
-      permissions = "u+rx,g+x,o-rwx";
-    };
+      "slabinfo.plugin" = {
+        source = "${cfg.package}/libexec/netdata/plugins.d/slabinfo.plugin.org";
+        capabilities = "cap_dac_override+ep";
+        owner = cfg.user;
+        group = cfg.group;
+        permissions = "u+rx,g+x,o-rwx";
+      };
 
-    security.wrappers."slabinfo.plugin" = {
-      source = "${cfg.package}/libexec/netdata/plugins.d/slabinfo.plugin.org";
-      capabilities = "cap_dac_override+ep";
-      owner = cfg.user;
-      group = cfg.group;
-      permissions = "u+rx,g+x,o-rwx";
+    } // optionalAttrs (cfg.package.withIpmi) {
+      "freeipmi.plugin" = {
+        source = "${cfg.package}/libexec/netdata/plugins.d/freeipmi.plugin.org";
+        capabilities = "cap_dac_override,cap_fowner+ep";
+        owner = cfg.user;
+        group = cfg.group;
+        permissions = "u+rx,g+x,o-rwx";
+      };
     };
 
     security.pam.loginLimits = [
@@ -258,6 +261,7 @@ in {
 
     users.users = optionalAttrs (cfg.user == defaultUser) {
       ${defaultUser} = {
+        group = defaultUser;
         isSystemUser = true;
       };
     };
diff --git a/nixpkgs/nixos/modules/services/monitoring/parsedmarc.md b/nixpkgs/nixos/modules/services/monitoring/parsedmarc.md
new file mode 100644
index 000000000000..d93134a4cc76
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/parsedmarc.md
@@ -0,0 +1,113 @@
+# parsedmarc {#module-services-parsedmarc}
+[parsedmarc](https://domainaware.github.io/parsedmarc/) is a service
+which parses incoming [DMARC](https://dmarc.org/) reports and stores
+or sends them to a downstream service for further analysis. In
+combination with Elasticsearch, Grafana and the included Grafana
+dashboard, it provides a handy overview of DMARC reports over time.
+
+## Basic usage {#module-services-parsedmarc-basic-usage}
+A very minimal setup which reads incoming reports from an external
+email address and saves them to a local Elasticsearch instance looks
+like this:
+
+```nix
+services.parsedmarc = {
+  enable = true;
+  settings.imap = {
+    host = "imap.example.com";
+    user = "alice@example.com";
+    password = "/path/to/imap_password_file";
+    watch = true;
+  };
+  provision.geoIp = false; # Not recommended!
+};
+```
+
+Note that GeoIP provisioning is disabled in the example for
+simplicity, but should be turned on for fully functional reports.
+
+## Local mail
+Instead of watching an external inbox, a local inbox can be
+automatically provisioned. The recipient's name is by default set to
+`dmarc`, but can be configured in
+[services.parsedmarc.provision.localMail.recipientName](options.html#opt-services.parsedmarc.provision.localMail.recipientName). You
+need to add an MX record pointing to the host. More concretely: for
+the example to work, an MX record needs to be set up for
+`monitoring.example.com` and the complete email address that should be
+configured in the domain's dmarc policy is
+`dmarc@monitoring.example.com`.
+
+```nix
+services.parsedmarc = {
+  enable = true;
+  provision = {
+    localMail = {
+      enable = true;
+      hostname = monitoring.example.com;
+    };
+    geoIp = false; # Not recommended!
+  };
+};
+```
+
+## Grafana and GeoIP
+The reports can be visualized and summarized with parsedmarc's
+official Grafana dashboard. For all views to work, and for the data to
+be complete, GeoIP databases are also required. The following example
+shows a basic deployment where the provisioned Elasticsearch instance
+is automatically added as a Grafana datasource, and the dashboard is
+added to Grafana as well.
+
+```nix
+services.parsedmarc = {
+  enable = true;
+  provision = {
+    localMail = {
+      enable = true;
+      hostname = url;
+    };
+    grafana = {
+      datasource = true;
+      dashboard = true;
+    };
+  };
+};
+
+# Not required, but recommended for full functionality
+services.geoipupdate = {
+  settings = {
+    AccountID = 000000;
+    LicenseKey = "/path/to/license_key_file";
+  };
+};
+
+services.grafana = {
+  enable = true;
+  addr = "0.0.0.0";
+  domain = url;
+  rootUrl = "https://" + url;
+  protocol = "socket";
+  security = {
+    adminUser = "admin";
+    adminPasswordFile = "/path/to/admin_password_file";
+    secretKeyFile = "/path/to/secret_key_file";
+  };
+};
+
+services.nginx = {
+  enable = true;
+  recommendedTlsSettings = true;
+  recommendedOptimisation = true;
+  recommendedGzipSettings = true;
+  recommendedProxySettings = true;
+  upstreams.grafana.servers."unix:/${config.services.grafana.socket}" = {};
+  virtualHosts.${url} = {
+    root = config.services.grafana.staticRootPath;
+    enableACME = true;
+    forceSSL = true;
+    locations."/".tryFiles = "$uri @grafana";
+    locations."@grafana".proxyPass = "http://grafana";
+  };
+};
+users.users.nginx.extraGroups = [ "grafana" ];
+```
diff --git a/nixpkgs/nixos/modules/services/monitoring/parsedmarc.nix b/nixpkgs/nixos/modules/services/monitoring/parsedmarc.nix
new file mode 100644
index 000000000000..e6a72dea0260
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/parsedmarc.nix
@@ -0,0 +1,537 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.parsedmarc;
+  ini = pkgs.formats.ini {};
+in
+{
+  options.services.parsedmarc = {
+
+    enable = lib.mkEnableOption ''
+      parsedmarc, a DMARC report monitoring service
+    '';
+
+    provision = {
+      localMail = {
+        enable = lib.mkOption {
+          type = lib.types.bool;
+          default = false;
+          description = ''
+            Whether Postfix and Dovecot should be set up to receive
+            mail locally. parsedmarc will be configured to watch the
+            local inbox as the automatically created user specified in
+            <xref linkend="opt-services.parsedmarc.provision.localMail.recipientName" />
+          '';
+        };
+
+        recipientName = lib.mkOption {
+          type = lib.types.str;
+          default = "dmarc";
+          description = ''
+            The DMARC mail recipient name, i.e. the name part of the
+            email address which receives DMARC reports.
+
+            A local user with this name will be set up and assigned a
+            randomized password on service start.
+          '';
+        };
+
+        hostname = lib.mkOption {
+          type = lib.types.str;
+          default = config.networking.fqdn;
+          defaultText = "config.networking.fqdn";
+          example = "monitoring.example.com";
+          description = ''
+            The hostname to use when configuring Postfix.
+
+            Should correspond to the host's fully qualified domain
+            name and the domain part of the email address which
+            receives DMARC reports. You also have to set up an MX record
+            pointing to this domain name.
+          '';
+        };
+      };
+
+      geoIp = lib.mkOption {
+        type = lib.types.bool;
+        default = true;
+        description = ''
+          Whether to enable and configure the <link
+          linkend="opt-services.geoipupdate.enable">geoipupdate</link>
+          service to automatically fetch GeoIP databases. Not crucial,
+          but recommended for full functionality.
+
+          To finish the setup, you need to manually set the <xref
+          linkend="opt-services.geoipupdate.settings.AccountID" /> and
+          <xref linkend="opt-services.geoipupdate.settings.LicenseKey" />
+          options.
+        '';
+      };
+
+      elasticsearch = lib.mkOption {
+        type = lib.types.bool;
+        default = true;
+        description = ''
+          Whether to set up and use a local instance of Elasticsearch.
+        '';
+      };
+
+      grafana = {
+        datasource = lib.mkOption {
+          type = lib.types.bool;
+          default = cfg.provision.elasticsearch && config.services.grafana.enable;
+          apply = x: x && cfg.provision.elasticsearch;
+          description = ''
+            Whether the automatically provisioned Elasticsearch
+            instance should be added as a grafana datasource. Has no
+            effect unless
+            <xref linkend="opt-services.parsedmarc.provision.elasticsearch" />
+            is also enabled.
+          '';
+        };
+
+        dashboard = lib.mkOption {
+          type = lib.types.bool;
+          default = config.services.grafana.enable;
+          description = ''
+            Whether the official parsedmarc grafana dashboard should
+            be provisioned to the local grafana instance.
+          '';
+        };
+      };
+    };
+
+    settings = lib.mkOption {
+      description = ''
+        Configuration parameters to set in
+        <filename>parsedmarc.ini</filename>. For a full list of
+        available parameters, see
+        <link xlink:href="https://domainaware.github.io/parsedmarc/#configuration-file" />.
+      '';
+
+      type = lib.types.submodule {
+        freeformType = ini.type;
+
+        options = {
+          general = {
+            save_aggregate = lib.mkOption {
+              type = lib.types.bool;
+              default = true;
+              description = ''
+                Save aggregate report data to Elasticsearch and/or Splunk.
+              '';
+            };
+
+            save_forensic = lib.mkOption {
+              type = lib.types.bool;
+              default = true;
+              description = ''
+                Save forensic report data to Elasticsearch and/or Splunk.
+              '';
+            };
+          };
+
+          imap = {
+            host = lib.mkOption {
+              type = lib.types.str;
+              default = "localhost";
+              description = ''
+                The IMAP server hostname or IP address.
+              '';
+            };
+
+            port = lib.mkOption {
+              type = lib.types.port;
+              default = 993;
+              description = ''
+                The IMAP server port.
+              '';
+            };
+
+            ssl = lib.mkOption {
+              type = lib.types.bool;
+              default = true;
+              description = ''
+                Use an encrypted SSL/TLS connection.
+              '';
+            };
+
+            user = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = null;
+              description = ''
+                The IMAP server username.
+              '';
+            };
+
+            password = lib.mkOption {
+              type = with lib.types; nullOr path;
+              default = null;
+              description = ''
+                The path to a file containing the IMAP server password.
+              '';
+            };
+
+            watch = lib.mkOption {
+              type = lib.types.bool;
+              default = true;
+              description = ''
+                Use the IMAP IDLE command to process messages as they arrive.
+              '';
+            };
+
+            delete = lib.mkOption {
+              type = lib.types.bool;
+              default = false;
+              description = ''
+                Delete messages after processing them, instead of archiving them.
+              '';
+            };
+          };
+
+          smtp = {
+            host = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = null;
+              description = ''
+                The SMTP server hostname or IP address.
+              '';
+            };
+
+            port = lib.mkOption {
+              type = with lib.types; nullOr port;
+              default = null;
+              description = ''
+                The SMTP server port.
+              '';
+            };
+
+            ssl = lib.mkOption {
+              type = with lib.types; nullOr bool;
+              default = null;
+              description = ''
+                Use an encrypted SSL/TLS connection.
+              '';
+            };
+
+            user = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = null;
+              description = ''
+                The SMTP server username.
+              '';
+            };
+
+            password = lib.mkOption {
+              type = with lib.types; nullOr path;
+              default = null;
+              description = ''
+                The path to a file containing the SMTP server password.
+              '';
+            };
+
+            from = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = null;
+              description = ''
+                The <literal>From</literal> address to use for the
+                outgoing mail.
+              '';
+            };
+
+            to = lib.mkOption {
+              type = with lib.types; nullOr (listOf str);
+              default = null;
+              description = ''
+                The addresses to send outgoing mail to.
+              '';
+            };
+          };
+
+          elasticsearch = {
+            hosts = lib.mkOption {
+              default = [];
+              type = with lib.types; listOf str;
+              apply = x: if x == [] then null else lib.concatStringsSep "," x;
+              description = ''
+                A list of Elasticsearch hosts to push parsed reports
+                to.
+              '';
+            };
+
+            user = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = null;
+              description = ''
+                Username to use when connecting to Elasticsearch, if
+                required.
+              '';
+            };
+
+            password = lib.mkOption {
+              type = with lib.types; nullOr path;
+              default = null;
+              description = ''
+                The path to a file containing the password to use when
+                connecting to Elasticsearch, if required.
+              '';
+            };
+
+            ssl = lib.mkOption {
+              type = lib.types.bool;
+              default = false;
+              description = ''
+                Whether to use an encrypted SSL/TLS connection.
+              '';
+            };
+
+            cert_path = lib.mkOption {
+              type = lib.types.path;
+              default = "/etc/ssl/certs/ca-certificates.crt";
+              description = ''
+                The path to a TLS certificate bundle used to verify
+                the server's certificate.
+              '';
+            };
+          };
+
+          kafka = {
+            hosts = lib.mkOption {
+              default = [];
+              type = with lib.types; listOf str;
+              apply = x: if x == [] then null else lib.concatStringsSep "," x;
+              description = ''
+                A list of Apache Kafka hosts to publish parsed reports
+                to.
+              '';
+            };
+
+            user = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = null;
+              description = ''
+                Username to use when connecting to Kafka, if
+                required.
+              '';
+            };
+
+            password = lib.mkOption {
+              type = with lib.types; nullOr path;
+              default = null;
+              description = ''
+                The path to a file containing the password to use when
+                connecting to Kafka, if required.
+              '';
+            };
+
+            ssl = lib.mkOption {
+              type = with lib.types; nullOr bool;
+              default = null;
+              description = ''
+                Whether to use an encrypted SSL/TLS connection.
+              '';
+            };
+
+            aggregate_topic = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = null;
+              example = "aggregate";
+              description = ''
+                The Kafka topic to publish aggregate reports on.
+              '';
+            };
+
+            forensic_topic = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = null;
+              example = "forensic";
+              description = ''
+                The Kafka topic to publish forensic reports on.
+              '';
+            };
+          };
+
+        };
+
+      };
+    };
+
+  };
+
+  config = lib.mkIf cfg.enable {
+
+    services.elasticsearch.enable = lib.mkDefault cfg.provision.elasticsearch;
+
+    services.geoipupdate = lib.mkIf cfg.provision.geoIp {
+      enable = true;
+      settings = {
+        EditionIDs = [
+          "GeoLite2-ASN"
+          "GeoLite2-City"
+          "GeoLite2-Country"
+        ];
+        DatabaseDirectory = "/var/lib/GeoIP";
+      };
+    };
+
+    services.dovecot2 = lib.mkIf cfg.provision.localMail.enable {
+      enable = true;
+      protocols = [ "imap" ];
+    };
+
+    services.postfix = lib.mkIf cfg.provision.localMail.enable {
+      enable = true;
+      origin = cfg.provision.localMail.hostname;
+      config = {
+        myhostname = cfg.provision.localMail.hostname;
+        mydestination = cfg.provision.localMail.hostname;
+      };
+    };
+
+    services.grafana = {
+      declarativePlugins = with pkgs.grafanaPlugins;
+        lib.mkIf cfg.provision.grafana.dashboard [
+          grafana-worldmap-panel
+          grafana-piechart-panel
+        ];
+
+      provision = {
+        enable = cfg.provision.grafana.datasource || cfg.provision.grafana.dashboard;
+        datasources =
+          let
+            pkgVer = lib.getVersion config.services.elasticsearch.package;
+            esVersion =
+              if lib.versionOlder pkgVer "7" then
+                "60"
+              else if lib.versionOlder pkgVer "8" then
+                "70"
+              else
+                throw "When provisioning parsedmarc grafana datasources: unknown Elasticsearch version.";
+          in
+            lib.mkIf cfg.provision.grafana.datasource [
+              {
+                name = "dmarc-ag";
+                type = "elasticsearch";
+                access = "proxy";
+                url = "localhost:9200";
+                jsonData = {
+                  timeField = "date_range";
+                  inherit esVersion;
+                };
+              }
+              {
+                name = "dmarc-fo";
+                type = "elasticsearch";
+                access = "proxy";
+                url = "localhost:9200";
+                jsonData = {
+                  timeField = "date_range";
+                  inherit esVersion;
+                };
+              }
+            ];
+        dashboards = lib.mkIf cfg.provision.grafana.dashboard [{
+          name = "parsedmarc";
+          options.path = "${pkgs.python3Packages.parsedmarc.dashboard}";
+        }];
+      };
+    };
+
+    services.parsedmarc.settings = lib.mkMerge [
+      (lib.mkIf cfg.provision.elasticsearch {
+        elasticsearch = {
+          hosts = [ "localhost:9200" ];
+          ssl = false;
+        };
+      })
+      (lib.mkIf cfg.provision.localMail.enable {
+        imap = {
+          host = "localhost";
+          port = 143;
+          ssl = false;
+          user = cfg.provision.localMail.recipientName;
+          password = "${pkgs.writeText "imap-password" "@imap-password@"}";
+          watch = true;
+        };
+      })
+    ];
+
+    systemd.services.parsedmarc =
+      let
+        # Remove any empty attributes from the config, i.e. empty
+        # lists, empty attrsets and null. This makes it possible to
+        # list interesting options in `settings` without them always
+        # ending up in the resulting config.
+        filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! builtins.elem v [ null [] {} ])) cfg.settings;
+        parsedmarcConfig = ini.generate "parsedmarc.ini" filteredConfig;
+        mkSecretReplacement = file:
+          lib.optionalString (file != null) ''
+            replace-secret '${file}' '${file}' /run/parsedmarc/parsedmarc.ini
+          '';
+      in
+        {
+          wantedBy = [ "multi-user.target" ];
+          after = [ "postfix.service" "dovecot2.service" "elasticsearch.service" ];
+          path = with pkgs; [ replace-secret openssl shadow ];
+          serviceConfig = {
+            ExecStartPre = let
+              startPreFullPrivileges = ''
+                set -o errexit -o pipefail -o nounset -o errtrace
+                shopt -s inherit_errexit
+
+                umask u=rwx,g=,o=
+                cp ${parsedmarcConfig} /run/parsedmarc/parsedmarc.ini
+                chown parsedmarc:parsedmarc /run/parsedmarc/parsedmarc.ini
+                ${mkSecretReplacement cfg.settings.smtp.password}
+                ${mkSecretReplacement cfg.settings.imap.password}
+                ${mkSecretReplacement cfg.settings.elasticsearch.password}
+                ${mkSecretReplacement cfg.settings.kafka.password}
+              '' + lib.optionalString cfg.provision.localMail.enable ''
+                openssl rand -hex 64 >/run/parsedmarc/dmarc_user_passwd
+                replace-secret '@imap-password@' '/run/parsedmarc/dmarc_user_passwd' /run/parsedmarc/parsedmarc.ini
+                echo "Setting new randomized password for user '${cfg.provision.localMail.recipientName}'."
+                cat <(echo -n "${cfg.provision.localMail.recipientName}:") /run/parsedmarc/dmarc_user_passwd | chpasswd
+              '';
+            in
+              "+${pkgs.writeShellScript "parsedmarc-start-pre-full-privileges" startPreFullPrivileges}";
+            Type = "simple";
+            User = "parsedmarc";
+            Group = "parsedmarc";
+            DynamicUser = true;
+            RuntimeDirectory = "parsedmarc";
+            RuntimeDirectoryMode = 0700;
+            CapabilityBoundingSet = "";
+            PrivateDevices = true;
+            PrivateMounts = true;
+            PrivateUsers = true;
+            ProtectClock = true;
+            ProtectControlGroups = true;
+            ProtectHome = true;
+            ProtectHostname = true;
+            ProtectKernelLogs = true;
+            ProtectKernelModules = true;
+            ProtectKernelTunables = true;
+            ProtectProc = "invisible";
+            ProcSubset = "pid";
+            SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
+            RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
+            RestrictRealtime = true;
+            RestrictNamespaces = true;
+            MemoryDenyWriteExecute = true;
+            LockPersonality = true;
+            SystemCallArchitectures = "native";
+            ExecStart = "${pkgs.python3Packages.parsedmarc}/bin/parsedmarc -c /run/parsedmarc/parsedmarc.ini";
+          };
+        };
+
+    users.users.${cfg.provision.localMail.recipientName} = lib.mkIf cfg.provision.localMail.enable {
+      isNormalUser = true;
+      description = "DMARC mail recipient";
+    };
+  };
+
+  # Don't edit the docbook xml directly, edit the md and generate it:
+  # `pandoc parsedmarc.md -t docbook --top-level-division=chapter --extract-media=media -f markdown+smart > parsedmarc.xml`
+  meta.doc = ./parsedmarc.xml;
+  meta.maintainers = [ lib.maintainers.talyz ];
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/parsedmarc.xml b/nixpkgs/nixos/modules/services/monitoring/parsedmarc.xml
new file mode 100644
index 000000000000..7167b52d0357
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/parsedmarc.xml
@@ -0,0 +1,125 @@
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="module-services-parsedmarc">
+  <title>parsedmarc</title>
+  <para>
+    <link xlink:href="https://domainaware.github.io/parsedmarc/">parsedmarc</link>
+    is a service which parses incoming
+    <link xlink:href="https://dmarc.org/">DMARC</link> reports and
+    stores or sends them to a downstream service for further analysis.
+    In combination with Elasticsearch, Grafana and the included Grafana
+    dashboard, it provides a handy overview of DMARC reports over time.
+  </para>
+  <section xml:id="module-services-parsedmarc-basic-usage">
+    <title>Basic usage</title>
+    <para>
+      A very minimal setup which reads incoming reports from an external
+      email address and saves them to a local Elasticsearch instance
+      looks like this:
+    </para>
+    <programlisting language="bash">
+services.parsedmarc = {
+  enable = true;
+  settings.imap = {
+    host = &quot;imap.example.com&quot;;
+    user = &quot;alice@example.com&quot;;
+    password = &quot;/path/to/imap_password_file&quot;;
+    watch = true;
+  };
+  provision.geoIp = false; # Not recommended!
+};
+</programlisting>
+    <para>
+      Note that GeoIP provisioning is disabled in the example for
+      simplicity, but should be turned on for fully functional reports.
+    </para>
+  </section>
+  <section xml:id="local-mail">
+    <title>Local mail</title>
+    <para>
+      Instead of watching an external inbox, a local inbox can be
+      automatically provisioned. The recipient’s name is by default set
+      to <literal>dmarc</literal>, but can be configured in
+      <link xlink:href="options.html#opt-services.parsedmarc.provision.localMail.recipientName">services.parsedmarc.provision.localMail.recipientName</link>.
+      You need to add an MX record pointing to the host. More
+      concretely: for the example to work, an MX record needs to be set
+      up for <literal>monitoring.example.com</literal> and the complete
+      email address that should be configured in the domain’s dmarc
+      policy is <literal>dmarc@monitoring.example.com</literal>.
+    </para>
+    <programlisting language="bash">
+services.parsedmarc = {
+  enable = true;
+  provision = {
+    localMail = {
+      enable = true;
+      hostname = monitoring.example.com;
+    };
+    geoIp = false; # Not recommended!
+  };
+};
+</programlisting>
+  </section>
+  <section xml:id="grafana-and-geoip">
+    <title>Grafana and GeoIP</title>
+    <para>
+      The reports can be visualized and summarized with parsedmarc’s
+      official Grafana dashboard. For all views to work, and for the
+      data to be complete, GeoIP databases are also required. The
+      following example shows a basic deployment where the provisioned
+      Elasticsearch instance is automatically added as a Grafana
+      datasource, and the dashboard is added to Grafana as well.
+    </para>
+    <programlisting language="bash">
+services.parsedmarc = {
+  enable = true;
+  provision = {
+    localMail = {
+      enable = true;
+      hostname = url;
+    };
+    grafana = {
+      datasource = true;
+      dashboard = true;
+    };
+  };
+};
+
+# Not required, but recommended for full functionality
+services.geoipupdate = {
+  settings = {
+    AccountID = 000000;
+    LicenseKey = &quot;/path/to/license_key_file&quot;;
+  };
+};
+
+services.grafana = {
+  enable = true;
+  addr = &quot;0.0.0.0&quot;;
+  domain = url;
+  rootUrl = &quot;https://&quot; + url;
+  protocol = &quot;socket&quot;;
+  security = {
+    adminUser = &quot;admin&quot;;
+    adminPasswordFile = &quot;/path/to/admin_password_file&quot;;
+    secretKeyFile = &quot;/path/to/secret_key_file&quot;;
+  };
+};
+
+services.nginx = {
+  enable = true;
+  recommendedTlsSettings = true;
+  recommendedOptimisation = true;
+  recommendedGzipSettings = true;
+  recommendedProxySettings = true;
+  upstreams.grafana.servers.&quot;unix:/${config.services.grafana.socket}&quot; = {};
+  virtualHosts.${url} = {
+    root = config.services.grafana.staticRootPath;
+    enableACME = true;
+    forceSSL = true;
+    locations.&quot;/&quot;.tryFiles = &quot;$uri @grafana&quot;;
+    locations.&quot;@grafana&quot;.proxyPass = &quot;http://grafana&quot;;
+  };
+};
+users.users.nginx.extraGroups = [ &quot;grafana&quot; ];
+</programlisting>
+  </section>
+</chapter>
diff --git a/nixpkgs/nixos/modules/services/monitoring/tuptime.nix b/nixpkgs/nixos/modules/services/monitoring/tuptime.nix
index 17c5c1f56eaf..de80282559ae 100644
--- a/nixpkgs/nixos/modules/services/monitoring/tuptime.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/tuptime.nix
@@ -36,6 +36,7 @@ in {
       groups._tuptime.members = [ "_tuptime" ];
       users._tuptime = {
         isSystemUser = true;
+        group = "_tuptime";
         description = "tuptime database owner";
       };
     };
diff --git a/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix b/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix
index 2c8b8b92cb38..8c7a2970e9b3 100644
--- a/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix
@@ -262,7 +262,12 @@ in
     };
 
     security.wrappers = {
-      fping.source = "${pkgs.fping}/bin/fping";
+      fping =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.fping}/bin/fping";
+        };
     };
 
     systemd.services.zabbix-proxy = {
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/orangefs/server.nix b/nixpkgs/nixos/modules/services/network-filesystems/orangefs/server.nix
index 8eb754fe6110..8c55ccf5ffb0 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/orangefs/server.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/orangefs/server.nix
@@ -193,7 +193,10 @@ in {
     environment.systemPackages = [ pkgs.orangefs ];
 
     # orangefs daemon will run as user
-    users.users.orangefs.isSystemUser = true;
+    users.users.orangefs = {
+      isSystemUser = true;
+      group = "orangfs";
+    };
     users.groups.orangefs = {};
 
     # To format the file system the config file is needed.
diff --git a/nixpkgs/nixos/modules/services/networking/bind.nix b/nixpkgs/nixos/modules/services/networking/bind.nix
index 480d5a184f25..0c23fb7e40f0 100644
--- a/nixpkgs/nixos/modules/services/networking/bind.nix
+++ b/nixpkgs/nixos/modules/services/networking/bind.nix
@@ -229,9 +229,11 @@ in
 
     users.users.${bindUser} =
       {
-        uid = config.ids.uids.bind;
+        group = bindUser;
         description = "BIND daemon user";
+        isSystemUser = true;
       };
+    users.groups.${bindUser} = {};
 
     systemd.services.bind = {
       description = "BIND Domain Name Server";
diff --git a/nixpkgs/nixos/modules/services/networking/consul.nix b/nixpkgs/nixos/modules/services/networking/consul.nix
index ae7998913ee0..476ca738dd1b 100644
--- a/nixpkgs/nixos/modules/services/networking/consul.nix
+++ b/nixpkgs/nixos/modules/services/networking/consul.nix
@@ -159,10 +159,12 @@ in
 
       users.users.consul = {
         description = "Consul agent daemon user";
-        uid = config.ids.uids.consul;
+        isSystemUser = true;
+        group = "consul";
         # The shell is needed for health checks
         shell = "/run/current-system/sw/bin/bash";
       };
+      users.groups.consul = {};
 
       environment = {
         etc."consul.json".text = builtins.toJSON configOptions;
diff --git a/nixpkgs/nixos/modules/services/networking/coturn.nix b/nixpkgs/nixos/modules/services/networking/coturn.nix
index 5f7d2893ae27..12098ec6d338 100644
--- a/nixpkgs/nixos/modules/services/networking/coturn.nix
+++ b/nixpkgs/nixos/modules/services/networking/coturn.nix
@@ -311,6 +311,7 @@ in {
     {
       users.users.turnserver =
         { uid = config.ids.uids.turnserver;
+          group = "turnserver";
           description = "coturn TURN server user";
         };
       users.groups.turnserver =
diff --git a/nixpkgs/nixos/modules/services/networking/dhcpd.nix b/nixpkgs/nixos/modules/services/networking/dhcpd.nix
index 8966deac76cb..54e4f9002859 100644
--- a/nixpkgs/nixos/modules/services/networking/dhcpd.nix
+++ b/nixpkgs/nixos/modules/services/networking/dhcpd.nix
@@ -212,9 +212,11 @@ in
 
     users = {
       users.dhcpd = {
-        uid = config.ids.uids.dhcpd;
+        isSystemUser = true;
+        group = "dhcpd";
         description = "DHCP daemon user";
       };
+      groups.dhcpd = {};
     };
 
     systemd.services = dhcpdService "4" cfg4 // dhcpdService "6" cfg6;
diff --git a/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix b/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix
index 89360f4bf373..400d6e67044e 100644
--- a/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix
+++ b/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix
@@ -217,6 +217,7 @@ in {
       home = "${dataDir}";
       createHome = true;
       isSystemUser = true;
+      group = "dnscrypt-wrapper";
     };
     users.groups.dnscrypt-wrapper = { };
 
diff --git a/nixpkgs/nixos/modules/services/networking/dnsmasq.nix b/nixpkgs/nixos/modules/services/networking/dnsmasq.nix
index 377d7bc57058..59a3ca2f28e3 100644
--- a/nixpkgs/nixos/modules/services/networking/dnsmasq.nix
+++ b/nixpkgs/nixos/modules/services/networking/dnsmasq.nix
@@ -87,9 +87,11 @@ in
     services.dbus.packages = [ dnsmasq ];
 
     users.users.dnsmasq = {
-      uid = config.ids.uids.dnsmasq;
+      isSystemUser = true;
+      group = "dnsmasq";
       description = "Dnsmasq daemon user";
     };
+    users.groups.dnsmasq = {};
 
     networking.resolvconf = mkIf cfg.resolveLocalQueries {
       useLocalResolver = mkDefault true;
diff --git a/nixpkgs/nixos/modules/services/networking/flannel.nix b/nixpkgs/nixos/modules/services/networking/flannel.nix
index 32a7eb3ed69e..2d67a2a2ad22 100644
--- a/nixpkgs/nixos/modules/services/networking/flannel.nix
+++ b/nixpkgs/nixos/modules/services/networking/flannel.nix
@@ -164,7 +164,7 @@ in {
       path = [ pkgs.iptables ];
       preStart = optionalString (cfg.storageBackend == "etcd") ''
         echo "setting network configuration"
-        until ${pkgs.etcdctl}/bin/etcdctl set /coreos.com/network/config '${builtins.toJSON networkConfig}'
+        until ${pkgs.etcd}/bin/etcdctl set /coreos.com/network/config '${builtins.toJSON networkConfig}'
         do
           echo "setting network configuration, retry"
           sleep 1
diff --git a/nixpkgs/nixos/modules/services/networking/git-daemon.nix b/nixpkgs/nixos/modules/services/networking/git-daemon.nix
index 98f80dd4bc40..6be72505c216 100644
--- a/nixpkgs/nixos/modules/services/networking/git-daemon.nix
+++ b/nixpkgs/nixos/modules/services/networking/git-daemon.nix
@@ -107,6 +107,7 @@ in
     users.users = optionalAttrs (cfg.user == "git") {
       git = {
         uid = config.ids.uids.git;
+        group = "git";
         description = "Git daemon user";
       };
     };
diff --git a/nixpkgs/nixos/modules/services/networking/iodine.nix b/nixpkgs/nixos/modules/services/networking/iodine.nix
index 46051d7044b5..f67e2d9a5e71 100644
--- a/nixpkgs/nixos/modules/services/networking/iodine.nix
+++ b/nixpkgs/nixos/modules/services/networking/iodine.nix
@@ -190,6 +190,7 @@ in
 
     users.users.${iodinedUser} = {
       uid = config.ids.uids.iodined;
+      group = "iodined";
       description = "Iodine daemon user";
     };
     users.groups.iodined.gid = config.ids.gids.iodined;
diff --git a/nixpkgs/nixos/modules/services/networking/morty.nix b/nixpkgs/nixos/modules/services/networking/morty.nix
index e110a5c86101..c627feb527b6 100644
--- a/nixpkgs/nixos/modules/services/networking/morty.nix
+++ b/nixpkgs/nixos/modules/services/networking/morty.nix
@@ -77,7 +77,9 @@ in
         createHome = true;
         home = "/var/lib/morty";
         isSystemUser = true;
+        group = "morty";
       };
+    users.groups.morty = {};
 
     systemd.services.morty =
       {
diff --git a/nixpkgs/nixos/modules/services/networking/ncdns.nix b/nixpkgs/nixos/modules/services/networking/ncdns.nix
index d30fe0f6f6d1..c5ea5d950573 100644
--- a/nixpkgs/nixos/modules/services/networking/ncdns.nix
+++ b/nixpkgs/nixos/modules/services/networking/ncdns.nix
@@ -245,8 +245,10 @@ in
 
     users.users.ncdns = {
       isSystemUser = true;
+      group = "ncdns";
       description = "ncdns daemon user";
     };
+    users.groups.ncdns = {};
 
     systemd.services.ncdns = {
       description = "ncdns daemon";
diff --git a/nixpkgs/nixos/modules/services/networking/networkmanager.nix b/nixpkgs/nixos/modules/services/networking/networkmanager.nix
index c8861171dd6c..ba13f575c39e 100644
--- a/nixpkgs/nixos/modules/services/networking/networkmanager.nix
+++ b/nixpkgs/nixos/modules/services/networking/networkmanager.nix
@@ -464,6 +464,7 @@ in {
     users.users = {
       nm-openvpn = {
         uid = config.ids.uids.nm-openvpn;
+        group = "nm-openvpn";
         extraGroups = [ "networkmanager" ];
       };
       nm-iodine = {
diff --git a/nixpkgs/nixos/modules/services/networking/ngircd.nix b/nixpkgs/nixos/modules/services/networking/ngircd.nix
index 4b2fa7795922..1b631de3b025 100644
--- a/nixpkgs/nixos/modules/services/networking/ngircd.nix
+++ b/nixpkgs/nixos/modules/services/networking/ngircd.nix
@@ -52,8 +52,11 @@ in {
     };
 
     users.users.ngircd = {
-      uid = config.ids.uids.ngircd;
+      isSystemUser = true;
+      group = "ngircd";
       description = "ngircd user.";
     };
+    users.groups.ngircd = {};
+
   };
 }
diff --git a/nixpkgs/nixos/modules/services/networking/nntp-proxy.nix b/nixpkgs/nixos/modules/services/networking/nntp-proxy.nix
index cc061bf6e3b9..0083990cff5a 100644
--- a/nixpkgs/nixos/modules/services/networking/nntp-proxy.nix
+++ b/nixpkgs/nixos/modules/services/networking/nntp-proxy.nix
@@ -6,8 +6,6 @@ let
 
   inherit (pkgs) nntp-proxy;
 
-  proxyUser = "nntp-proxy";
-
   cfg = config.services.nntp-proxy;
 
   configBool = b: if b then "TRUE" else "FALSE";
@@ -210,16 +208,18 @@ in
 
   config = mkIf cfg.enable {
 
-    users.users.${proxyUser} =
-      { uid = config.ids.uids.nntp-proxy;
-        description = "NNTP-Proxy daemon user";
-      };
+    users.users.nntp-proxy = {
+      isSystemUser = true;
+      group = "nntp-proxy";
+      description = "NNTP-Proxy daemon user";
+    };
+    users.groups.nntp-proxy = {};
 
     systemd.services.nntp-proxy = {
       description = "NNTP proxy";
       after = [ "network.target" "nss-lookup.target" ];
       wantedBy = [ "multi-user.target" ];
-      serviceConfig = { User="${proxyUser}"; };
+      serviceConfig = { User="nntp-proxy"; };
       serviceConfig.ExecStart = "${nntp-proxy}/bin/nntp-proxy ${confFile}";
       preStart = ''
         if [ ! \( -f ${cfg.sslCert} -a -f ${cfg.sslKey} \) ]; then
diff --git a/nixpkgs/nixos/modules/services/networking/ntp/ntpd.nix b/nixpkgs/nixos/modules/services/networking/ntp/ntpd.nix
index 861b0db01a48..1dffbd78bbe4 100644
--- a/nixpkgs/nixos/modules/services/networking/ntp/ntpd.nix
+++ b/nixpkgs/nixos/modules/services/networking/ntp/ntpd.nix
@@ -10,8 +10,6 @@ let
 
   stateDir = "/var/lib/ntp";
 
-  ntpUser = "ntp";
-
   configFile = pkgs.writeText "ntp.conf" ''
     driftfile ${stateDir}/ntp.drift
 
@@ -27,7 +25,7 @@ let
     ${cfg.extraConfig}
   '';
 
-  ntpFlags = "-c ${configFile} -u ${ntpUser}:nogroup ${toString cfg.extraFlags}";
+  ntpFlags = "-c ${configFile} -u ntp:ntp ${toString cfg.extraFlags}";
 
 in
 
@@ -119,11 +117,13 @@ in
 
     systemd.services.systemd-timedated.environment = { SYSTEMD_TIMEDATED_NTP_SERVICES = "ntpd.service"; };
 
-    users.users.${ntpUser} =
-      { uid = config.ids.uids.ntp;
+    users.users.ntp =
+      { isSystemUser = true;
+        group = "ntp";
         description = "NTP daemon user";
         home = stateDir;
       };
+    users.groups.ntp = {};
 
     systemd.services.ntpd =
       { description = "NTP Daemon";
@@ -135,7 +135,7 @@ in
         preStart =
           ''
             mkdir -m 0755 -p ${stateDir}
-            chown ${ntpUser} ${stateDir}
+            chown ntp ${stateDir}
           '';
 
         serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/networking/ntp/openntpd.nix b/nixpkgs/nixos/modules/services/networking/ntp/openntpd.nix
index 67a04d48d308..9f3892e3b538 100644
--- a/nixpkgs/nixos/modules/services/networking/ntp/openntpd.nix
+++ b/nixpkgs/nixos/modules/services/networking/ntp/openntpd.nix
@@ -61,10 +61,12 @@ in
     environment.etc."ntpd.conf".text = configFile;
 
     users.users.ntp = {
-      uid = config.ids.uids.ntp;
+      isSystemUser = true;
+      group = "ntp";
       description = "OpenNTP daemon user";
       home = "/var/empty";
     };
+    users.groups.ntp = {};
 
     systemd.services.openntpd = {
       description = "OpenNTP Server";
diff --git a/nixpkgs/nixos/modules/services/networking/pleroma.nix b/nixpkgs/nixos/modules/services/networking/pleroma.nix
index bd75083a4a78..93ab29b71e5c 100644
--- a/nixpkgs/nixos/modules/services/networking/pleroma.nix
+++ b/nixpkgs/nixos/modules/services/networking/pleroma.nix
@@ -74,7 +74,7 @@ in {
       users."${cfg.user}" = {
         description = "Pleroma user";
         home = cfg.stateDir;
-        extraGroups = [ cfg.group ];
+        group = cfg.group;
         isSystemUser = true;
       };
       groups."${cfg.group}" = {};
diff --git a/nixpkgs/nixos/modules/services/networking/pleroma.xml b/nixpkgs/nixos/modules/services/networking/pleroma.xml
index 9ab0be3d947c..ad0a481af28b 100644
--- a/nixpkgs/nixos/modules/services/networking/pleroma.xml
+++ b/nixpkgs/nixos/modules/services/networking/pleroma.xml
@@ -4,129 +4,185 @@
          version="5.0"
          xml:id="module-services-pleroma">
  <title>Pleroma</title>
- <para><link xlink:href="https://pleroma.social/">Pleroma</link> is a lightweight activity pub server.</para>
- <section xml:id="module-services-pleroma-getting-started">
-   <title>Quick Start</title>
-   <para>To get quickly started, you can use this sample NixOS configuration and adapt it to your use case.</para>
-   <para><programlisting>
-    {
-      security.acme = {
-        email = "root@tld";
-        acceptTerms = true;
-        certs = {
-          "social.tld.com" = {
-            webroot = "/var/www/social.tld.com";
-            email = "root@tld";
-            group = "nginx";
-          };
-        };
-      };
-      services = {
-        pleroma = {
-          enable = true;
-          secretConfigFile = "/var/lib/pleroma/secrets.exs";
-          configs = [
-          ''
-            import Config
-
-            config :pleroma, Pleroma.Web.Endpoint,
-            url: [host: "social.tld.com", scheme: "https", port: 443],
-            http: [ip: {127, 0, 0, 1}, port: 4000]
-
-            config :pleroma, :instance,
-            name: "NixOS test pleroma server",
-            email: "pleroma@social.tld.com",
-            notify_email: "pleroma@social.tld.com",
-            limit: 5000,
-            registrations_open: true
-
-            config :pleroma, :media_proxy,
-            enabled: false,
-            redirect_on_failure: true
-            #base_url: "https://cache.pleroma.social"
-
-            config :pleroma, Pleroma.Repo,
-            adapter: Ecto.Adapters.Postgres,
-            username: "pleroma",
-            password: "${test-db-passwd}",
-            database: "pleroma",
-            hostname: "localhost",
-            pool_size: 10,
-            prepare: :named,
-            parameters: [
-                plan_cache_mode: "force_custom_plan"
-            ]
-
-            config :pleroma, :database, rum_enabled: false
-            config :pleroma, :instance, static_dir: "/var/lib/pleroma/static"
-            config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads"
-            config :pleroma, configurable_from_database: false
-          ''
-          ];
-        };
-        postgresql = {
-          enable = true;
-          package = pkgs.postgresql_12;
-        };
-        nginx = {
-          enable = true;
-          addSSL = true;
-          sslCertificate = "/var/lib/acme/social.tld.com/fullchain.pem";
-          sslCertificateKey = "/var/lib/acme/social.tld.com/key.pem";
-          root = "/var/www/social.tld.com";
-          # ACME endpoint
-          locations."/.well-known/acme-challenge" = {
-              root = "/var/www/social.tld.com/";
-          };
-          virtualHosts."social.tld.com" = {
-            addSSL = true;
-            locations."/" = {
-              proxyPass = "http://127.0.0.1:4000";
-              extraConfig = ''
-                add_header 'Access-Control-Allow-Origin' '*' always;
-                add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always;
-                add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always;
-                add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always;
-                if ($request_method = OPTIONS) {
-                    return 204;
-                }
-                add_header X-XSS-Protection "1; mode=block";
-                add_header X-Permitted-Cross-Domain-Policies none;
-                add_header X-Frame-Options DENY;
-                add_header X-Content-Type-Options nosniff;
-                add_header Referrer-Policy same-origin;
-                add_header X-Download-Options noopen;
-                proxy_http_version 1.1;
-                proxy_set_header Upgrade $http_upgrade;
-                proxy_set_header Connection "upgrade";
-                proxy_set_header Host $host;
-                client_max_body_size 16m;
-              '';
-            };
-          };
-        };
-      };
-    };
-   </programlisting></para>
-   <para>Note that you'll need to seed your database and upload your pleroma secrets to the path pointed by <literal>config.pleroma.secretConfigFile</literal>. You can find more informations about how to do that in the <link linkend="module-services-pleroma-generate-config">next</link> section.</para>
- </section>
+ <para>
+  <link xlink:href="https://pleroma.social/">Pleroma</link> is a lightweight activity pub server.</para>
  <section xml:id="module-services-pleroma-generate-config">
-   <title>Generating the Pleroma Config and Seed the Database</title>
-
-   <para>Before using this service, you'll need to generate your
-server configuration and its associated database seed. The
-<literal>pleroma_ctl</literal> CLI utility can help you with that. You
-can start with <literal>pleroma_ctl instance gen --output config.exs
---output-psql setup.psql</literal>, this will prompt you some
-questions and will generate both your config file and database initial
-migration. </para>
-<para>For more details about this configuration format, please have a look at the <link xlink:href="https://docs-develop.pleroma.social/backend/configuration/cheatsheet/">upstream documentation</link>.</para>
-<para>To seed your database, you can use the <literal>setup.psql</literal> file you just generated by running
+  <title>Generating the Pleroma config</title>
+  <para>The <literal>pleroma_ctl</literal> CLI utility will prompt you some questions and it will generate an initial config file. This is an example of usage
+<programlisting>
+<prompt>$ </prompt>mkdir tmp-pleroma
+<prompt>$ </prompt>cd tmp-pleroma
+<prompt>$ </prompt>nix-shell -p pleroma-otp
+<prompt>$ </prompt>pleroma_ctl instance gen --output config.exs --output-psql setup.psql
+</programlisting>
+  </para>
+  <para>The <literal>config.exs</literal> file can be further customized following the instructions on the <link xlink:href="https://docs-develop.pleroma.social/backend/configuration/cheatsheet/">upstream documentation</link>. Many refinements can be applied also after the service is running.</para>
+ </section>
+ <section xml:id="module-services-pleroma-initialize-db">
+  <title>Initializing the database</title>
+  <para>First, the Postgresql service must be enabled in the NixOS configuration
+<programlisting>
+services.postgresql = {
+  enable = true;
+  package = pkgs.postgresql_13;
+};
+</programlisting>
+and activated with the usual
+<programlisting>
+<prompt>$ </prompt>nixos-rebuild switch
+</programlisting>
+  </para>
+  <para>Then you can create and seed the database, using the <literal>setup.psql</literal> file that you generated in the previous section, by running
+<programlisting>
+<prompt>$ </prompt>sudo -u postgres psql -f setup.psql
+</programlisting>
+  </para>
+ </section>
+ <section xml:id="module-services-pleroma-enable">
+  <title>Enabling the Pleroma service locally</title>
+  <para>In this section we will enable the Pleroma service only locally, so its configurations can be improved incrementally.</para>
+  <para>This is an example of configuration, where <link linkend="opt-services.pleroma.configs">services.pleroma.configs</link> option contains the content of the file <literal>config.exs</literal>, generated <link linkend="module-services-pleroma-generate-config">in the first section</link>, but with the secrets (database password, endpoint secret key, salts, etc.) removed. Removing secrets is important, because otherwise they will be stored publicly in the Nix store.
+<programlisting>
+services.pleroma = {
+  enable = true;
+  secretConfigFile = "/var/lib/pleroma/secrets.exs";
+  configs = [
+    ''
+    import Config
+
+    config :pleroma, Pleroma.Web.Endpoint,
+      url: [host: "pleroma.example.net", scheme: "https", port: 443],
+      http: [ip: {127, 0, 0, 1}, port: 4000]
+
+    config :pleroma, :instance,
+      name: "Test",
+      email: "admin@example.net",
+      notify_email: "admin@example.net",
+      limit: 5000,
+      registrations_open: true
+
+    config :pleroma, :media_proxy,
+      enabled: false,
+      redirect_on_failure: true
+
+    config :pleroma, Pleroma.Repo,
+      adapter: Ecto.Adapters.Postgres,
+      username: "pleroma",
+      database: "pleroma",
+      hostname: "localhost"
+
+    # Configure web push notifications
+    config :web_push_encryption, :vapid_details,
+      subject: "mailto:admin@example.net"
+
+    # ... TO CONTINUE ...
+    ''
+  ];
+};
+</programlisting>
+  </para>
+  <para>Secrets must be moved into a file pointed by <link linkend="opt-services.pleroma.secretConfigFile">services.pleroma.secretConfigFile</link>, in our case <literal>/var/lib/pleroma/secrets.exs</literal>. This file can be created copying the previously generated <literal>config.exs</literal> file and then removing all the settings, except the secrets. This is an example
+<programlisting>
+# Pleroma instance passwords
+
+import Config
+
+config :pleroma, Pleroma.Web.Endpoint,
+   secret_key_base: "&lt;the secret generated by pleroma_ctl&gt;",
+   signing_salt: "&lt;the secret generated by pleroma_ctl&gt;"
+
+config :pleroma, Pleroma.Repo,
+  password: "&lt;the secret generated by pleroma_ctl&gt;"
+
+# Configure web push notifications
+config :web_push_encryption, :vapid_details,
+  public_key: "&lt;the secret generated by pleroma_ctl&gt;",
+  private_key: "&lt;the secret generated by pleroma_ctl&gt;"
+
+# ... TO CONTINUE ...
+</programlisting>
+  Note that the lines of the same configuration group are comma separated (i.e. all the lines end with a comma, except the last one), so when the lines with passwords are added or removed, commas must be adjusted accordingly.</para>
+
+  <para>The service can be enabled with the usual
+<programlisting>
+<prompt>$ </prompt>nixos-rebuild switch
+</programlisting>
+  </para>
+  <para>The service is accessible only from the local <literal>127.0.0.1:4000</literal> port. It can be tested using a port forwarding like this
+<programlisting>
+<prompt>$ </prompt>ssh -L 4000:localhost:4000 myuser@example.net
+</programlisting>
+and then accessing <link xlink:href="http://localhost:4000">http://localhost:4000</link> from a web browser.</para>
+ </section>
+ <section xml:id="module-services-pleroma-admin-user">
+  <title>Creating the admin user</title>
+  <para>After Pleroma service is running, all <link xlink:href="https://docs-develop.pleroma.social/">Pleroma administration utilities</link> can be used. In particular an admin user can be created with
+<programlisting>
+<prompt>$ </prompt>pleroma_ctl user new &lt;nickname&gt; &lt;email&gt;  --admin --moderator --password &lt;password&gt;
+</programlisting>
+  </para>
+ </section>
+ <section xml:id="module-services-pleroma-nginx">
+  <title>Configuring Nginx</title>
+  <para>In this configuration, Pleroma is listening only on the local port 4000. Nginx can be configured as a Reverse Proxy, for forwarding requests from public ports to the Pleroma service. This is an example of configuration, using
+<link xlink:href="https://letsencrypt.org/">Let's Encrypt</link> for the TLS certificates
 <programlisting>
-    sudo -u postgres psql -f setup.psql
-</programlisting></para>
-   <para>In regard of the pleroma service configuration you also just generated, you'll need to split it in two parts. The "public" part, which do not contain any secrets and thus can be safely stored in the Nix store and its "private" counterpart containing some secrets (database password, endpoint secret key, salts, etc.).</para>
+security.acme = {
+  email = "root@example.net";
+  acceptTerms = true;
+};
 
-   <para>The public part will live in your NixOS machine configuration in the <link linkend="opt-services.pleroma.configs">services.pleroma.configs</link> option. However, it's up to you to upload the secret pleroma configuration to the path pointed by <link linkend="opt-services.pleroma.secretConfigFile">services.pleroma.secretConfigFile</link>. You can do that manually or rely on a third party tool such as <link xlink:href="https://github.com/DBCDK/morph">Morph</link> or <link xlink:href="https://github.com/NixOS/nixops">NixOps</link>.</para>
+services.nginx = {
+  enable = true;
+  addSSL = true;
+
+  recommendedTlsSettings = true;
+  recommendedOptimisation = true;
+  recommendedGzipSettings = true;
+
+  recommendedProxySettings = false;
+  # NOTE: if enabled, the NixOS proxy optimizations will override the Pleroma
+  # specific settings, and they will enter in conflict.
+
+  virtualHosts = {
+    "pleroma.example.net" = {
+      http2 = true;
+      enableACME = true;
+      forceSSL = true;
+
+      locations."/" = {
+        proxyPass = "http://127.0.0.1:4000";
+
+        extraConfig = ''
+          etag on;
+          gzip on;
+
+          add_header 'Access-Control-Allow-Origin' '*' always;
+          add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always;
+          add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always;
+          add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always;
+          if ($request_method = OPTIONS) {
+            return 204;
+          }
+          add_header X-XSS-Protection "1; mode=block";
+          add_header X-Permitted-Cross-Domain-Policies none;
+          add_header X-Frame-Options DENY;
+          add_header X-Content-Type-Options nosniff;
+          add_header Referrer-Policy same-origin;
+          add_header X-Download-Options noopen;
+          proxy_http_version 1.1;
+          proxy_set_header Upgrade $http_upgrade;
+          proxy_set_header Connection "upgrade";
+          proxy_set_header Host $host;
+
+          client_max_body_size 16m;
+          # NOTE: increase if users need to upload very big files
+        '';
+      };
+    };
+  };
+};
+</programlisting>
+  </para>
  </section>
 </chapter>
diff --git a/nixpkgs/nixos/modules/services/networking/radicale.nix b/nixpkgs/nixos/modules/services/networking/radicale.nix
index 8c632c319d3c..368259b5b0bf 100644
--- a/nixpkgs/nixos/modules/services/networking/radicale.nix
+++ b/nixpkgs/nixos/modules/services/networking/radicale.nix
@@ -140,9 +140,12 @@ in {
 
     environment.systemPackages = [ pkg ];
 
-    users.users.radicale.uid = config.ids.uids.radicale;
+    users.users.radicale = {
+      isSystemUser = true;
+      group = "radicale";
+    };
 
-    users.groups.radicale.gid = config.ids.gids.radicale;
+    users.groups.radicale = {};
 
     systemd.services.radicale = {
       description = "A Simple Calendar and Contact Server";
diff --git a/nixpkgs/nixos/modules/services/networking/radvd.nix b/nixpkgs/nixos/modules/services/networking/radvd.nix
index 53fac4b7b72d..6e8db55bbf0d 100644
--- a/nixpkgs/nixos/modules/services/networking/radvd.nix
+++ b/nixpkgs/nixos/modules/services/networking/radvd.nix
@@ -55,9 +55,12 @@ in
   config = mkIf cfg.enable {
 
     users.users.radvd =
-      { uid = config.ids.uids.radvd;
+      {
+        isSystemUser = true;
+        group = "radvd";
         description = "Router Advertisement Daemon User";
       };
+    users.groups.radvd = {};
 
     systemd.services.radvd =
       { description = "IPv6 Router Advertisement Daemon";
diff --git a/nixpkgs/nixos/modules/services/networking/rdnssd.nix b/nixpkgs/nixos/modules/services/networking/rdnssd.nix
index 469504c43172..fd04bb8108f0 100644
--- a/nixpkgs/nixos/modules/services/networking/rdnssd.nix
+++ b/nixpkgs/nixos/modules/services/networking/rdnssd.nix
@@ -72,8 +72,10 @@ in
 
     users.users.rdnssd = {
       description = "RDNSSD Daemon User";
-      uid = config.ids.uids.rdnssd;
+      isSystemUser = true;
+      group = "rdnssd";
     };
+    users.groups.rdnssd = {};
 
   };
 
diff --git a/nixpkgs/nixos/modules/services/networking/shout.nix b/nixpkgs/nixos/modules/services/networking/shout.nix
index 405808491ea4..cca03a8f88a1 100644
--- a/nixpkgs/nixos/modules/services/networking/shout.nix
+++ b/nixpkgs/nixos/modules/services/networking/shout.nix
@@ -83,11 +83,13 @@ in {
 
   config = mkIf cfg.enable {
     users.users.shout = {
-      uid = config.ids.uids.shout;
+      isSystemUser = true;
+      group = "shout";
       description = "Shout daemon user";
       home = shoutHome;
       createHome = true;
     };
+    users.groups.shout = {};
 
     systemd.services.shout = {
       description = "Shout web IRC client";
diff --git a/nixpkgs/nixos/modules/services/networking/smokeping.nix b/nixpkgs/nixos/modules/services/networking/smokeping.nix
index 4470c18fd533..0f123fd18776 100644
--- a/nixpkgs/nixos/modules/services/networking/smokeping.nix
+++ b/nixpkgs/nixos/modules/services/networking/smokeping.nix
@@ -259,7 +259,7 @@ in
       user = mkOption {
         type = types.str;
         default = "smokeping";
-        description = "User that runs smokeping and (optionally) thttpd";
+        description = "User that runs smokeping and (optionally) thttpd. A group of the same name will be created as well.";
       };
       webService = mkOption {
         type = types.bool;
@@ -278,18 +278,23 @@ in
       }
     ];
     security.wrappers = {
-      fping.source = "${pkgs.fping}/bin/fping";
-      fping6.source = "${pkgs.fping}/bin/fping6";
+      fping =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.fping}/bin/fping";
+        };
     };
     environment.systemPackages = [ pkgs.fping ];
     users.users.${cfg.user} = {
       isNormalUser = false;
       isSystemUser = true;
-      uid = config.ids.uids.smokeping;
+      group = cfg.user;
       description = "smokeping daemon user";
       home = smokepingHome;
       createHome = true;
     };
+    users.groups.${cfg.user} = {};
     systemd.services.smokeping = {
       wantedBy = [ "multi-user.target"];
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix b/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
index 04879eb7d82d..311fd5abccad 100644
--- a/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
@@ -410,11 +410,13 @@ in
     users.users = {
       sshd = {
         isSystemUser = true;
+        group = "sshd";
         description = "SSH privilege separation user";
       };
     } // (optionalAttrs (cfg.authorizedKeysCommand != null) {
       ${cfg.authorizedKeysCommandUser} = {};
     });
+    users.groups.sshd = {};
 
     services.openssh.moduliFile = mkDefault "${cfgc.package}/etc/ssh/moduli";
     services.openssh.sftpServerExecutable = mkDefault "${cfgc.package}/libexec/sftp-server";
diff --git a/nixpkgs/nixos/modules/services/networking/tinydns.nix b/nixpkgs/nixos/modules/services/networking/tinydns.nix
index 79507b2ebcdd..2c44ad49296d 100644
--- a/nixpkgs/nixos/modules/services/networking/tinydns.nix
+++ b/nixpkgs/nixos/modules/services/networking/tinydns.nix
@@ -32,7 +32,11 @@ with lib;
   config = mkIf config.services.tinydns.enable {
     environment.systemPackages = [ pkgs.djbdns ];
 
-    users.users.tinydns.isSystemUser = true;
+    users.users.tinydns = {
+      isSystemUser = true;
+      group = "tinydns";
+    };
+    users.groups.tinydns = {};
 
     systemd.services.tinydns = {
       description = "djbdns tinydns server";
diff --git a/nixpkgs/nixos/modules/services/networking/tox-bootstrapd.nix b/nixpkgs/nixos/modules/services/networking/tox-bootstrapd.nix
index f88e34827d00..7c13724e084a 100644
--- a/nixpkgs/nixos/modules/services/networking/tox-bootstrapd.nix
+++ b/nixpkgs/nixos/modules/services/networking/tox-bootstrapd.nix
@@ -3,15 +3,15 @@
 with lib;
 
 let
-  home = "/var/lib/tox-bootstrapd";
-  PIDFile = "${home}/pid";
+  WorkingDirectory = "/var/lib/tox-bootstrapd";
+  PIDFile = "${WorkingDirectory}/pid";
 
   pkg = pkgs.libtoxcore;
   cfg = config.services.toxBootstrapd;
   cfgFile = builtins.toFile "tox-bootstrapd.conf"
     ''
       port = ${toString cfg.port}
-      keys_file_path = "${home}/keys"
+      keys_file_path = "${WorkingDirectory}/keys"
       pid_file_path = "${PIDFile}"
       ${cfg.extraConfig}
     '';
@@ -36,7 +36,7 @@ in
 
           keysFile = mkOption {
             type = types.str;
-            default = "${home}/keys";
+            default = "${WorkingDirectory}/keys";
             description = "Node key file.";
           };
 
@@ -56,13 +56,6 @@ in
 
   config = mkIf config.services.toxBootstrapd.enable {
 
-    users.users.tox-bootstrapd =
-      { uid = config.ids.uids.tox-bootstrapd;
-        description = "Tox bootstrap daemon user";
-        inherit home;
-        createHome = true;
-      };
-
     systemd.services.tox-bootstrapd = {
       description = "Tox DHT bootstrap daemon";
       after = [ "network.target" ];
@@ -70,8 +63,10 @@ in
       serviceConfig =
         { ExecStart = "${pkg}/bin/tox-bootstrapd --config=${cfgFile}";
           Type = "forking";
-          inherit PIDFile;
-          User = "tox-bootstrapd";
+          inherit PIDFile WorkingDirectory;
+          AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];
+          DynamicUser = true;
+          StateDirectory = "tox-bootstrapd";
         };
     };
 
diff --git a/nixpkgs/nixos/modules/services/networking/toxvpn.nix b/nixpkgs/nixos/modules/services/networking/toxvpn.nix
index 9e97faeebc1e..1765ef3ea2d9 100644
--- a/nixpkgs/nixos/modules/services/networking/toxvpn.nix
+++ b/nixpkgs/nixos/modules/services/networking/toxvpn.nix
@@ -59,10 +59,12 @@ with lib;
 
     users.users = {
       toxvpn = {
-        uid        = config.ids.uids.toxvpn;
+        isSystemUser = true;
+        group = "toxvpn";
         home       = "/var/lib/toxvpn";
         createHome = true;
       };
     };
+    users.groups.toxvpn = {};
   };
 }
diff --git a/nixpkgs/nixos/modules/services/networking/tvheadend.nix b/nixpkgs/nixos/modules/services/networking/tvheadend.nix
index ccf879996631..19a10a03bd9b 100644
--- a/nixpkgs/nixos/modules/services/networking/tvheadend.nix
+++ b/nixpkgs/nixos/modules/services/networking/tvheadend.nix
@@ -29,8 +29,10 @@ in
       description = "Tvheadend Service user";
       home        = "/var/lib/tvheadend";
       createHome  = true;
-      uid         = config.ids.uids.tvheadend;
+      isSystemUser = true;
+      group = "tvheadend";
     };
+    users.groups.tvheadend = {};
 
     systemd.services.tvheadend = {
       description = "Tvheadend TV streaming server";
diff --git a/nixpkgs/nixos/modules/services/networking/unifi.nix b/nixpkgs/nixos/modules/services/networking/unifi.nix
index 2e320378cc9a..73170ebfc903 100644
--- a/nixpkgs/nixos/modules/services/networking/unifi.nix
+++ b/nixpkgs/nixos/modules/services/networking/unifi.nix
@@ -115,10 +115,12 @@ in
   config = mkIf cfg.enable {
 
     users.users.unifi = {
-      uid = config.ids.uids.unifi;
+      isSystemUser = true;
+      group = "unifi";
       description = "UniFi controller daemon user";
       home = "${stateDir}";
     };
+    users.groups.unifi = {};
 
     networking.firewall = mkIf cfg.openPorts {
       # https://help.ubnt.com/hc/en-us/articles/218506997
diff --git a/nixpkgs/nixos/modules/services/networking/vsftpd.nix b/nixpkgs/nixos/modules/services/networking/vsftpd.nix
index c57994533c17..5489f74bf032 100644
--- a/nixpkgs/nixos/modules/services/networking/vsftpd.nix
+++ b/nixpkgs/nixos/modules/services/networking/vsftpd.nix
@@ -282,7 +282,8 @@ in
 
     users.users = {
       "vsftpd" = {
-        uid = config.ids.uids.vsftpd;
+        group = "vsftpd";
+        isSystemUser = true;
         description = "VSFTPD user";
         home = if cfg.localRoot != null
                then cfg.localRoot # <= Necessary for virtual users.
@@ -297,6 +298,7 @@ in
         };
     };
 
+    users.groups.vsftpd = {};
     users.groups.ftp.gid = config.ids.gids.ftp;
 
     # If you really have to access root via FTP use mkOverride or userlistDeny
diff --git a/nixpkgs/nixos/modules/services/networking/x2goserver.nix b/nixpkgs/nixos/modules/services/networking/x2goserver.nix
index 48020fc1ceca..554e51f9d4ff 100644
--- a/nixpkgs/nixos/modules/services/networking/x2goserver.nix
+++ b/nixpkgs/nixos/modules/services/networking/x2goserver.nix
@@ -88,12 +88,14 @@ in {
       source = "${pkgs.x2goserver}/lib/x2go/libx2go-server-db-sqlite3-wrapper.pl";
       owner = "x2go";
       group = "x2go";
+      setuid = false;
       setgid = true;
     };
     security.wrappers.x2goprintWrapper = {
       source = "${pkgs.x2goserver}/bin/x2goprint";
       owner = "x2go";
       group = "x2go";
+      setuid = false;
       setgid = true;
     };
 
diff --git a/nixpkgs/nixos/modules/services/scheduling/atd.nix b/nixpkgs/nixos/modules/services/scheduling/atd.nix
index 37f6651ec4cf..9bb0191ee469 100644
--- a/nixpkgs/nixos/modules/services/scheduling/atd.nix
+++ b/nixpkgs/nixos/modules/services/scheduling/atd.nix
@@ -58,7 +58,9 @@ in
     security.pam.services.atd = {};
 
     users.users.atd =
-      { uid = config.ids.uids.atd;
+      {
+        uid = config.ids.uids.atd;
+        group = "atd";
         description = "atd user";
         home = "/var/empty";
       };
diff --git a/nixpkgs/nixos/modules/services/scheduling/cron.nix b/nixpkgs/nixos/modules/services/scheduling/cron.nix
index 3bc31832946b..c28956b3bfeb 100644
--- a/nixpkgs/nixos/modules/services/scheduling/cron.nix
+++ b/nixpkgs/nixos/modules/services/scheduling/cron.nix
@@ -93,7 +93,12 @@ in
 
     { services.cron.enable = mkDefault (allFiles != []); }
     (mkIf (config.services.cron.enable) {
-      security.wrappers.crontab.source = "${cronNixosPkg}/bin/crontab";
+      security.wrappers.crontab =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${cronNixosPkg}/bin/crontab";
+        };
       environment.systemPackages = [ cronNixosPkg ];
       environment.etc.crontab =
         { source = pkgs.runCommand "crontabs" { inherit allFiles; preferLocalBuild = true; }
diff --git a/nixpkgs/nixos/modules/services/scheduling/fcron.nix b/nixpkgs/nixos/modules/services/scheduling/fcron.nix
index 42bed21bf25b..acaa995f7395 100644
--- a/nixpkgs/nixos/modules/services/scheduling/fcron.nix
+++ b/nixpkgs/nixos/modules/services/scheduling/fcron.nix
@@ -136,10 +136,13 @@ in
         owner = "fcron";
         group = "fcron";
         setgid = true;
+        setuid = false;
       };
       fcronsighup = {
         source = "${pkgs.fcron}/bin/fcronsighup";
+        owner = "root";
         group = "fcron";
+        setuid = true;
       };
     };
     systemd.services.fcron = {
diff --git a/nixpkgs/nixos/modules/services/search/elasticsearch.nix b/nixpkgs/nixos/modules/services/search/elasticsearch.nix
index 1d7a28d5d245..40ebe29c9a60 100644
--- a/nixpkgs/nixos/modules/services/search/elasticsearch.nix
+++ b/nixpkgs/nixos/modules/services/search/elasticsearch.nix
@@ -5,13 +5,13 @@ with lib;
 let
   cfg = config.services.elasticsearch;
 
+  es7 = builtins.compareVersions cfg.package.version "7" >= 0;
+
   esConfig = ''
     network.host: ${cfg.listenAddress}
     cluster.name: ${cfg.cluster_name}
-    ${lib.optionalString cfg.single_node ''
-      discovery.type: single-node
-      gateway.auto_import_dangling_indices: true
-    ''}
+    ${lib.optionalString cfg.single_node "discovery.type: single-node"}
+    ${lib.optionalString (cfg.single_node && es7) "gateway.auto_import_dangling_indices: true"}
 
     http.port: ${toString cfg.port}
     transport.port: ${toString cfg.tcp_port}
@@ -201,6 +201,13 @@ in
 
         if [ "$(id -u)" = 0 ]; then chown -R elasticsearch:elasticsearch ${cfg.dataDir}; fi
       '';
+      postStart = ''
+        # Make sure elasticsearch is up and running before dependents
+        # are started
+        while ! ${pkgs.curl}/bin/curl -sS -f http://localhost:${toString cfg.port} 2>/dev/null; do
+          sleep 1
+        done
+      '';
     };
 
     environment.systemPackages = [ cfg.package ];
diff --git a/nixpkgs/nixos/modules/services/search/kibana.nix b/nixpkgs/nixos/modules/services/search/kibana.nix
index 2beb265ee5d1..b3093abfa5c5 100644
--- a/nixpkgs/nixos/modules/services/search/kibana.nix
+++ b/nixpkgs/nixos/modules/services/search/kibana.nix
@@ -199,10 +199,12 @@ in {
     environment.systemPackages = [ cfg.package ];
 
     users.users.kibana = {
-      uid = config.ids.uids.kibana;
+      isSystemUser = true;
       description = "Kibana service user";
       home = cfg.dataDir;
       createHome = true;
+      group = "kibana";
     };
+    users.groups.kibana = {};
   };
 }
diff --git a/nixpkgs/nixos/modules/services/search/meilisearch.md b/nixpkgs/nixos/modules/services/search/meilisearch.md
new file mode 100644
index 000000000000..98e7c542cb9a
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/search/meilisearch.md
@@ -0,0 +1,39 @@
+# Meilisearch {#module-services-meilisearch}
+
+Meilisearch is a lightweight, fast and powerful search engine. Think elastic search with a much smaller footprint.
+
+## Quickstart
+
+the minimum to start meilisearch is
+
+```nix
+services.meilisearch.enable = true;
+```
+
+this will start the http server included with meilisearch on port 7700.
+
+test with `curl -X GET 'http://localhost:7700/health'`
+
+## Usage
+
+you first need to add documents to an index before you can search for documents.
+
+### Add a documents to the `movies` index
+
+`curl -X POST 'http://127.0.0.1:7700/indexes/movies/documents' --data '[{"id": "123", "title": "Superman"}, {"id": 234, "title": "Batman"}]'`
+
+### Search documents in the `movies` index
+
+`curl 'http://127.0.0.1:7700/indexes/movies/search' --data '{ "q": "botman" }'` (note the typo is intentional and there to demonstrate the typo tolerant capabilities)
+
+## Defaults
+
+- The default nixos package doesn't come with the [dashboard](https://docs.meilisearch.com/learn/getting_started/quick_start.html#search), since the dashboard features makes some assets downloads at compile time.
+
+- Anonimized Analytics sent to meilisearch are disabled by default.
+
+- Default deployment is development mode. It doesn't require a secret master key. All routes are not protected and accessible.
+
+## Missing
+
+- the snapshot feature is not yet configurable from the module, it's just a matter of adding the relevant environment variables.
diff --git a/nixpkgs/nixos/modules/services/search/meilisearch.nix b/nixpkgs/nixos/modules/services/search/meilisearch.nix
new file mode 100644
index 000000000000..f6210f6f16e1
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/search/meilisearch.nix
@@ -0,0 +1,132 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.meilisearch;
+
+in
+{
+
+  meta.maintainers = with maintainers; [ Br1ght0ne happysalada ];
+  # Don't edit the docbook xml directly, edit the md and generate it:
+  # `pandoc meilisearch.md -t docbook --top-level-division=chapter --extract-media=media -f markdown+smart > meilisearch.xml`
+  meta.doc = ./meilisearch.xml;
+
+  ###### interface
+
+  options.services.meilisearch = {
+    enable = mkEnableOption "MeiliSearch - a RESTful search API";
+
+    package = mkOption {
+      description = "The package to use for meilisearch. Use this if you require specific features to be enabled. The default package has no features.";
+      default = pkgs.meilisearch;
+      defaultText = "pkgs.meilisearch";
+      type = types.package;
+    };
+
+    listenAddress = mkOption {
+      description = "MeiliSearch listen address.";
+      default = "127.0.0.1";
+      type = types.str;
+    };
+
+    listenPort = mkOption {
+      description = "MeiliSearch port to listen on.";
+      default = 7700;
+      type = types.port;
+    };
+
+    environment = mkOption {
+      description = "Defines the running environment of MeiliSearch.";
+      default = "development";
+      type = types.enum [ "development" "production" ];
+    };
+
+    # TODO change this to LoadCredentials once possible
+    masterKeyEnvironmentFile = mkOption {
+      description = ''
+        Path to file which contains the master key.
+        By doing so, all routes will be protected and will require a key to be accessed.
+        If no master key is provided, all routes can be accessed without requiring any key.
+        The format is the following:
+        MEILI_MASTER_KEY=my_secret_key
+      '';
+      default = null;
+      type = with types; nullOr path;
+    };
+
+    noAnalytics = mkOption {
+      description = ''
+        Deactivates analytics.
+        Analytics allow MeiliSearch to know how many users are using MeiliSearch,
+        which versions and which platforms are used.
+        This process is entirely anonymous.
+      '';
+      default = true;
+      type = types.bool;
+    };
+
+    logLevel = mkOption {
+      description = ''
+        Defines how much detail should be present in MeiliSearch's logs.
+        MeiliSearch currently supports four log levels, listed in order of increasing verbosity:
+        - 'ERROR': only log unexpected events indicating MeiliSearch is not functioning as expected
+        - 'WARN:' log all unexpected events, regardless of their severity
+        - 'INFO:' log all events. This is the default value
+        - 'DEBUG': log all events and including detailed information on MeiliSearch's internal processes.
+          Useful when diagnosing issues and debugging
+      '';
+      default = "INFO";
+      type = types.str;
+    };
+
+    maxIndexSize = mkOption {
+      description = ''
+        Sets the maximum size of the index.
+        Value must be given in bytes or explicitly stating a base unit.
+        For example, the default value can be written as 107374182400, '107.7Gb', or '107374 Mb'.
+        Default is 100 GiB
+      '';
+      default = "107374182400";
+      type = types.str;
+    };
+
+    payloadSizeLimit = mkOption {
+      description = ''
+        Sets the maximum size of accepted JSON payloads.
+        Value must be given in bytes or explicitly stating a base unit.
+        For example, the default value can be written as 107374182400, '107.7Gb', or '107374 Mb'.
+        Default is ~ 100 MB
+      '';
+      default = "104857600";
+      type = types.str;
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    systemd.services.meilisearch = {
+      description = "MeiliSearch daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      environment = {
+        MEILI_DB_PATH = "/var/lib/meilisearch";
+        MEILI_HTTP_ADDR = "${cfg.listenAddress}:${toString cfg.listenPort}";
+        MEILI_NO_ANALYTICS = toString cfg.noAnalytics;
+        MEILI_ENV = cfg.environment;
+        MEILI_DUMPS_DIR = "/var/lib/meilisearch/dumps";
+        MEILI_LOG_LEVEL = cfg.logLevel;
+        MEILI_MAX_INDEX_SIZE = cfg.maxIndexSize;
+      };
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/meilisearch";
+        DynamicUser = true;
+        StateDirectory = "meilisearch";
+        EnvironmentFile = mkIf (cfg.masterKeyEnvironmentFile != null) cfg.masterKeyEnvironmentFile;
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/search/meilisearch.xml b/nixpkgs/nixos/modules/services/search/meilisearch.xml
new file mode 100644
index 000000000000..c1a73f358c28
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/search/meilisearch.xml
@@ -0,0 +1,85 @@
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="module-services-meilisearch">
+  <title>Meilisearch</title>
+  <para>
+    Meilisearch is a lightweight, fast and powerful search engine. Think
+    elastic search with a much smaller footprint.
+  </para>
+  <section xml:id="quickstart">
+    <title>Quickstart</title>
+    <para>
+      the minimum to start meilisearch is
+    </para>
+    <programlisting language="bash">
+services.meilisearch.enable = true;
+</programlisting>
+    <para>
+      this will start the http server included with meilisearch on port
+      7700.
+    </para>
+    <para>
+      test with
+      <literal>curl -X GET 'http://localhost:7700/health'</literal>
+    </para>
+  </section>
+  <section xml:id="usage">
+    <title>Usage</title>
+    <para>
+      you first need to add documents to an index before you can search
+      for documents.
+    </para>
+    <section xml:id="add-a-documents-to-the-movies-index">
+      <title>Add a documents to the <literal>movies</literal>
+      index</title>
+      <para>
+        <literal>curl -X POST 'http://127.0.0.1:7700/indexes/movies/documents' --data '[{&quot;id&quot;: &quot;123&quot;, &quot;title&quot;: &quot;Superman&quot;}, {&quot;id&quot;: 234, &quot;title&quot;: &quot;Batman&quot;}]'</literal>
+      </para>
+    </section>
+    <section xml:id="search-documents-in-the-movies-index">
+      <title>Search documents in the <literal>movies</literal>
+      index</title>
+      <para>
+        <literal>curl 'http://127.0.0.1:7700/indexes/movies/search' --data '{ &quot;q&quot;: &quot;botman&quot; }'</literal>
+        (note the typo is intentional and there to demonstrate the typo
+        tolerant capabilities)
+      </para>
+    </section>
+  </section>
+  <section xml:id="defaults">
+    <title>Defaults</title>
+    <itemizedlist>
+      <listitem>
+        <para>
+          The default nixos package doesn’t come with the
+          <link xlink:href="https://docs.meilisearch.com/learn/getting_started/quick_start.html#search">dashboard</link>,
+          since the dashboard features makes some assets downloads at
+          compile time.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Anonimized Analytics sent to meilisearch are disabled by
+          default.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Default deployment is development mode. It doesn’t require a
+          secret master key. All routes are not protected and
+          accessible.
+        </para>
+      </listitem>
+    </itemizedlist>
+  </section>
+  <section xml:id="missing">
+    <title>Missing</title>
+    <itemizedlist spacing="compact">
+      <listitem>
+        <para>
+          the snapshot feature is not yet configurable from the module,
+          it’s just a matter of adding the relevant environment
+          variables.
+        </para>
+      </listitem>
+    </itemizedlist>
+  </section>
+</chapter>
diff --git a/nixpkgs/nixos/modules/services/security/hockeypuck.nix b/nixpkgs/nixos/modules/services/security/hockeypuck.nix
index 686634c8add8..2e98624bb2ee 100644
--- a/nixpkgs/nixos/modules/services/security/hockeypuck.nix
+++ b/nixpkgs/nixos/modules/services/security/hockeypuck.nix
@@ -82,8 +82,10 @@ in {
 
     users.users.hockeypuck = {
       isSystemUser = true;
+      group = "hockeypuck";
       description = "Hockeypuck user";
     };
+    users.groups.hockeypuck = {};
 
     systemd.services.hockeypuck = {
       description = "Hockeypuck OpenPGP Key Server";
diff --git a/nixpkgs/nixos/modules/services/security/opensnitch.nix b/nixpkgs/nixos/modules/services/security/opensnitch.nix
new file mode 100644
index 000000000000..919346cf2bb1
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/security/opensnitch.nix
@@ -0,0 +1,24 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  name = "opensnitch";
+  cfg = config.services.opensnitch;
+in {
+  options = {
+    services.opensnitch = {
+      enable = mkEnableOption "Opensnitch application firewall";
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd = {
+      packages = [ pkgs.opensnitch ];
+      services.opensnitchd.wantedBy = [ "multi-user.target" ];
+    };
+
+  };
+}
+
diff --git a/nixpkgs/nixos/modules/services/security/physlock.nix b/nixpkgs/nixos/modules/services/security/physlock.nix
index da5c22a90a09..760e80f147f7 100644
--- a/nixpkgs/nixos/modules/services/security/physlock.nix
+++ b/nixpkgs/nixos/modules/services/security/physlock.nix
@@ -38,9 +38,6 @@ in
           setuid wrapper to allow any user to start physlock as root, which
           is a minor security risk. Call the physlock binary to use this instead
           of using the systemd service.
-
-          Note that you might need to relog to have the correct binary in your
-          PATH upon changing this option.
         '';
       };
 
@@ -129,7 +126,12 @@ in
 
     (mkIf cfg.allowAnyUser {
 
-      security.wrappers.physlock = { source = "${pkgs.physlock}/bin/physlock"; user = "root"; };
+      security.wrappers.physlock =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.physlock}/bin/physlock";
+        };
 
     })
   ]);
diff --git a/nixpkgs/nixos/modules/services/security/tor.nix b/nixpkgs/nixos/modules/services/security/tor.nix
index 9e8f18e93c85..1e1f443905d4 100644
--- a/nixpkgs/nixos/modules/services/security/tor.nix
+++ b/nixpkgs/nixos/modules/services/security/tor.nix
@@ -1022,7 +1022,7 @@ in
         ProtectKernelTunables = true;
         ProtectSystem = "strict";
         RemoveIPC = true;
-        RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
+        RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ];
         RestrictNamespaces = true;
         RestrictRealtime = true;
         RestrictSUIDSGID = true;
diff --git a/nixpkgs/nixos/modules/services/system/kerberos/heimdal.nix b/nixpkgs/nixos/modules/services/system/kerberos/heimdal.nix
index f0e56c7951a4..837c59caa562 100644
--- a/nixpkgs/nixos/modules/services/system/kerberos/heimdal.nix
+++ b/nixpkgs/nixos/modules/services/system/kerberos/heimdal.nix
@@ -27,7 +27,7 @@ in
 {
   # No documentation about correct triggers, so guessing at them.
 
-  config = mkIf (cfg.enable && kerberos == pkgs.heimdalFull) {
+  config = mkIf (cfg.enable && kerberos == pkgs.heimdal) {
     systemd.services.kadmind = {
       description = "Kerberos Administration Daemon";
       wantedBy = [ "multi-user.target" ];
diff --git a/nixpkgs/nixos/modules/services/system/localtime.nix b/nixpkgs/nixos/modules/services/system/localtime.nix
index bb99e5e36ff8..8f23454af9df 100644
--- a/nixpkgs/nixos/modules/services/system/localtime.nix
+++ b/nixpkgs/nixos/modules/services/system/localtime.nix
@@ -37,7 +37,9 @@ in {
     users.users.localtimed = {
       description = "localtime daemon";
       isSystemUser = true;
+      group = "localtimed";
     };
+    users.groups.localtimed = {};
 
     systemd.services.localtime = {
       wantedBy = [ "multi-user.target" ];
diff --git a/nixpkgs/nixos/modules/services/torrent/magnetico.nix b/nixpkgs/nixos/modules/services/torrent/magnetico.nix
index 7465c10e002c..ada6f9b1e3a9 100644
--- a/nixpkgs/nixos/modules/services/torrent/magnetico.nix
+++ b/nixpkgs/nixos/modules/services/torrent/magnetico.nix
@@ -172,8 +172,10 @@ in {
 
     users.users.magnetico = {
       description = "Magnetico daemons user";
+      group = "magnetico";
       isSystemUser = true;
     };
+    users.groups.magnetico = {};
 
     systemd.services.magneticod = {
       description = "Magnetico DHT crawler";
diff --git a/nixpkgs/nixos/modules/services/torrent/peerflix.nix b/nixpkgs/nixos/modules/services/torrent/peerflix.nix
index a74f65984328..3e5f80960dc7 100644
--- a/nixpkgs/nixos/modules/services/torrent/peerflix.nix
+++ b/nixpkgs/nixos/modules/services/torrent/peerflix.nix
@@ -60,6 +60,10 @@ in {
       };
     };
 
-    users.users.peerflix.uid = config.ids.uids.peerflix;
+    users.users.peerflix = {
+      isSystemUser = true;
+      group = "peerflix";
+    };
+    users.groups.peerflix = {};
   };
 }
diff --git a/nixpkgs/nixos/modules/services/ttys/getty.nix b/nixpkgs/nixos/modules/services/ttys/getty.nix
index 7cf2ff87da26..eb966c37ce7f 100644
--- a/nixpkgs/nixos/modules/services/ttys/getty.nix
+++ b/nixpkgs/nixos/modules/services/ttys/getty.nix
@@ -131,6 +131,14 @@ in
         restartIfChanged = false;
       };
 
+    systemd.services."autovt@" =
+      { serviceConfig.ExecStart = [
+          "" # override upstream default with an empty ExecStart
+          (gettyCmd "--noclear %I $TERM")
+        ];
+        restartIfChanged = false;
+      };
+
     systemd.services."container-getty@" =
       { serviceConfig.ExecStart = [
           "" # override upstream default with an empty ExecStart
diff --git a/nixpkgs/nixos/modules/services/video/replay-sorcery.nix b/nixpkgs/nixos/modules/services/video/replay-sorcery.nix
index d78e782c7968..7ce5be8a5a1c 100644
--- a/nixpkgs/nixos/modules/services/video/replay-sorcery.nix
+++ b/nixpkgs/nixos/modules/services/video/replay-sorcery.nix
@@ -44,8 +44,10 @@ in
 
     security.wrappers = mkIf cfg.enableSysAdminCapability {
       replay-sorcery = {
-        source = "${pkgs.replay-sorcery}/bin/replay-sorcery";
+        owner = "root";
+        group = "root";
         capabilities = "cap_sys_admin+ep";
+        source = "${pkgs.replay-sorcery}/bin/replay-sorcery";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/web-apps/discourse.nix b/nixpkgs/nixos/modules/services/web-apps/discourse.nix
index 050e4ee3d329..b28e3cf0deb2 100644
--- a/nixpkgs/nixos/modules/services/web-apps/discourse.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/discourse.nix
@@ -172,6 +172,15 @@ in
       };
 
       admin = {
+        skipCreate = lib.mkOption {
+          type = lib.types.bool;
+          default = false;
+          description = ''
+            Do not create the admin account, instead rely on other
+            existing admin accounts.
+          '';
+        };
+
         email = lib.mkOption {
           type = lib.types.str;
           example = "admin@example.com";
@@ -721,12 +730,24 @@ in
             lib.optionalString (file != null) ''
               replace-secret '${file}' '${file}' /run/discourse/config/discourse.conf
             '';
+
+          mkAdmin = ''
+            export ADMIN_EMAIL="${cfg.admin.email}"
+            export ADMIN_NAME="${cfg.admin.fullName}"
+            export ADMIN_USERNAME="${cfg.admin.username}"
+            ADMIN_PASSWORD="$(<${cfg.admin.passwordFile})"
+            export ADMIN_PASSWORD
+            discourse-rake admin:create_noninteractively
+          '';
+
         in ''
           set -o errexit -o pipefail -o nounset -o errtrace
           shopt -s inherit_errexit
 
           umask u=rwx,g=rx,o=
 
+          rm -rf /var/lib/discourse/tmp/*
+
           cp -r ${cfg.package}/share/discourse/config.dist/* /run/discourse/config/
           cp -r ${cfg.package}/share/discourse/public.dist/* /run/discourse/public/
           ln -sf /var/lib/discourse/uploads /run/discourse/public/uploads
@@ -748,14 +769,9 @@ in
           )
 
           discourse-rake db:migrate >>/var/log/discourse/db_migration.log
-          chmod -R u+w /run/discourse/tmp/
+          chmod -R u+w /var/lib/discourse/tmp/
 
-          export ADMIN_EMAIL="${cfg.admin.email}"
-          export ADMIN_NAME="${cfg.admin.fullName}"
-          export ADMIN_USERNAME="${cfg.admin.username}"
-          ADMIN_PASSWORD="$(<${cfg.admin.passwordFile})"
-          export ADMIN_PASSWORD
-          discourse-rake admin:create_noninteractively
+          ${lib.optionalString (!cfg.admin.skipCreate) mkAdmin}
 
           discourse-rake themes:update
           discourse-rake uploads:regenerate_missing_optimized
@@ -768,7 +784,6 @@ in
         RuntimeDirectory = map (p: "discourse/" + p) [
           "config"
           "home"
-          "tmp"
           "assets/javascripts/plugins"
           "public"
           "sockets"
@@ -777,6 +792,7 @@ in
         StateDirectory = map (p: "discourse/" + p) [
           "uploads"
           "backups"
+          "tmp"
         ];
         StateDirectoryMode = 0750;
         LogsDirectory = "discourse";
diff --git a/nixpkgs/nixos/modules/services/web-apps/dokuwiki.nix b/nixpkgs/nixos/modules/services/web-apps/dokuwiki.nix
index 685cb4967030..964fef23addf 100644
--- a/nixpkgs/nixos/modules/services/web-apps/dokuwiki.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/dokuwiki.nix
@@ -1,16 +1,21 @@
-{ config, lib, pkgs, ... }:
+{ config, pkgs, lib, ... }:
 
 let
+  inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types maintainers recursiveUpdate;
+  inherit (lib) any attrValues concatMapStrings concatMapStringsSep flatten literalExample;
+  inherit (lib) filterAttrs mapAttrs mapAttrs' mapAttrsToList nameValuePair optional optionalAttrs optionalString;
 
-  inherit (lib) mkEnableOption mkForce mkIf mkMerge mkOption optionalAttrs recursiveUpdate types maintainers;
-  inherit (lib) concatMapStringsSep flatten mapAttrs mapAttrs' mapAttrsToList nameValuePair concatMapStringSep;
-
-  eachSite = config.services.dokuwiki;
-
+  cfg = migrateOldAttrs config.services.dokuwiki;
+  eachSite = cfg.sites;
   user = "dokuwiki";
-  group = config.services.nginx.group;
+  webserver = config.services.${cfg.webserver};
+  stateDir = hostName: "/var/lib/dokuwiki/${hostName}/data";
+
+  # Migrate config.services.dokuwiki.<hostName> to config.services.dokuwiki.sites.<hostName>
+  oldSites = filterAttrs (o: _: o != "sites" && o != "webserver");
+  migrateOldAttrs = cfg: cfg // { sites = cfg.sites // oldSites cfg; };
 
-  dokuwikiAclAuthConfig = cfg: pkgs.writeText "acl.auth.php" ''
+  dokuwikiAclAuthConfig = hostName: cfg: pkgs.writeText "acl.auth-${hostName}.php" ''
     # acl.auth.php
     # <?php exit()?>
     #
@@ -19,7 +24,7 @@ let
     ${toString cfg.acl}
   '';
 
-  dokuwikiLocalConfig = cfg: pkgs.writeText "local.php" ''
+  dokuwikiLocalConfig = hostName: cfg: pkgs.writeText "local-${hostName}.php" ''
     <?php
     $conf['savedir'] = '${cfg.stateDir}';
     $conf['superuser'] = '${toString cfg.superUser}';
@@ -28,11 +33,12 @@ let
     ${toString cfg.extraConfig}
   '';
 
-  dokuwikiPluginsLocalConfig = cfg: pkgs.writeText "plugins.local.php" ''
+  dokuwikiPluginsLocalConfig = hostName: cfg: pkgs.writeText "plugins.local-${hostName}.php" ''
     <?php
     ${cfg.pluginsConfig}
   '';
 
+
   pkg = hostName: cfg: pkgs.stdenv.mkDerivation rec {
     pname = "dokuwiki-${hostName}";
     version = src.version;
@@ -43,13 +49,13 @@ let
       cp -r * $out/
 
       # symlink the dokuwiki config
-      ln -s ${dokuwikiLocalConfig cfg} $out/share/dokuwiki/local.php
+      ln -s ${dokuwikiLocalConfig hostName cfg} $out/share/dokuwiki/local.php
 
       # symlink plugins config
-      ln -s ${dokuwikiPluginsLocalConfig cfg} $out/share/dokuwiki/plugins.local.php
+      ln -s ${dokuwikiPluginsLocalConfig hostName cfg} $out/share/dokuwiki/plugins.local.php
 
       # symlink acl
-      ln -s ${dokuwikiAclAuthConfig cfg} $out/share/dokuwiki/acl.auth.php
+      ln -s ${dokuwikiAclAuthConfig hostName cfg} $out/share/dokuwiki/acl.auth.php
 
       # symlink additional plugin(s) and templates(s)
       ${concatMapStringsSep "\n" (template: "ln -s ${template} $out/share/dokuwiki/lib/tpl/${template.name}") cfg.templates}
@@ -57,332 +63,385 @@ let
     '';
   };
 
-  siteOpts = { config, lib, name, ...}: {
-    options = {
-      enable = mkEnableOption "DokuWiki web application.";
-
-      package = mkOption {
-        type = types.package;
-        default = pkgs.dokuwiki;
-        description = "Which dokuwiki package to use.";
-      };
+  siteOpts = { config, lib, name, ... }:
+    {
+      options = {
+        package = mkOption {
+          type = types.package;
+          default = pkgs.dokuwiki;
+          description = "Which DokuWiki package to use.";
+        };
 
-      hostName = mkOption {
-        type = types.str;
-        default = "localhost";
-        description = "FQDN for the instance.";
-      };
+        stateDir = mkOption {
+          type = types.path;
+          default = "/var/lib/dokuwiki/${name}/data";
+          description = "Location of the DokuWiki state directory.";
+        };
 
-      stateDir = mkOption {
-        type = types.path;
-        default = "/var/lib/dokuwiki/${name}/data";
-        description = "Location of the dokuwiki state directory.";
-      };
+        acl = mkOption {
+          type = types.nullOr types.lines;
+          default = null;
+          example = "*               @ALL               8";
+          description = ''
+            Access Control Lists: see <link xlink:href="https://www.dokuwiki.org/acl"/>
+            Mutually exclusive with services.dokuwiki.aclFile
+            Set this to a value other than null to take precedence over aclFile option.
+
+            Warning: Consider using aclFile instead if you do not
+            want to store the ACL in the world-readable Nix store.
+          '';
+        };
 
-      acl = mkOption {
-        type = types.nullOr types.lines;
-        default = null;
-        example = "*               @ALL               8";
-        description = ''
-          Access Control Lists: see <link xlink:href="https://www.dokuwiki.org/acl"/>
-          Mutually exclusive with services.dokuwiki.aclFile
-          Set this to a value other than null to take precedence over aclFile option.
-
-          Warning: Consider using aclFile instead if you do not
-          want to store the ACL in the world-readable Nix store.
-        '';
-      };
+        aclFile = mkOption {
+          type = with types; nullOr str;
+          default = if (config.aclUse && config.acl == null) then "/var/lib/dokuwiki/${name}/acl.auth.php" else null;
+          description = ''
+            Location of the dokuwiki acl rules. Mutually exclusive with services.dokuwiki.acl
+            Mutually exclusive with services.dokuwiki.acl which is preferred.
+            Consult documentation <link xlink:href="https://www.dokuwiki.org/acl"/> for further instructions.
+            Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/acl.auth.php.dist"/>
+          '';
+          example = "/var/lib/dokuwiki/${name}/acl.auth.php";
+        };
 
-      aclFile = mkOption {
-        type = with types; nullOr str;
-        default = if (config.aclUse && config.acl == null) then "/var/lib/dokuwiki/${name}/acl.auth.php" else null;
-        description = ''
-          Location of the dokuwiki acl rules. Mutually exclusive with services.dokuwiki.acl
-          Mutually exclusive with services.dokuwiki.acl which is preferred.
-          Consult documentation <link xlink:href="https://www.dokuwiki.org/acl"/> for further instructions.
-          Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/acl.auth.php.dist"/>
-        '';
-        example = "/var/lib/dokuwiki/${name}/acl.auth.php";
-      };
+        aclUse = mkOption {
+          type = types.bool;
+          default = true;
+          description = ''
+            Necessary for users to log in into the system.
+            Also limits anonymous users. When disabled,
+            everyone is able to create and edit content.
+          '';
+        };
 
-      aclUse = mkOption {
-        type = types.bool;
-        default = true;
-        description = ''
-          Necessary for users to log in into the system.
-          Also limits anonymous users. When disabled,
-          everyone is able to create and edit content.
-        '';
-      };
+        pluginsConfig = mkOption {
+          type = types.lines;
+          default = ''
+            $plugins['authad'] = 0;
+            $plugins['authldap'] = 0;
+            $plugins['authmysql'] = 0;
+            $plugins['authpgsql'] = 0;
+          '';
+          description = ''
+            List of the dokuwiki (un)loaded plugins.
+          '';
+        };
 
-      pluginsConfig = mkOption {
-        type = types.lines;
-        default = ''
-          $plugins['authad'] = 0;
-          $plugins['authldap'] = 0;
-          $plugins['authmysql'] = 0;
-          $plugins['authpgsql'] = 0;
-        '';
-        description = ''
-          List of the dokuwiki (un)loaded plugins.
-        '';
-      };
+        superUser = mkOption {
+          type = types.nullOr types.str;
+          default = "@admin";
+          description = ''
+            You can set either a username, a list of usernames (“admin1,admin2”),
+            or the name of a group by prepending an @ char to the groupname
+            Consult documentation <link xlink:href="https://www.dokuwiki.org/config:superuser"/> for further instructions.
+          '';
+        };
 
-      superUser = mkOption {
-        type = types.nullOr types.str;
-        default = "@admin";
-        description = ''
-          You can set either a username, a list of usernames (“admin1,admin2”),
-          or the name of a group by prepending an @ char to the groupname
-          Consult documentation <link xlink:href="https://www.dokuwiki.org/config:superuser"/> for further instructions.
-        '';
-      };
+        usersFile = mkOption {
+          type = with types; nullOr str;
+          default = if config.aclUse then "/var/lib/dokuwiki/${name}/users.auth.php" else null;
+          description = ''
+            Location of the dokuwiki users file. List of users. Format:
+            login:passwordhash:Real Name:email:groups,comma,separated
+            Create passwordHash easily by using:$ mkpasswd -5 password `pwgen 8 1`
+            Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/users.auth.php.dist"/>
+            '';
+          example = "/var/lib/dokuwiki/${name}/users.auth.php";
+        };
 
-      usersFile = mkOption {
-        type = with types; nullOr str;
-        default = if config.aclUse then "/var/lib/dokuwiki/${name}/users.auth.php" else null;
-        description = ''
-          Location of the dokuwiki users file. List of users. Format:
-          login:passwordhash:Real Name:email:groups,comma,separated
-          Create passwordHash easily by using:$ mkpasswd -5 password `pwgen 8 1`
-          Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/users.auth.php.dist"/>
+        disableActions = mkOption {
+          type = types.nullOr types.str;
+          default = "";
+          example = "search,register";
+          description = ''
+            Disable individual action modes. Refer to
+            <link xlink:href="https://www.dokuwiki.org/config:action_modes"/>
+            for details on supported values.
           '';
-        example = "/var/lib/dokuwiki/${name}/users.auth.php";
-      };
+        };
 
-      disableActions = mkOption {
-        type = types.nullOr types.str;
-        default = "";
-        example = "search,register";
-        description = ''
-          Disable individual action modes. Refer to
-          <link xlink:href="https://www.dokuwiki.org/config:action_modes"/>
-          for details on supported values.
-        '';
-      };
+        plugins = mkOption {
+          type = types.listOf types.path;
+          default = [];
+          description = ''
+                List of path(s) to respective plugin(s) which are copied from the 'plugin' directory.
+                <note><para>These plugins need to be packaged before use, see example.</para></note>
+          '';
+          example = ''
+                # Let's package the icalevents plugin
+                plugin-icalevents = pkgs.stdenv.mkDerivation {
+                  name = "icalevents";
+                  # Download the plugin from the dokuwiki site
+                  src = pkgs.fetchurl {
+                    url = "https://github.com/real-or-random/dokuwiki-plugin-icalevents/releases/download/2017-06-16/dokuwiki-plugin-icalevents-2017-06-16.zip";
+                    sha256 = "e40ed7dd6bbe7fe3363bbbecb4de481d5e42385b5a0f62f6a6ce6bf3a1f9dfa8";
+                  };
+                  sourceRoot = ".";
+                  # We need unzip to build this package
+                  buildInputs = [ pkgs.unzip ];
+                  # Installing simply means copying all files to the output directory
+                  installPhase = "mkdir -p $out; cp -R * $out/";
+                };
 
-      extraConfig = mkOption {
-        type = types.nullOr types.lines;
-        default = null;
-        example = ''
-          $conf['title'] = 'My Wiki';
-          $conf['userewrite'] = 1;
-        '';
-        description = ''
-          DokuWiki configuration. Refer to
-          <link xlink:href="https://www.dokuwiki.org/config"/>
-          for details on supported values.
-        '';
-      };
+                # And then pass this theme to the plugin list like this:
+                plugins = [ plugin-icalevents ];
+          '';
+        };
 
-      plugins = mkOption {
-        type = types.listOf types.path;
-        default = [];
-        description = ''
-              List of path(s) to respective plugin(s) which are copied from the 'plugin' directory.
-              <note><para>These plugins need to be packaged before use, see example.</para></note>
-        '';
-        example = ''
-              # Let's package the icalevents plugin
-              plugin-icalevents = pkgs.stdenv.mkDerivation {
-                name = "icalevents";
-                # Download the plugin from the dokuwiki site
-                src = pkgs.fetchurl {
-                  url = "https://github.com/real-or-random/dokuwiki-plugin-icalevents/releases/download/2017-06-16/dokuwiki-plugin-icalevents-2017-06-16.zip";
-                  sha256 = "e40ed7dd6bbe7fe3363bbbecb4de481d5e42385b5a0f62f6a6ce6bf3a1f9dfa8";
+        templates = mkOption {
+          type = types.listOf types.path;
+          default = [];
+          description = ''
+                List of path(s) to respective template(s) which are copied from the 'tpl' directory.
+                <note><para>These templates need to be packaged before use, see example.</para></note>
+          '';
+          example = ''
+                # Let's package the bootstrap3 theme
+                template-bootstrap3 = pkgs.stdenv.mkDerivation {
+                  name = "bootstrap3";
+                  # Download the theme from the dokuwiki site
+                  src = pkgs.fetchurl {
+                    url = "https://github.com/giterlizzi/dokuwiki-template-bootstrap3/archive/v2019-05-22.zip";
+                    sha256 = "4de5ff31d54dd61bbccaf092c9e74c1af3a4c53e07aa59f60457a8f00cfb23a6";
+                  };
+                  # We need unzip to build this package
+                  buildInputs = [ pkgs.unzip ];
+                  # Installing simply means copying all files to the output directory
+                  installPhase = "mkdir -p $out; cp -R * $out/";
                 };
-                sourceRoot = ".";
-                # We need unzip to build this package
-                nativeBuildInputs = [ pkgs.unzip ];
-                # Installing simply means copying all files to the output directory
-                installPhase = "mkdir -p $out; cp -R * $out/";
-              };
-
-              # And then pass this theme to the plugin list like this:
-              plugins = [ plugin-icalevents ];
-        '';
-      };
 
-      templates = mkOption {
-        type = types.listOf types.path;
-        default = [];
-        description = ''
-              List of path(s) to respective template(s) which are copied from the 'tpl' directory.
-              <note><para>These templates need to be packaged before use, see example.</para></note>
-        '';
-        example = ''
-              # Let's package the bootstrap3 theme
-              template-bootstrap3 = pkgs.stdenv.mkDerivation {
-                name = "bootstrap3";
-                # Download the theme from the dokuwiki site
-                src = pkgs.fetchurl {
-                  url = "https://github.com/giterlizzi/dokuwiki-template-bootstrap3/archive/v2019-05-22.zip";
-                  sha256 = "4de5ff31d54dd61bbccaf092c9e74c1af3a4c53e07aa59f60457a8f00cfb23a6";
-                };
-                # We need unzip to build this package
-                nativeBuildInputs = [ pkgs.unzip ];
-                # Installing simply means copying all files to the output directory
-                installPhase = "mkdir -p $out; cp -R * $out/";
-              };
-
-              # And then pass this theme to the template list like this:
-              templates = [ template-bootstrap3 ];
-        '';
-      };
+                # And then pass this theme to the template list like this:
+                templates = [ template-bootstrap3 ];
+          '';
+        };
 
-      poolConfig = mkOption {
-        type = with types; attrsOf (oneOf [ str int bool ]);
-        default = {
-          "pm" = "dynamic";
-          "pm.max_children" = 32;
-          "pm.start_servers" = 2;
-          "pm.min_spare_servers" = 2;
-          "pm.max_spare_servers" = 4;
-          "pm.max_requests" = 500;
+        poolConfig = mkOption {
+          type = with types; attrsOf (oneOf [ str int bool ]);
+          default = {
+            "pm" = "dynamic";
+            "pm.max_children" = 32;
+            "pm.start_servers" = 2;
+            "pm.min_spare_servers" = 2;
+            "pm.max_spare_servers" = 4;
+            "pm.max_requests" = 500;
+          };
+          description = ''
+            Options for the DokuWiki PHP pool. See the documentation on <literal>php-fpm.conf</literal>
+            for details on configuration directives.
+          '';
         };
-        description = ''
-          Options for the dokuwiki PHP pool. See the documentation on <literal>php-fpm.conf</literal>
-          for details on configuration directives.
-        '';
-      };
 
-      nginx = mkOption {
-        type = types.submodule (
-          recursiveUpdate
-            (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) {}
-        );
-        default = {};
-        example = {
-          serverAliases = [
-            "wiki.\${config.networking.domain}"
-          ];
-          # To enable encryption and let let's encrypt take care of certificate
-          forceSSL = true;
-          enableACME = true;
+        extraConfig = mkOption {
+          type = types.nullOr types.lines;
+          default = null;
+          example = ''
+            $conf['title'] = 'My Wiki';
+            $conf['userewrite'] = 1;
+          '';
+          description = ''
+            DokuWiki configuration. Refer to
+            <link xlink:href="https://www.dokuwiki.org/config"/>
+            for details on supported values.
+          '';
         };
-        description = ''
-          With this option, you can customize the nginx virtualHost settings.
-        '';
+
       };
+
     };
-  };
 in
 {
   # interface
   options = {
     services.dokuwiki = mkOption {
-      type = types.attrsOf (types.submodule siteOpts);
+      type = types.submodule {
+        # Used to support old interface
+        freeformType = types.attrsOf (types.submodule siteOpts);
+
+        # New interface
+        options.sites = mkOption {
+          type = types.attrsOf (types.submodule siteOpts);
+          default = {};
+          description = "Specification of one or more DokuWiki sites to serve";
+        };
+
+        options.webserver = mkOption {
+          type = types.enum [ "nginx" "caddy" ];
+          default = "nginx";
+          description = ''
+            Whether to use nginx or caddy for virtual host management.
+
+            Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.&lt;name&gt;</literal>.
+            See <xref linkend="opt-services.nginx.virtualHosts"/> for further information.
+
+            Further apache2 configuration can be done by adapting <literal>services.httpd.virtualHosts.&lt;name&gt;</literal>.
+            See <xref linkend="opt-services.httpd.virtualHosts"/> for further information.
+          '';
+        };
+      };
       default = {};
-      description = "Sepcification of one or more dokuwiki sites to serve.";
+      description = "DokuWiki configuration";
     };
+
   };
 
   # implementation
-
-  config = mkIf (eachSite != {}) {
-
-    warnings = mapAttrsToList (hostName: cfg: mkIf (cfg.superUser == null) "Not setting services.dokuwiki.${hostName} superUser will impair your ability to administer DokuWiki") eachSite;
+  config = mkIf (eachSite != {}) (mkMerge [{
 
     assertions = flatten (mapAttrsToList (hostName: cfg:
     [{
       assertion = cfg.aclUse -> (cfg.acl != null || cfg.aclFile != null);
-      message = "Either services.dokuwiki.${hostName}.acl or services.dokuwiki.${hostName}.aclFile is mandatory if aclUse true";
+      message = "Either services.dokuwiki.sites.${hostName}.acl or services.dokuwiki.sites.${hostName}.aclFile is mandatory if aclUse true";
     }
     {
       assertion = cfg.usersFile != null -> cfg.aclUse != false;
-      message = "services.dokuwiki.${hostName}.aclUse must must be true if usersFile is not null";
+      message = "services.dokuwiki.sites.${hostName}.aclUse must must be true if usersFile is not null";
     }
     ]) eachSite);
 
+    warnings = mapAttrsToList (hostName: _: ''services.dokuwiki."${hostName}" is deprecated use services.dokuwiki.sites."${hostName}"'') (oldSites cfg);
+
     services.phpfpm.pools = mapAttrs' (hostName: cfg: (
       nameValuePair "dokuwiki-${hostName}" {
         inherit user;
-        inherit group;
+        group = webserver.group;
+
         phpEnv = {
-          DOKUWIKI_LOCAL_CONFIG = "${dokuwikiLocalConfig cfg}";
-          DOKUWIKI_PLUGINS_LOCAL_CONFIG = "${dokuwikiPluginsLocalConfig cfg}";
+          DOKUWIKI_LOCAL_CONFIG = "${dokuwikiLocalConfig hostName cfg}";
+          DOKUWIKI_PLUGINS_LOCAL_CONFIG = "${dokuwikiPluginsLocalConfig hostName cfg}";
         } // optionalAttrs (cfg.usersFile != null) {
           DOKUWIKI_USERS_AUTH_CONFIG = "${cfg.usersFile}";
         } //optionalAttrs (cfg.aclUse) {
-          DOKUWIKI_ACL_AUTH_CONFIG = if (cfg.acl != null) then "${dokuwikiAclAuthConfig cfg}" else "${toString cfg.aclFile}";
+          DOKUWIKI_ACL_AUTH_CONFIG = if (cfg.acl != null) then "${dokuwikiAclAuthConfig hostName cfg}" else "${toString cfg.aclFile}";
         };
 
         settings = {
-          "listen.mode" = "0660";
-          "listen.owner" = user;
-          "listen.group" = group;
+          "listen.owner" = webserver.user;
+          "listen.group" = webserver.group;
         } // cfg.poolConfig;
-      })) eachSite;
-
-    services.nginx = {
-      enable = true;
-      virtualHosts = mapAttrs (hostName: cfg:  mkMerge [ cfg.nginx {
-        root = mkForce "${pkg hostName cfg}/share/dokuwiki";
-        extraConfig = lib.optionalString (cfg.nginx.addSSL || cfg.nginx.forceSSL || cfg.nginx.onlySSL || cfg.nginx.enableACME) "fastcgi_param HTTPS on;";
-
-        locations."~ /(conf/|bin/|inc/|install.php)" = {
-          extraConfig = "deny all;";
-        };
+      }
+    )) eachSite;
 
-        locations."~ ^/data/" = {
-          root = "${cfg.stateDir}";
-          extraConfig = "internal;";
-        };
+  }
 
-        locations."~ ^/lib.*\\.(js|css|gif|png|ico|jpg|jpeg)$" = {
-          extraConfig = "expires 365d;";
-        };
+  {
+    systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [
+      "d ${stateDir hostName}/attic 0750 ${user} ${webserver.group} - -"
+      "d ${stateDir hostName}/cache 0750 ${user} ${webserver.group} - -"
+      "d ${stateDir hostName}/index 0750 ${user} ${webserver.group} - -"
+      "d ${stateDir hostName}/locks 0750 ${user} ${webserver.group} - -"
+      "d ${stateDir hostName}/media 0750 ${user} ${webserver.group} - -"
+      "d ${stateDir hostName}/media_attic 0750 ${user} ${webserver.group} - -"
+      "d ${stateDir hostName}/media_meta 0750 ${user} ${webserver.group} - -"
+      "d ${stateDir hostName}/meta 0750 ${user} ${webserver.group} - -"
+      "d ${stateDir hostName}/pages 0750 ${user} ${webserver.group} - -"
+      "d ${stateDir hostName}/tmp 0750 ${user} ${webserver.group} - -"
+    ] ++ lib.optional (cfg.aclFile != null) "C ${cfg.aclFile} 0640 ${user} ${webserver.group} - ${pkg hostName cfg}/share/dokuwiki/conf/acl.auth.php.dist"
+    ++ lib.optional (cfg.usersFile != null) "C ${cfg.usersFile} 0640 ${user} ${webserver.group} - ${pkg hostName cfg}/share/dokuwiki/conf/users.auth.php.dist"
+    ) eachSite);
 
-        locations."/" = {
-          priority = 1;
-          index = "doku.php";
-          extraConfig = "try_files $uri $uri/ @dokuwiki;";
-        };
+    users.users.${user} = {
+      group = webserver.group;
+      isSystemUser = true;
+    };
+  }
 
-        locations."@dokuwiki" = {
-          extraConfig = ''
+  (mkIf (cfg.webserver == "nginx") {
+    services.nginx = {
+      enable = true;
+      virtualHosts = mapAttrs (hostName: cfg: {
+        serverName = mkDefault hostName;
+        root = "${pkg hostName cfg}/share/dokuwiki";
+
+        locations = {
+          "~ /(conf/|bin/|inc/|install.php)" = {
+            extraConfig = "deny all;";
+          };
+
+          "~ ^/data/" = {
+            root = "${stateDir hostName}";
+            extraConfig = "internal;";
+          };
+
+          "~ ^/lib.*\.(js|css|gif|png|ico|jpg|jpeg)$" = {
+            extraConfig = "expires 365d;";
+          };
+
+          "/" = {
+            priority = 1;
+            index = "doku.php";
+            extraConfig = ''try_files $uri $uri/ @dokuwiki;'';
+          };
+
+          "@dokuwiki" = {
+            extraConfig = ''
               # rewrites "doku.php/" out of the URLs if you set the userwrite setting to .htaccess in dokuwiki config page
               rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
               rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
               rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
               rewrite ^/(.*) /doku.php?id=$1&$args last;
-          '';
-        };
+            '';
+          };
 
-        locations."~ \\.php$" = {
-          extraConfig = ''
+          "~ \\.php$" = {
+            extraConfig = ''
               try_files $uri $uri/ /doku.php;
               include ${pkgs.nginx}/conf/fastcgi_params;
               fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
               fastcgi_param REDIRECT_STATUS 200;
               fastcgi_pass unix:${config.services.phpfpm.pools."dokuwiki-${hostName}".socket};
-              ${lib.optionalString (cfg.nginx.addSSL || cfg.nginx.forceSSL || cfg.nginx.onlySSL || cfg.nginx.enableACME) "fastcgi_param HTTPS on;"}
-          '';
+              '';
+          };
+
         };
-      }]) eachSite;
+      }) eachSite;
     };
+  })
 
-    systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [
-      "d ${cfg.stateDir}/attic 0750 ${user} ${group} - -"
-      "d ${cfg.stateDir}/cache 0750 ${user} ${group} - -"
-      "d ${cfg.stateDir}/index 0750 ${user} ${group} - -"
-      "d ${cfg.stateDir}/locks 0750 ${user} ${group} - -"
-      "d ${cfg.stateDir}/media 0750 ${user} ${group} - -"
-      "d ${cfg.stateDir}/media_attic 0750 ${user} ${group} - -"
-      "d ${cfg.stateDir}/media_meta 0750 ${user} ${group} - -"
-      "d ${cfg.stateDir}/meta 0750 ${user} ${group} - -"
-      "d ${cfg.stateDir}/pages 0750 ${user} ${group} - -"
-      "d ${cfg.stateDir}/tmp 0750 ${user} ${group} - -"
-    ] ++ lib.optional (cfg.aclFile != null) "C ${cfg.aclFile} 0640 ${user} ${group} - ${pkg hostName cfg}/share/dokuwiki/conf/acl.auth.php.dist"
-    ++ lib.optional (cfg.usersFile != null) "C ${cfg.usersFile} 0640 ${user} ${group} - ${pkg hostName cfg}/share/dokuwiki/conf/users.auth.php.dist"
-    ) eachSite);
+  (mkIf (cfg.webserver == "caddy") {
+    services.caddy = {
+      enable = true;
+      virtualHosts = mapAttrs' (hostName: cfg: (
+        nameValuePair "http://${hostName}" {
+          extraConfig = ''
+            root * ${pkg hostName cfg}/share/dokuwiki
+            file_server
 
-    users.users.${user} = {
-      group = group;
-      isSystemUser = true;
+            encode zstd gzip
+            php_fastcgi unix/${config.services.phpfpm.pools."dokuwiki-${hostName}".socket}
+
+            @restrict_files {
+              path /data/* /conf/* /bin/* /inc/* /vendor/* /install.php
+            }
+
+            respond @restrict_files 404
+
+            @allow_media {
+              path_regexp path ^/_media/(.*)$
+            }
+            rewrite @allow_media /lib/exe/fetch.php?media=/{http.regexp.path.1}
+
+            @allow_detail   {
+              path /_detail*
+            }
+            rewrite @allow_detail /lib/exe/detail.php?media={path}
+
+            @allow_export   {
+              path /_export*
+              path_regexp export /([^/]+)/(.*)
+            }
+            rewrite @allow_export /doku.php?do=export_{http.regexp.export.1}&id={http.regexp.export.2}
+
+            try_files {path} {path}/ /doku.php?id={path}&{query}
+          '';
+        }
+      )) eachSite;
     };
-  };
+  })
 
-  meta.maintainers = with maintainers; [ _1000101 ];
+  ]);
 
+  meta.maintainers = with maintainers; [
+    _1000101
+    onny
+  ];
 }
diff --git a/nixpkgs/nixos/modules/services/web-apps/mastodon.nix b/nixpkgs/nixos/modules/services/web-apps/mastodon.nix
index 5e24bd06ffdb..5bda7d5a5dd2 100644
--- a/nixpkgs/nixos/modules/services/web-apps/mastodon.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/mastodon.nix
@@ -9,6 +9,13 @@ let
     RAILS_ENV = "production";
     NODE_ENV = "production";
 
+    # mastodon-web concurrency.
+    WEB_CONCURRENCY = toString cfg.webProcesses;
+    MAX_THREADS = toString cfg.webThreads;
+
+    # mastodon-streaming concurrency.
+    STREAMING_CLUSTER_NUM = toString cfg.streamingProcesses;
+
     DB_USER = cfg.database.user;
 
     REDIS_HOST = cfg.redis.host;
@@ -146,18 +153,41 @@ in {
         type = lib.types.port;
         default = 55000;
       };
+      streamingProcesses = lib.mkOption {
+        description = ''
+          Processes used by the mastodon-streaming service.
+          Defaults to the number of CPU cores minus one.
+        '';
+        type = lib.types.nullOr lib.types.int;
+        default = null;
+      };
 
       webPort = lib.mkOption {
         description = "TCP port used by the mastodon-web service.";
         type = lib.types.port;
         default = 55001;
       };
+      webProcesses = lib.mkOption {
+        description = "Processes used by the mastodon-web service.";
+        type = lib.types.int;
+        default = 2;
+      };
+      webThreads = lib.mkOption {
+        description = "Threads per process used by the mastodon-web service.";
+        type = lib.types.int;
+        default = 5;
+      };
 
       sidekiqPort = lib.mkOption {
-        description = "TCP port used by the mastodon-sidekiq service";
+        description = "TCP port used by the mastodon-sidekiq service.";
         type = lib.types.port;
         default = 55002;
       };
+      sidekiqThreads = lib.mkOption {
+        description = "Worker threads used by the mastodon-sidekiq service.";
+        type = lib.types.int;
+        default = 25;
+      };
 
       vapidPublicKeyFile = lib.mkOption {
         description = ''
@@ -524,9 +554,10 @@ in {
       wantedBy = [ "multi-user.target" ];
       environment = env // {
         PORT = toString(cfg.sidekiqPort);
+        DB_POOL = toString cfg.sidekiqThreads;
       };
       serviceConfig = {
-        ExecStart = "${cfg.package}/bin/sidekiq -c 25 -r ${cfg.package}";
+        ExecStart = "${cfg.package}/bin/sidekiq -c ${toString cfg.sidekiqThreads} -r ${cfg.package}";
         Restart = "always";
         RestartSec = 20;
         EnvironmentFile = "/var/lib/mastodon/.secrets_env";
diff --git a/nixpkgs/nixos/modules/services/web-apps/node-red.nix b/nixpkgs/nixos/modules/services/web-apps/node-red.nix
index 4f6850ace214..400790576d67 100644
--- a/nixpkgs/nixos/modules/services/web-apps/node-red.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/node-red.nix
@@ -114,6 +114,7 @@ in
     users.users = optionalAttrs (cfg.user == defaultUser) {
       ${defaultUser} = {
         isSystemUser = true;
+        group = defaultUser;
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/web-apps/wordpress.nix b/nixpkgs/nixos/modules/services/web-apps/wordpress.nix
index 6f1ef815bc46..eb91256045cc 100644
--- a/nixpkgs/nixos/modules/services/web-apps/wordpress.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/wordpress.nix
@@ -278,7 +278,7 @@ in
         };
 
         options.webserver = mkOption {
-          type = types.enum [ "httpd" "nginx" ];
+          type = types.enum [ "httpd" "nginx" "caddy" ];
           default = "httpd";
           description = ''
             Whether to use apache2 or nginx for virtual host management.
@@ -458,5 +458,32 @@ in
     };
   })
 
+  (mkIf (cfg.webserver == "caddy") {
+    services.caddy = {
+      enable = true;
+      virtualHosts = mapAttrs' (hostName: cfg: (
+        nameValuePair "http://${hostName}" {
+          extraConfig = ''
+            root    * /${pkg hostName cfg}/share/wordpress
+            file_server
+
+            php_fastcgi unix/${config.services.phpfpm.pools."wordpress-${hostName}".socket}
+
+            @uploads {
+              path_regexp path /uploads\/(.*)\.php
+            }
+            rewrite @uploads /
+
+            @wp-admin {
+              path  not ^\/wp-admin/*
+            }
+            rewrite @wp-admin {path}/index.php?{query}
+          '';
+        }
+      )) eachSite;
+    };
+  })
+
+
   ]);
 }
diff --git a/nixpkgs/nixos/modules/services/web-servers/trafficserver.nix b/nixpkgs/nixos/modules/services/web-servers/trafficserver/default.nix
index db0e2ac0bd05..341e8b13976a 100644
--- a/nixpkgs/nixos/modules/services/web-servers/trafficserver.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/trafficserver/default.nix
@@ -8,21 +8,9 @@ let
   group = config.users.groups.trafficserver.name;
 
   getManualUrl = name: "https://docs.trafficserver.apache.org/en/latest/admin-guide/files/${name}.en.html";
-  getConfPath = name: "${pkgs.trafficserver}/etc/trafficserver/${name}";
 
   yaml = pkgs.formats.yaml { };
 
-  fromYAML = f:
-    let
-      jsonFile = pkgs.runCommand "in.json"
-        {
-          nativeBuildInputs = [ pkgs.remarshal ];
-        } ''
-        yaml2json < "${f}" > "$out"
-      '';
-    in
-    builtins.fromJSON (builtins.readFile jsonFile);
-
   mkYamlConf = name: cfg:
     if cfg != null then {
       "trafficserver/${name}.yaml".source = yaml.generate "${name}.yaml" cfg;
@@ -73,7 +61,7 @@ in
 
     ipAllow = mkOption {
       type = types.nullOr yaml.type;
-      default = fromYAML (getConfPath "ip_allow.yaml");
+      default = builtins.fromJSON (builtins.readFile ./ip_allow.json);
       defaultText = "upstream defaults";
       example = literalExample {
         ip_allow = [{
@@ -94,7 +82,7 @@ in
 
     logging = mkOption {
       type = types.nullOr yaml.type;
-      default = fromYAML (getConfPath "logging.yaml");
+      default = builtins.fromJSON (builtins.readFile ./logging.json);
       defaultText = "upstream defaults";
       example = literalExample { };
       description = ''
diff --git a/nixpkgs/nixos/modules/services/web-servers/trafficserver/ip_allow.json b/nixpkgs/nixos/modules/services/web-servers/trafficserver/ip_allow.json
new file mode 100644
index 000000000000..fc2db8037286
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-servers/trafficserver/ip_allow.json
@@ -0,0 +1,36 @@
+{
+  "ip_allow": [
+    {
+      "apply": "in",
+      "ip_addrs": "127.0.0.1",
+      "action": "allow",
+      "methods": "ALL"
+    },
+    {
+      "apply": "in",
+      "ip_addrs": "::1",
+      "action": "allow",
+      "methods": "ALL"
+    },
+    {
+      "apply": "in",
+      "ip_addrs": "0/0",
+      "action": "deny",
+      "methods": [
+        "PURGE",
+        "PUSH",
+        "DELETE"
+      ]
+    },
+    {
+      "apply": "in",
+      "ip_addrs": "::/0",
+      "action": "deny",
+      "methods": [
+        "PURGE",
+        "PUSH",
+        "DELETE"
+      ]
+    }
+  ]
+}
diff --git a/nixpkgs/nixos/modules/services/web-servers/trafficserver/logging.json b/nixpkgs/nixos/modules/services/web-servers/trafficserver/logging.json
new file mode 100644
index 000000000000..81e7ba0186c6
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-servers/trafficserver/logging.json
@@ -0,0 +1,37 @@
+{
+  "logging": {
+    "formats": [
+      {
+        "name": "welf",
+        "format": "id=firewall time=\"%<cqtd> %<cqtt>\" fw=%<phn> pri=6 proto=%<cqus> duration=%<ttmsf> sent=%<psql> rcvd=%<cqhl> src=%<chi> dst=%<shi> dstname=%<shn> user=%<caun> op=%<cqhm> arg=\"%<cqup>\" result=%<pssc> ref=\"%<{Referer}cqh>\" agent=\"%<{user-agent}cqh>\" cache=%<crc>"
+      },
+      {
+        "name": "squid_seconds_only_timestamp",
+        "format": "%<cqts> %<ttms> %<chi> %<crc>/%<pssc> %<psql> %<cqhm> %<cquc> %<caun> %<phr>/%<shn> %<psct>"
+      },
+      {
+        "name": "squid",
+        "format": "%<cqtq> %<ttms> %<chi> %<crc>/%<pssc> %<psql> %<cqhm> %<cquc> %<caun> %<phr>/%<shn> %<psct>"
+      },
+      {
+        "name": "common",
+        "format": "%<chi> - %<caun> [%<cqtn>] \"%<cqtx>\" %<pssc> %<pscl>"
+      },
+      {
+        "name": "extended",
+        "format": "%<chi> - %<caun> [%<cqtn>] \"%<cqtx>\" %<pssc> %<pscl> %<sssc> %<sscl> %<cqcl> %<pqcl> %<cqhl> %<pshl> %<pqhl> %<sshl> %<tts>"
+      },
+      {
+        "name": "extended2",
+        "format": "%<chi> - %<caun> [%<cqtn>] \"%<cqtx>\" %<pssc> %<pscl> %<sssc> %<sscl> %<cqcl> %<pqcl> %<cqhl> %<pshl> %<pqhl> %<sshl> %<tts> %<phr> %<cfsc> %<pfsc> %<crc>"
+      }
+    ],
+    "logs": [
+      {
+        "filename": "squid",
+        "format": "squid",
+        "mode": "binary"
+      }
+    ]
+  }
+}
diff --git a/nixpkgs/nixos/modules/services/web-servers/zope2.nix b/nixpkgs/nixos/modules/services/web-servers/zope2.nix
index 3abd506827c0..ab12e87502eb 100644
--- a/nixpkgs/nixos/modules/services/web-servers/zope2.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/zope2.nix
@@ -103,7 +103,11 @@ in
 
   config = mkIf (cfg.instances != {}) {
 
-    users.users.zope2.uid = config.ids.uids.zope2;
+    users.users.zope2 = {
+      isSystemUser = true;
+      group = "zope2";
+    };
+    users.groups.zope2 = {};
 
     systemd.services =
       let
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/cde.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/cde.nix
index 3f1575a0ca63..24ca82fca796 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/cde.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/cde.nix
@@ -49,9 +49,10 @@ in {
     users.groups.mail = {};
     security.wrappers = {
       dtmail = {
-        source = "${pkgs.cdesktopenv}/bin/dtmail";
-        group = "mail";
         setgid = true;
+        owner = "nobody";
+        group = "mail";
+        source = "${pkgs.cdesktopenv}/bin/dtmail";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/enlightenment.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/enlightenment.nix
index 3a7ab64510b5..e3d876e82fdd 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/enlightenment.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/enlightenment.nix
@@ -65,9 +65,24 @@ in
 
     # Wrappers for programs installed by enlightenment that should be setuid
     security.wrappers = {
-      enlightenment_ckpasswd.source = "${pkgs.enlightenment.enlightenment}/lib/enlightenment/utils/enlightenment_ckpasswd";
-      enlightenment_sys.source = "${pkgs.enlightenment.enlightenment}/lib/enlightenment/utils/enlightenment_sys";
-      enlightenment_system.source = "${pkgs.enlightenment.enlightenment}/lib/enlightenment/utils/enlightenment_system";
+      enlightenment_ckpasswd =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.enlightenment.enlightenment}/lib/enlightenment/utils/enlightenment_ckpasswd";
+        };
+      enlightenment_sys =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.enlightenment.enlightenment}/lib/enlightenment/utils/enlightenment_sys";
+        };
+      enlightenment_system =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.enlightenment.enlightenment}/lib/enlightenment/utils/enlightenment_system";
+        };
     };
 
     environment.etc."X11/xkb".source = xcfg.xkbDir;
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome.nix
index 4bc42525906c..9bb671adbecf 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome.nix
@@ -476,6 +476,8 @@ in
     (mkIf serviceCfg.experimental-features.realtime-scheduling {
       security.wrappers.".gnome-shell-wrapped" = {
         source = "${pkgs.gnome.gnome-shell}/bin/.gnome-shell-wrapped";
+        owner = "root";
+        group = "root";
         capabilities = "cap_sys_nice=ep";
       };
 
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix
index e492073b80ff..887d6c91e83b 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -18,7 +18,7 @@ in
 
   meta = {
     doc = ./pantheon.xml;
-    maintainers = pkgs.pantheon.maintainers;
+    maintainers = teams.pantheon.members;
   };
 
   options = {
@@ -134,6 +134,9 @@ in
       services.accounts-daemon.enable = true;
       services.bamf.enable = true;
       services.colord.enable = mkDefault true;
+      services.fwupd.enable = mkDefault true;
+      services.touchegg.enable = mkDefault true;
+      services.touchegg.package = pkgs.pantheon.touchegg;
       services.tumbler.enable = mkDefault true;
       services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
       services.dbus.packages = with pkgs.pantheon; [
@@ -162,12 +165,11 @@ in
         isAllowed = true;
         isSystem = true;
       };
-      # Use gnome-settings-daemon fork
       services.udev.packages = [
-        pkgs.pantheon.elementary-settings-daemon
+        pkgs.gnome.gnome-settings-daemon338
       ];
       systemd.packages = [
-        pkgs.pantheon.elementary-settings-daemon
+        pkgs.gnome.gnome-settings-daemon338
       ];
       programs.dconf.enable = true;
       networking.networkmanager.enable = mkDefault true;
@@ -180,7 +182,6 @@ in
         gnome.adwaita-icon-theme
         gtk3.out
         hicolor-icon-theme
-        lightlocker
         onboard
         qgnomeplatform
         shared-mime-info
@@ -208,15 +209,13 @@ in
 
         # Services
         elementary-capnet-assist
-        elementary-dpms-helper
         elementary-notifications
         elementary-settings-daemon
         pantheon-agent-geoclue2
         pantheon-agent-polkit
       ]) ++ (gnome.removePackagesByName [
-        gnome.geary
-        gnome.epiphany
         gnome.gnome-font-viewer
+        gnome.gnome-settings-daemon338
       ] config.environment.pantheon.excludePackages);
 
       programs.evince.enable = mkDefault true;
@@ -224,9 +223,12 @@ in
 
       # Settings from elementary-default-settings
       environment.sessionVariables.GTK_CSD = "1";
-      environment.sessionVariables.GTK3_MODULES = [ "pantheon-filechooser-module" ];
       environment.etc."gtk-3.0/settings.ini".source = "${pkgs.pantheon.elementary-default-settings}/etc/gtk-3.0/settings.ini";
 
+      xdg.portal.extraPortals = [
+        pkgs.pantheon.elementary-files
+      ];
+
       # Override GSettings schemas
       environment.sessionVariables.NIX_GSETTINGS_OVERRIDES_DIR = "${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
 
@@ -254,6 +256,8 @@ in
 
       # Default Fonts
       fonts.fonts = with pkgs; [
+        inter
+        open-dyslexic
         open-sans
         roboto-mono
       ];
@@ -271,14 +275,16 @@ in
         elementary-camera
         elementary-code
         elementary-files
+        elementary-mail
         elementary-music
         elementary-photos
-        elementary-screenshot-tool
+        elementary-screenshot
         elementary-terminal
         elementary-videos
+        epiphany
       ] config.environment.pantheon.excludePackages);
 
-      # needed by screenshot-tool
+      # needed by screenshot
       fonts.fonts = [
         pkgs.pantheon.elementary-redacted-script
       ];
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.xml b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.xml
index 7905ceebd9aa..fe0a1c496223 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.xml
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.xml
@@ -22,7 +22,7 @@
 <programlisting>
 <xref linkend="opt-services.pantheon.apps.enable"/> = false;
 </programlisting>
-   You can also use <xref linkend="opt-environment.pantheon.excludePackages"/> to remove any other app (like <package>geary</package>).
+   You can also use <xref linkend="opt-environment.pantheon.excludePackages"/> to remove any other app (like <package>elementary-mail</package>).
   </para>
  </section>
  <section xml:id="sec-pantheon-wingpanel-switchboard">
@@ -105,8 +105,14 @@ switchboard-with-plugs.override {
     </term>
     <listitem>
      <para>
-      AppCenter has been available since 20.03, but it is of little use. This is because there is no functioning PackageKit backend for Nix 2.0. In the near future you will be able to install Flatpak applications from AppCenter on NixOS. See this <link xlink:href="https://github.com/NixOS/nixpkgs/issues/70214">issue</link>.
+      AppCenter has been available since 20.03, but it is of little use. This is because there is no functioning PackageKit backend for Nix 2.0. Starting from 21.11, the Flatpak backend should work so you can install some Flatpak applications using it. See this <link xlink:href="https://github.com/NixOS/nixpkgs/issues/70214">issue</link>.
      </para>
+     <para>
+      To use AppCenter on NixOS, add <literal>pantheon.appcenter</literal> to <xref linkend="opt-environment.systemPackages" />, <link linkend="module-services-flatpak">enable Flatpak support</link> and optionally add the <literal>appcenter</literal> Flatpak remote:
+     </para>
+<screen>
+<prompt>$ </prompt>flatpak remote-add --if-not-exists appcenter https://flatpak.elementary.io/repo.flatpakrepo
+</screen>
     </listitem>
    </varlistentry>
   </variablelist>
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
index aac905fea437..d8dc2675f068 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -197,12 +197,24 @@ in
       };
 
       security.wrappers = {
-        kcheckpass.source = "${lib.getBin libsForQt5.kscreenlocker}/libexec/kcheckpass";
-        start_kdeinit.source = "${lib.getBin libsForQt5.kinit}/libexec/kf5/start_kdeinit";
-        kwin_wayland = {
-          source = "${lib.getBin plasma5.kwin}/bin/kwin_wayland";
-          capabilities = "cap_sys_nice+ep";
-        };
+        kcheckpass =
+          { setuid = true;
+            owner = "root";
+            group = "root";
+            source = "${lib.getBin libsForQt5.kscreenlocker}/libexec/kcheckpass";
+          };
+        start_kdeinit =
+          { setuid = true;
+            owner = "root";
+            group = "root";
+            source = "${lib.getBin libsForQt5.kinit}/libexec/kf5/start_kdeinit";
+          };
+        kwin_wayland =
+          { owner = "root";
+            group = "root";
+            capabilities = "cap_sys_nice+ep";
+            source = "${lib.getBin plasma5.kwin}/bin/kwin_wayland";
+          };
       };
 
       # DDC support
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
index 5c4c6c67fd02..3df576038a9f 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
@@ -174,9 +174,6 @@ in
       "systemd-machined.service"
       # setSessionScript wants AccountsService
       "accounts-daemon.service"
-      # Failed to open gpu '/dev/dri/card0': GDBus.Error:org.freedesktop.DBus.Error.AccessDenied: Operation not permitted
-      # https://github.com/NixOS/nixpkgs/pull/25311#issuecomment-609417621
-      "systemd-udev-settle.service"
     ];
 
     systemd.services.display-manager.after = [
@@ -186,7 +183,6 @@ in
       "getty@tty${gdm.initialVT}.service"
       "plymouth-quit.service"
       "plymouth-start.service"
-      "systemd-udev-settle.service"
     ];
     systemd.services.display-manager.conflicts = [
       "getty@tty${gdm.initialVT}.service"
diff --git a/nixpkgs/nixos/modules/services/x11/extra-layouts.nix b/nixpkgs/nixos/modules/services/x11/extra-layouts.nix
index 0e2edc6a5309..b1c4e04975f9 100644
--- a/nixpkgs/nixos/modules/services/x11/extra-layouts.nix
+++ b/nixpkgs/nixos/modules/services/x11/extra-layouts.nix
@@ -79,6 +79,10 @@ let
     };
   };
 
+  xkb_patched = pkgs.xorg.xkeyboardconfig_custom {
+    layouts = config.services.xserver.extraLayouts;
+  };
+
 in
 
 {
@@ -114,58 +118,14 @@ in
 
   config = mkIf (layouts != { }) {
 
-    # We don't override xkeyboard_config directly to
-    # reduce the amount of packages to be recompiled.
-    # Only the following packages are necessary to set
-    # a custom layout anyway:
-    nixpkgs.overlays = lib.singleton (self: super: {
-
-      xkb_patched = self.xorg.xkeyboardconfig_custom {
-        layouts = config.services.xserver.extraLayouts;
-      };
-
-      xorg = super.xorg // {
-        xorgserver = super.xorg.xorgserver.overrideAttrs (old: {
-          configureFlags = old.configureFlags ++ [
-            "--with-xkb-bin-directory=${self.xorg.xkbcomp}/bin"
-            "--with-xkb-path=${self.xkb_patched}/share/X11/xkb"
-          ];
-        });
-
-        setxkbmap = super.xorg.setxkbmap.overrideAttrs (old: {
-          postInstall =
-            ''
-              mkdir -p $out/share
-              ln -sfn ${self.xkb_patched}/etc/X11 $out/share/X11
-            '';
-        });
-
-        xkbcomp = super.xorg.xkbcomp.overrideAttrs (old: {
-          configureFlags = [ "--with-xkb-config-root=${self.xkb_patched}/share/X11/xkb" ];
-        });
-
-      };
-
-      ckbcomp = super.ckbcomp.override {
-        xkeyboard_config = self.xkb_patched;
-      };
-
-      xkbvalidate = super.xkbvalidate.override {
-        libxkbcommon = self.libxkbcommon.override {
-          xkeyboard_config = self.xkb_patched;
-        };
-      };
-
-    });
-
     environment.sessionVariables = {
       # runtime override supported by multiple libraries e. g. libxkbcommon
       # https://xkbcommon.org/doc/current/group__include-path.html
-      XKB_CONFIG_ROOT = "${pkgs.xkb_patched}/etc/X11/xkb";
+      XKB_CONFIG_ROOT = "${xkb_patched}/etc/X11/xkb";
     };
 
     services.xserver = {
-      xkbDir = "${pkgs.xkb_patched}/etc/X11/xkb";
+      xkbDir = "${xkb_patched}/etc/X11/xkb";
       exportConfiguration = config.services.xserver.displayManager.startx.enable
         || config.services.xserver.displayManager.sx.enable;
     };
diff --git a/nixpkgs/nixos/modules/services/x11/hardware/libinput.nix b/nixpkgs/nixos/modules/services/x11/hardware/libinput.nix
index 439708bc47ed..e2fb7d0918e3 100644
--- a/nixpkgs/nixos/modules/services/x11/hardware/libinput.nix
+++ b/nixpkgs/nixos/modules/services/x11/hardware/libinput.nix
@@ -163,6 +163,15 @@ let cfg = config.services.xserver.libinput;
           '';
       };
 
+      transformationMatrix = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          A  string  of  9 space-separated floating point numbers.  Sets the transformation matrix to
+          the 3x3 matrix where the first row is (abc), the second row is (def) and the third row is (ghi).
+        '';
+      };
+
       disableWhileTyping = mkOption {
         type = types.bool;
         default = false;
@@ -196,6 +205,7 @@ let cfg = config.services.xserver.libinput;
       ${optionalString (cfg.${deviceType}.accelSpeed != null) ''Option "AccelSpeed" "${cfg.${deviceType}.accelSpeed}"''}
       ${optionalString (cfg.${deviceType}.buttonMapping != null) ''Option "ButtonMapping" "${cfg.${deviceType}.buttonMapping}"''}
       ${optionalString (cfg.${deviceType}.calibrationMatrix != null) ''Option "CalibrationMatrix" "${cfg.${deviceType}.calibrationMatrix}"''}
+      ${optionalString (cfg.${deviceType}.transformationMatrix != null) ''Option "TransformationMatrix" "${cfg.${deviceType}.transformationMatrix}"''}
       ${optionalString (cfg.${deviceType}.clickMethod != null) ''Option "ClickMethod" "${cfg.${deviceType}.clickMethod}"''}
       Option "LeftHanded" "${xorgBool cfg.${deviceType}.leftHanded}"
       Option "MiddleEmulation" "${xorgBool cfg.${deviceType}.middleEmulation}"
@@ -227,6 +237,7 @@ in {
       "sendEventsMode"
       "tapping"
       "tappingDragLock"
+      "transformationMatrix"
       "disableWhileTyping"
       "additionalOptions"
     ]);
diff --git a/nixpkgs/nixos/modules/services/x11/touchegg.nix b/nixpkgs/nixos/modules/services/x11/touchegg.nix
new file mode 100644
index 000000000000..fab7fac3f017
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/x11/touchegg.nix
@@ -0,0 +1,38 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let cfg = config.services.touchegg;
+
+in {
+  meta = {
+    maintainers = teams.pantheon.members;
+  };
+
+  ###### interface
+  options.services.touchegg = {
+    enable = mkEnableOption "touchegg, a multi-touch gesture recognizer";
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.touchegg;
+      defaultText = "pkgs.touchegg";
+      description = "touchegg derivation to use.";
+    };
+  };
+
+  ###### implementation
+  config = mkIf cfg.enable {
+    systemd.services.touchegg = {
+      description = "Touchegg Daemon";
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = "${cfg.package}/bin/touchegg --daemon";
+        Restart = "on-failure";
+      };
+      wantedBy = [ "multi-user.target" ];
+    };
+
+    environment.systemPackages = [ cfg.package ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/x11/xserver.nix b/nixpkgs/nixos/modules/services/x11/xserver.nix
index ad9bd88f98aa..ee190ac3cc44 100644
--- a/nixpkgs/nixos/modules/services/x11/xserver.nix
+++ b/nixpkgs/nixos/modules/services/x11/xserver.nix
@@ -738,6 +738,9 @@ in
       nativeBuildInputs = with pkgs.buildPackages; [ xkbvalidate ];
       preferLocalBuild = true;
     } ''
+      ${optionalString (config.environment.sessionVariables ? XKB_CONFIG_ROOT)
+        "export XKB_CONFIG_ROOT=${config.environment.sessionVariables.XKB_CONFIG_ROOT}"
+      }
       xkbvalidate "$xkbModel" "$layout" "$xkbVariant" "$xkbOptions"
       touch "$out"
     '');
diff --git a/nixpkgs/nixos/modules/system/activation/activation-script.nix b/nixpkgs/nixos/modules/system/activation/activation-script.nix
index 548b4de852b7..704fc15fe207 100644
--- a/nixpkgs/nixos/modules/system/activation/activation-script.nix
+++ b/nixpkgs/nixos/modules/system/activation/activation-script.nix
@@ -18,8 +18,17 @@ let
   });
 
   systemActivationScript = set: onlyDry: let
-    set' = filterAttrs (_: v: onlyDry -> v.supportsDryActivation) (mapAttrs (_: v: if isString v then (noDepEntry v) // { supportsDryActivation = false; } else v) set);
+    set' = mapAttrs (_: v: if isString v then (noDepEntry v) // { supportsDryActivation = false; } else v) set;
     withHeadlines = addAttributeName set';
+    # When building a dry activation script, this replaces all activation scripts
+    # that do not support dry mode with a comment that does nothing. Filtering these
+    # activation scripts out so they don't get generated into the dry activation script
+    # does not work because when an activation script that supports dry mode depends on
+    # an activation script that does not, the dependency cannot be resolved and the eval
+    # fails.
+    withDrySnippets = mapAttrs (a: v: if onlyDry && !v.supportsDryActivation then v // {
+      text = "#### Activation script snippet ${a} does not support dry activation.";
+    } else v) withHeadlines;
   in
     ''
       #!${pkgs.runtimeShell}
@@ -37,7 +46,7 @@ let
       # Ensure a consistent umask.
       umask 0022
 
-      ${textClosureMap id (withHeadlines) (attrNames withHeadlines)}
+      ${textClosureMap id (withDrySnippets) (attrNames withDrySnippets)}
 
     '' + optionalString (!onlyDry) ''
       # Make this configuration the current configuration.
@@ -254,6 +263,7 @@ in
         script = config.system.userActivationScripts.script;
         unitConfig.ConditionUser = "!@system";
         serviceConfig.Type = "oneshot";
+        wantedBy = [ "default.target" ];
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/system/activation/top-level.nix b/nixpkgs/nixos/modules/system/activation/top-level.nix
index 616e1422aa8c..dad9acba91af 100644
--- a/nixpkgs/nixos/modules/system/activation/top-level.nix
+++ b/nixpkgs/nixos/modules/system/activation/top-level.nix
@@ -61,8 +61,8 @@ let
       substituteInPlace $out/dry-activate --subst-var out
       chmod u+x $out/activate $out/dry-activate
       unset activationScript dryActivationScript
-      ${pkgs.runtimeShell} -n $out/activate
-      ${pkgs.runtimeShell} -n $out/dry-activate
+      ${pkgs.stdenv.shell} -n $out/activate
+      ${pkgs.stdenv.shell} -n $out/dry-activate
 
       cp ${config.system.build.bootStage2} $out/init
       substituteInPlace $out/init --subst-var-by systemConfig $out
diff --git a/nixpkgs/nixos/modules/system/boot/kernel.nix b/nixpkgs/nixos/modules/system/boot/kernel.nix
index 1a6a9d99d5bb..15a5fd236092 100644
--- a/nixpkgs/nixos/modules/system/boot/kernel.nix
+++ b/nixpkgs/nixos/modules/system/boot/kernel.nix
@@ -47,7 +47,7 @@ in
       # We don't want to evaluate all of linuxPackages for the manual
       # - some of it might not even evaluate correctly.
       defaultText = "pkgs.linuxPackages";
-      example = literalExample "pkgs.linuxPackages_2_6_25";
+      example = literalExample "pkgs.linuxKernel.packages.linux_5_10";
       description = ''
         This option allows you to override the Linux kernel used by
         NixOS.  Since things like external kernel module packages are
diff --git a/nixpkgs/nixos/modules/system/boot/networkd.nix b/nixpkgs/nixos/modules/system/boot/networkd.nix
index 1de58b3d2c4a..bf254be1341b 100644
--- a/nixpkgs/nixos/modules/system/boot/networkd.nix
+++ b/nixpkgs/nixos/modules/system/boot/networkd.nix
@@ -384,6 +384,7 @@ let
           "AllMulticast"
           "Unmanaged"
           "RequiredForOnline"
+          "ActivationPolicy"
         ])
         (assertMacAddress "MACAddress")
         (assertByteFormat "MTUBytes")
@@ -402,6 +403,14 @@ let
           "enslaved"
           "routable"
         ]))
+        (assertValueOneOf "ActivationPolicy" ([
+          "up"
+          "always-up"
+          "manual"
+          "always-down"
+          "down"
+          "bound"
+        ]))
       ];
 
       sectionNetwork = checkUnitConfig "Network" [
diff --git a/nixpkgs/nixos/modules/system/boot/systemd.nix b/nixpkgs/nixos/modules/system/boot/systemd.nix
index 644ee9d2e46a..f4413188187e 100644
--- a/nixpkgs/nixos/modules/system/boot/systemd.nix
+++ b/nixpkgs/nixos/modules/system/boot/systemd.nix
@@ -1056,10 +1056,20 @@ in
 
     services.dbus.enable = true;
 
-    users.users.systemd-coredump.uid = config.ids.uids.systemd-coredump;
-    users.users.systemd-network.uid = config.ids.uids.systemd-network;
+    users.users.systemd-coredump = {
+      uid = config.ids.uids.systemd-coredump;
+      group = "systemd-coredump";
+    };
+    users.groups.systemd-coredump = {};
+    users.users.systemd-network = {
+      uid = config.ids.uids.systemd-network;
+      group = "systemd-network";
+    };
     users.groups.systemd-network.gid = config.ids.gids.systemd-network;
-    users.users.systemd-resolve.uid = config.ids.uids.systemd-resolve;
+    users.users.systemd-resolve = {
+      uid = config.ids.uids.systemd-resolve;
+      group = "systemd-resolve";
+    };
     users.groups.systemd-resolve.gid = config.ids.gids.systemd-resolve;
 
     # Target for ‘charon send-keys’ to hook into.
diff --git a/nixpkgs/nixos/modules/system/boot/tmp.nix b/nixpkgs/nixos/modules/system/boot/tmp.nix
index 5bb299adb15f..6edafd6695b6 100644
--- a/nixpkgs/nixos/modules/system/boot/tmp.nix
+++ b/nixpkgs/nixos/modules/system/boot/tmp.nix
@@ -2,6 +2,9 @@
 
 with lib;
 
+let
+  cfg = config.boot;
+in
 {
 
   ###### interface
@@ -24,18 +27,28 @@ with lib;
       '';
     };
 
+    boot.tmpOnTmpfsSize = mkOption {
+      type = types.oneOf [ types.str types.types.ints.positive ];
+      default = "50%";
+      description = ''
+        Size of tmpfs in percentage.
+        Percentage is defined by systemd.
+      '';
+    };
+
   };
 
   ###### implementation
 
   config = {
 
-    systemd.mounts = mkIf config.boot.tmpOnTmpfs [
+    # When changing remember to update /tmp mount in virtualisation/qemu-vm.nix
+    systemd.mounts = mkIf cfg.tmpOnTmpfs [
       {
         what = "tmpfs";
         where = "/tmp";
         type = "tmpfs";
-        mountConfig.Options = [ "mode=1777" "strictatime" "rw" "nosuid" "nodev" "size=50%" ];
+        mountConfig.Options = [ "mode=1777" "strictatime" "rw" "nosuid" "nodev" "size=${toString cfg.tmpOnTmpfsSize}" ];
       }
     ];
 
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/ecryptfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/ecryptfs.nix
index 12a407cabbfb..8138e6591610 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems/ecryptfs.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems/ecryptfs.nix
@@ -7,8 +7,18 @@ with lib;
   config = mkIf (any (fs: fs == "ecryptfs") config.boot.supportedFilesystems) {
     system.fsPackages = [ pkgs.ecryptfs ];
     security.wrappers = {
-      "mount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/mount.ecryptfs_private";
-      "umount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/umount.ecryptfs_private";
+      "mount.ecryptfs_private" =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.ecryptfs.out}/bin/mount.ecryptfs_private";
+        };
+      "umount.ecryptfs_private" =
+        { setuid = true;
+          owner = "root";
+          group = "root";
+          source = "${pkgs.ecryptfs.out}/bin/umount.ecryptfs_private";
+        };
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/tasks/network-interfaces.nix b/nixpkgs/nixos/modules/tasks/network-interfaces.nix
index 8f9c66b01572..d934e3cf0224 100644
--- a/nixpkgs/nixos/modules/tasks/network-interfaces.nix
+++ b/nixpkgs/nixos/modules/tasks/network-interfaces.nix
@@ -1133,11 +1133,16 @@ in
     # kernel because we need the ambient capability
     security.wrappers = if (versionAtLeast (getVersion config.boot.kernelPackages.kernel) "4.3") then {
       ping = {
-        source  = "${pkgs.iputils.out}/bin/ping";
+        owner = "root";
+        group = "root";
         capabilities = "cap_net_raw+p";
+        source = "${pkgs.iputils.out}/bin/ping";
       };
     } else {
-      ping.source = "${pkgs.iputils.out}/bin/ping";
+      setuid = true;
+      owner = "root";
+      group = "root";
+      source = "${pkgs.iputils.out}/bin/ping";
     };
     security.apparmor.policies."bin.ping".profile = lib.mkIf config.security.apparmor.policies."bin.ping".enable (lib.mkAfter ''
       /run/wrappers/bin/ping {
diff --git a/nixpkgs/nixos/modules/virtualisation/containerd.nix b/nixpkgs/nixos/modules/virtualisation/containerd.nix
index 43cb6273f253..898a66e7b04e 100644
--- a/nixpkgs/nixos/modules/virtualisation/containerd.nix
+++ b/nixpkgs/nixos/modules/virtualisation/containerd.nix
@@ -53,8 +53,11 @@ in
     virtualisation.containerd = {
       args.config = toString containerdConfigChecked;
       settings = {
-        plugins.cri.containerd.snapshotter = lib.mkIf config.boot.zfs.enabled "zfs";
-        plugins.cri.cni.bin_dir = lib.mkDefault "${pkgs.cni-plugins}/bin";
+        plugins."io.containerd.grpc.v1.cri" = {
+         containerd.snapshotter =
+           lib.mkIf config.boot.zfs.enabled (lib.mkOptionDefault "zfs");
+         cni.bin_dir = lib.mkOptionDefault "${pkgs.cni-plugins}/bin";
+        };
       };
     };
 
diff --git a/nixpkgs/nixos/modules/virtualisation/libvirtd.nix b/nixpkgs/nixos/modules/virtualisation/libvirtd.nix
index f45f1802d91c..3c291397a998 100644
--- a/nixpkgs/nixos/modules/virtualisation/libvirtd.nix
+++ b/nixpkgs/nixos/modules/virtualisation/libvirtd.nix
@@ -183,6 +183,9 @@ in {
     };
 
     security.wrappers.qemu-bridge-helper = {
+      setuid = true;
+      owner = "root";
+      group = "root";
       source = "/run/${dirName}/nix-helpers/qemu-bridge-helper";
     };
 
diff --git a/nixpkgs/nixos/modules/virtualisation/lxd.nix b/nixpkgs/nixos/modules/virtualisation/lxd.nix
index cde29f7bf59c..6732e244369f 100644
--- a/nixpkgs/nixos/modules/virtualisation/lxd.nix
+++ b/nixpkgs/nixos/modules/virtualisation/lxd.nix
@@ -158,7 +158,7 @@ in {
       };
     };
 
-    users.groups.lxd.gid = config.ids.gids.lxd;
+    users.groups.lxd = {};
 
     users.users.root = {
       subUidRanges = [ { startUid = 1000000; count = 65536; } ];
diff --git a/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix b/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
index d9935bcafb71..b51c29f83d6d 100644
--- a/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
@@ -686,7 +686,7 @@ in
             fsType = "tmpfs";
             neededForBoot = true;
             # Sync with systemd's tmp.mount;
-            options = [ "mode=1777" "strictatime" "nosuid" "nodev" ];
+            options = [ "mode=1777" "strictatime" "nosuid" "nodev" "size=${toString config.boot.tmpOnTmpfsSize}" ];
           };
         "/tmp/xchg" =
           { device = "xchg";
diff --git a/nixpkgs/nixos/modules/virtualisation/spice-usb-redirection.nix b/nixpkgs/nixos/modules/virtualisation/spice-usb-redirection.nix
index 4168cebe79b1..255327f2622c 100644
--- a/nixpkgs/nixos/modules/virtualisation/spice-usb-redirection.nix
+++ b/nixpkgs/nixos/modules/virtualisation/spice-usb-redirection.nix
@@ -14,9 +14,11 @@
 
   config = lib.mkIf config.virtualisation.spiceUSBRedirection.enable {
     environment.systemPackages = [ pkgs.spice-gtk ]; # For polkit actions
-    security.wrappers.spice-client-glib-usb-acl-helper ={
-      source = "${pkgs.spice-gtk}/bin/spice-client-glib-usb-acl-helper";
+    security.wrappers.spice-client-glib-usb-acl-helper = {
+      owner = "root";
+      group = "root";
       capabilities = "cap_fowner+ep";
+      source = "${pkgs.spice-gtk}/bin/spice-client-glib-usb-acl-helper";
     };
   };
 
diff --git a/nixpkgs/nixos/modules/virtualisation/vmware-guest.nix b/nixpkgs/nixos/modules/virtualisation/vmware-guest.nix
index 9465a8d6800d..7b25ffc440f8 100644
--- a/nixpkgs/nixos/modules/virtualisation/vmware-guest.nix
+++ b/nixpkgs/nixos/modules/virtualisation/vmware-guest.nix
@@ -37,6 +37,28 @@ in
         serviceConfig.ExecStart = "${open-vm-tools}/bin/vmtoolsd";
       };
 
+    # Mount the vmblock for drag-and-drop and copy-and-paste.
+    systemd.mounts = [
+      {
+        description = "VMware vmblock fuse mount";
+        documentation = [ "https://github.com/vmware/open-vm-tools/blob/master/open-vm-tools/vmblock-fuse/design.txt" ];
+        before = [ "vmware.service" ];
+        wants = [ "vmware.service" ];
+        what = "${open-vm-tools}/bin/vmware-vmblock-fuse";
+        where = "/run/vmblock-fuse";
+        type = "fuse";
+        options = "subtype=vmware-vmblock,default_permissions,allow_other";
+        wantedBy = [ "multi-user.target" ];
+      }
+    ];
+
+    security.wrappers.vmware-user-suid-wrapper =
+      { setuid = true;
+        owner = "root";
+        group = "root";
+        source = "${open-vm-tools}/bin/vmware-user-suid-wrapper";
+      };
+
     environment.etc.vmware-tools.source = "${open-vm-tools}/etc/vmware-tools/*";
 
     services.xserver = mkIf (!cfg.headless) {
diff --git a/nixpkgs/nixos/tests/all-tests.nix b/nixpkgs/nixos/tests/all-tests.nix
index 6baa986b2bda..3f19aa397a78 100644
--- a/nixpkgs/nixos/tests/all-tests.nix
+++ b/nixpkgs/nixos/tests/all-tests.nix
@@ -98,6 +98,7 @@ in
   deluge = handleTest ./deluge.nix {};
   dendrite = handleTest ./dendrite.nix {};
   dhparams = handleTest ./dhparams.nix {};
+  disable-installer-tools = handleTest ./disable-installer-tools.nix {};
   discourse = handleTest ./discourse.nix {};
   dnscrypt-proxy2 = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy2.nix {};
   dnscrypt-wrapper = handleTestOn ["x86_64-linux"] ./dnscrypt-wrapper {};
@@ -222,7 +223,6 @@ in
   krb5 = discoverTests (import ./krb5 {});
   ksm = handleTest ./ksm.nix {};
   kubernetes = handleTestOn ["x86_64-linux"] ./kubernetes {};
-  latestKernel.hardened = handleTest ./hardened.nix { latestKernel = true; };
   latestKernel.login = handleTest ./login.nix { latestKernel = true; };
   leaps = handleTest ./leaps.nix {};
   libreddit = handleTest ./libreddit.nix {};
@@ -249,6 +249,7 @@ in
   matrix-appservice-irc = handleTest ./matrix-appservice-irc.nix {};
   matrix-synapse = handleTest ./matrix-synapse.nix {};
   mediawiki = handleTest ./mediawiki.nix {};
+  meilisearch = handleTest ./meilisearch.nix {};
   memcached = handleTest ./memcached.nix {};
   metabase = handleTest ./metabase.nix {};
   minecraft = handleTest ./minecraft.nix {};
@@ -326,6 +327,7 @@ in
   openstack-image-metadata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).metadata or {};
   openstack-image-userdata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).userdata or {};
   opentabletdriver = handleTest ./opentabletdriver.nix {};
+  owncast = handleTest ./owncast.nix {};
   image-contents = handleTest ./image-contents.nix {};
   orangefs = handleTest ./orangefs.nix {};
   os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {};
@@ -336,6 +338,7 @@ in
   pam-u2f = handleTest ./pam-u2f.nix {};
   pantheon = handleTest ./pantheon.nix {};
   paperless-ng = handleTest ./paperless-ng.nix {};
+  parsedmarc = handleTest ./parsedmarc {};
   pdns-recursor = handleTest ./pdns-recursor.nix {};
   peerflix = handleTest ./peerflix.nix {};
   pgjwt = handleTest ./pgjwt.nix {};
@@ -385,7 +388,6 @@ in
   rspamd = handleTest ./rspamd.nix {};
   rss2email = handleTest ./rss2email.nix {};
   rsyslogd = handleTest ./rsyslogd.nix {};
-  runInMachine = handleTest ./run-in-machine.nix {};
   rxe = handleTest ./rxe.nix {};
   samba = handleTest ./samba.nix {};
   samba-wsdd = handleTest ./samba-wsdd.nix {};
@@ -460,6 +462,7 @@ in
   unit-php = handleTest ./web-servers/unit-php.nix {};
   upnp = handleTest ./upnp.nix {};
   usbguard = handleTest ./usbguard.nix {};
+  user-activation-scripts = handleTest ./user-activation-scripts.nix {};
   uwsgi = handleTest ./uwsgi.nix {};
   v2ray = handleTest ./v2ray.nix {};
   vault = handleTest ./vault.nix {};
diff --git a/nixpkgs/nixos/tests/atop.nix b/nixpkgs/nixos/tests/atop.nix
index 1f8b005041f0..f7a90346f3d7 100644
--- a/nixpkgs/nixos/tests/atop.nix
+++ b/nixpkgs/nixos/tests/atop.nix
@@ -105,8 +105,6 @@ let assertions = rec {
 };
 in
 {
-  name = "atop";
-
   justThePackage = makeTest {
     name = "atop-justThePackage";
     machine = {
diff --git a/nixpkgs/nixos/tests/cntr.nix b/nixpkgs/nixos/tests/cntr.nix
index 8cffd97459d0..668470756209 100644
--- a/nixpkgs/nixos/tests/cntr.nix
+++ b/nixpkgs/nixos/tests/cntr.nix
@@ -9,7 +9,7 @@ let
     makeTest {
       name = "cntr-${backend}";
 
-      meta = { maintainers = with lib.maintainers; [ srk mic92 ]; };
+      meta = { maintainers = with lib.maintainers; [ sorki mic92 ]; };
 
       nodes = {
         ${backend} = { pkgs, ... }: {
diff --git a/nixpkgs/nixos/tests/disable-installer-tools.nix b/nixpkgs/nixos/tests/disable-installer-tools.nix
new file mode 100644
index 000000000000..23c15faa8d33
--- /dev/null
+++ b/nixpkgs/nixos/tests/disable-installer-tools.nix
@@ -0,0 +1,29 @@
+import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... }:
+
+{
+  name = "disable-installer-tools";
+
+  machine =
+    { pkgs, lib, ... }:
+    {
+        system.disableInstallerTools = true;
+        boot.enableContainers = false;
+        environment.defaultPackages = [];
+    };
+
+  testScript = ''
+      machine.wait_for_unit("multi-user.target")
+      machine.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
+
+      with subtest("nixos installer tools should not be included"):
+          machine.fail("which nixos-rebuild")
+          machine.fail("which nixos-install")
+          machine.fail("which nixos-generate-config")
+          machine.fail("which nixos-enter")
+          machine.fail("which nixos-version")
+          machine.fail("which nixos-build-vms")
+
+      with subtest("perl should not be included"):
+          machine.fail("which perl")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/dokuwiki.nix b/nixpkgs/nixos/tests/dokuwiki.nix
index 2664e1500ea4..67657e89f74c 100644
--- a/nixpkgs/nixos/tests/dokuwiki.nix
+++ b/nixpkgs/nixos/tests/dokuwiki.nix
@@ -33,44 +33,79 @@ let
 in {
   name = "dokuwiki";
   meta = with pkgs.lib; {
-    maintainers = with maintainers; [ _1000101 ];
+    maintainers = with maintainers; [
+      _1000101
+      onny
+    ];
   };
-  machine = { ... }: {
-    services.dokuwiki."site1.local" = {
-      aclUse = false;
-      superUser = "admin";
+
+  nodes = {
+    dokuwiki_nginx = {...}: {
+      services.dokuwiki = {
+        sites = {
+          "site1.local" = {
+            aclUse = false;
+            superUser = "admin";
+          };
+          "site2.local" = {
+            usersFile = "/var/lib/dokuwiki/site2.local/users.auth.php";
+            superUser = "admin";
+            templates = [ template-bootstrap3 ];
+            plugins = [ plugin-icalevents ];
+          };
+        };
+      };
+
+      networking.firewall.allowedTCPPorts = [ 80 ];
+      networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
     };
-    services.dokuwiki."site2.local" = {
-      usersFile = "/var/lib/dokuwiki/site2.local/users.auth.php";
-      superUser = "admin";
-      templates = [ template-bootstrap3 ];
-      plugins = [ plugin-icalevents ];
+
+    dokuwiki_caddy = {...}: {
+      services.dokuwiki = {
+        webserver = "caddy";
+        sites = {
+          "site1.local" = {
+            aclUse = false;
+            superUser = "admin";
+          };
+          "site2.local" = {
+            usersFile = "/var/lib/dokuwiki/site2.local/users.auth.php";
+            superUser = "admin";
+            templates = [ template-bootstrap3 ];
+            plugins = [ plugin-icalevents ];
+          };
+        };
+      };
+
+      networking.firewall.allowedTCPPorts = [ 80 ];
+      networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
     };
-    networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
+
   };
 
   testScript = ''
-    site_names = ["site1.local", "site2.local"]
 
     start_all()
 
-    machine.wait_for_unit("phpfpm-dokuwiki-site1.local.service")
-    machine.wait_for_unit("phpfpm-dokuwiki-site2.local.service")
+    dokuwiki_nginx.wait_for_unit("nginx")
+    dokuwiki_caddy.wait_for_unit("caddy")
 
-    machine.wait_for_unit("nginx.service")
+    site_names = ["site1.local", "site2.local"]
 
-    machine.wait_for_open_port(80)
+    for machine in (dokuwiki_nginx, dokuwiki_caddy):
+      for site_name in site_names:
+        machine.wait_for_unit(f"phpfpm-dokuwiki-{site_name}")
 
-    machine.succeed("curl -sSfL http://site1.local/ | grep 'DokuWiki'")
-    machine.fail("curl -sSfL 'http://site1.local/doku.php?do=login' | grep 'Login'")
+        machine.succeed("curl -sSfL http://site1.local/ | grep 'DokuWiki'")
+        machine.fail("curl -sSfL 'http://site1.local/doku.php?do=login' | grep 'Login'")
 
-    machine.succeed("curl -sSfL http://site2.local/ | grep 'DokuWiki'")
-    machine.succeed("curl -sSfL 'http://site2.local/doku.php?do=login' | grep 'Login'")
+        machine.succeed("curl -sSfL http://site2.local/ | grep 'DokuWiki'")
+        machine.succeed("curl -sSfL 'http://site2.local/doku.php?do=login' | grep 'Login'")
 
-    machine.succeed(
-        "echo 'admin:$2y$10$ijdBQMzSVV20SrKtCna8gue36vnsbVm2wItAXvdm876sshI4uwy6S:Admin:admin@example.test:user' >> /var/lib/dokuwiki/site2.local/users.auth.php",
-        "curl -sSfL -d 'u=admin&p=password' --cookie-jar cjar 'http://site2.local/doku.php?do=login'",
-        "curl -sSfL --cookie cjar --cookie-jar cjar 'http://site2.local/doku.php?do=login' | grep 'Logged in as: <bdi>Admin</bdi>'",
-    )
+        machine.succeed(
+            "echo 'admin:$2y$10$ijdBQMzSVV20SrKtCna8gue36vnsbVm2wItAXvdm876sshI4uwy6S:Admin:admin@example.test:user' >> /var/lib/dokuwiki/site2.local/users.auth.php",
+            "curl -sSfL -d 'u=admin&p=password' --cookie-jar cjar 'http://site2.local/doku.php?do=login'",
+            "curl -sSfL --cookie cjar --cookie-jar cjar 'http://site2.local/doku.php?do=login' | grep 'Logged in as: <bdi>Admin</bdi>'",
+        )
   '';
 })
diff --git a/nixpkgs/nixos/tests/ec2.nix b/nixpkgs/nixos/tests/ec2.nix
index df0672480168..aa3c2b7051f6 100644
--- a/nixpkgs/nixos/tests/ec2.nix
+++ b/nixpkgs/nixos/tests/ec2.nix
@@ -24,6 +24,11 @@ let
           ln -s vda1 /dev/xvda1
         '';
 
+        # In a NixOS test the serial console is occupied by the "backdoor"
+        # (see testing/test-instrumentation.nix) and is incompatible with
+        # the configuration in virtualisation/amazon-image.nix.
+        systemd.services."serial-getty@ttyS0".enable = mkForce false;
+
         # Needed by nixos-rebuild due to the lack of network
         # access. Determined by trial and error.
         system.extraDependencies = with pkgs; ( [
diff --git a/nixpkgs/nixos/tests/enlightenment.nix b/nixpkgs/nixos/tests/enlightenment.nix
index cc1da649d493..4623574ce92e 100644
--- a/nixpkgs/nixos/tests/enlightenment.nix
+++ b/nixpkgs/nixos/tests/enlightenment.nix
@@ -11,8 +11,8 @@ import ./make-test-python.nix ({ pkgs, ...} :
     imports = [ ./common/user-account.nix ];
     services.xserver.enable = true;
     services.xserver.desktopManager.enlightenment.enable = true;
-    services.xserver.displayManager.lightdm = {
-      enable = true;
+    services.xserver.displayManager = {
+      lightdm.enable = true;
       autoLogin = {
         enable = true;
         user = "alice";
diff --git a/nixpkgs/nixos/tests/hardened.nix b/nixpkgs/nixos/tests/hardened.nix
index a0b629086b5a..da7e0972e131 100644
--- a/nixpkgs/nixos/tests/hardened.nix
+++ b/nixpkgs/nixos/tests/hardened.nix
@@ -1,4 +1,4 @@
-import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... } : {
+import ./make-test-python.nix ({ pkgs, ... } : {
   name = "hardened";
   meta = with pkgs.lib.maintainers; {
     maintainers = [ joachifm ];
@@ -10,8 +10,6 @@ import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... } : {
     { users.users.alice = { isNormalUser = true; extraGroups = [ "proc" ]; };
       users.users.sybil = { isNormalUser = true; group = "wheel"; };
       imports = [ ../modules/profiles/hardened.nix ];
-      boot.kernelPackages =
-        lib.mkIf latestKernel pkgs.linuxPackages_latest_hardened;
       environment.memoryAllocator.provider = "graphene-hardened";
       nix.useSandbox = false;
       virtualisation.emptyDiskImages = [ 4096 ];
@@ -57,6 +55,7 @@ import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... } : {
       # Test kernel module hardening
       with subtest("No more kernel modules can be loaded"):
           # note: this better a be module we normally wouldn't load ...
+          machine.wait_for_unit("disable-kernel-module-loading.service")
           machine.fail("modprobe dccp")
 
 
diff --git a/nixpkgs/nixos/tests/herbstluftwm.nix b/nixpkgs/nixos/tests/herbstluftwm.nix
index 2c98cceee6a2..7d079f4bfb69 100644
--- a/nixpkgs/nixos/tests/herbstluftwm.nix
+++ b/nixpkgs/nixos/tests/herbstluftwm.nix
@@ -3,7 +3,6 @@ import ./make-test-python.nix ({ lib, ...} : {
 
   meta = {
     maintainers = with lib.maintainers; [ thibautmarty ];
-    timeout = 30;
   };
 
   machine = { pkgs, lib, ... }: {
diff --git a/nixpkgs/nixos/tests/kerberos/heimdal.nix b/nixpkgs/nixos/tests/kerberos/heimdal.nix
index 8abae667d043..391a61cc9a90 100644
--- a/nixpkgs/nixos/tests/kerberos/heimdal.nix
+++ b/nixpkgs/nixos/tests/kerberos/heimdal.nix
@@ -9,7 +9,7 @@ import ../make-test-python.nix ({pkgs, ...}: {
     };
     krb5 = {
       enable = true;
-      kerberos = pkgs.heimdalFull;
+      kerberos = pkgs.heimdal;
       libdefaults = {
         default_realm = "FOO.BAR";
       };
diff --git a/nixpkgs/nixos/tests/meilisearch.nix b/nixpkgs/nixos/tests/meilisearch.nix
new file mode 100644
index 000000000000..c379bda74c59
--- /dev/null
+++ b/nixpkgs/nixos/tests/meilisearch.nix
@@ -0,0 +1,60 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }:
+  let
+    listenAddress = "127.0.0.1";
+    listenPort = 7700;
+    apiUrl = "http://${listenAddress}:${toString listenPort}";
+    uid = "movies";
+    indexJSON = pkgs.writeText "index.json" (builtins.toJSON { inherit uid; });
+    moviesJSON = pkgs.runCommand "movies.json" {} ''
+      sed -n '1,5p;$p' ${pkgs.meilisearch.src}/datasets/movies/movies.json > $out
+    '';
+  in {
+    name = "meilisearch";
+    meta.maintainers = with lib.maintainers; [ Br1ght0ne ];
+
+    machine = { ... }: {
+      environment.systemPackages = with pkgs; [ curl jq ];
+      services.meilisearch = {
+        enable = true;
+        inherit listenAddress listenPort;
+      };
+    };
+
+    testScript = ''
+      import json
+
+      start_all()
+
+      machine.wait_for_unit("meilisearch")
+      machine.wait_for_open_port("7700")
+
+      with subtest("check version"):
+          version = json.loads(machine.succeed("curl ${apiUrl}/version"))
+          assert version["pkgVersion"] == "${pkgs.meilisearch.version}"
+
+      with subtest("create index"):
+          machine.succeed(
+              "curl -XPOST ${apiUrl}/indexes --data @${indexJSON}"
+          )
+          indexes = json.loads(machine.succeed("curl ${apiUrl}/indexes"))
+          assert len(indexes) == 1, "index wasn't created"
+
+      with subtest("add documents"):
+          response = json.loads(
+              machine.succeed(
+                  "curl -XPOST ${apiUrl}/indexes/${uid}/documents --data @${moviesJSON}"
+              )
+          )
+          update_id = response["updateId"]
+          machine.wait_until_succeeds(
+              f"curl ${apiUrl}/indexes/${uid}/updates/{update_id} | jq -e '.status == \"processed\"'"
+          )
+
+      with subtest("search"):
+          response = json.loads(
+              machine.succeed("curl ${apiUrl}/indexes/movies/search?q=hero")
+          )
+          print(response)
+          assert len(response["hits"]) >= 1, "no results found"
+    '';
+  })
diff --git a/nixpkgs/nixos/tests/minio.nix b/nixpkgs/nixos/tests/minio.nix
index e49c517098ae..ad51f738d490 100644
--- a/nixpkgs/nixos/tests/minio.nix
+++ b/nixpkgs/nixos/tests/minio.nix
@@ -28,7 +28,10 @@ in {
     machine = { pkgs, ... }: {
       services.minio = {
         enable = true;
-        inherit accessKey secretKey;
+        rootCredentialsFile = pkgs.writeText "minio-credentials" ''
+          MINIO_ROOT_USER=${accessKey}
+          MINIO_ROOT_PASSWORD=${secretKey}
+        '';
       };
       environment.systemPackages = [ pkgs.minio-client ];
 
diff --git a/nixpkgs/nixos/tests/mpv.nix b/nixpkgs/nixos/tests/mpv.nix
index bcfc17cf3328..9e44862cb1b4 100644
--- a/nixpkgs/nixos/tests/mpv.nix
+++ b/nixpkgs/nixos/tests/mpv.nix
@@ -14,7 +14,7 @@ in
     {
       environment.systemPackages = [
         pkgs.curl
-        (pkgs.mpv-with-scripts.override {
+        (pkgs.wrapMpv pkgs.mpv-unwrapped {
           scripts = [ pkgs.mpvScripts.simple-mpv-webui ];
         })
       ];
diff --git a/nixpkgs/nixos/tests/mysql/mariadb-galera-mariabackup.nix b/nixpkgs/nixos/tests/mysql/mariadb-galera-mariabackup.nix
index 1c73bc854a57..10682c361d1d 100644
--- a/nixpkgs/nixos/tests/mysql/mariadb-galera-mariabackup.nix
+++ b/nixpkgs/nixos/tests/mysql/mariadb-galera-mariabackup.nix
@@ -4,6 +4,16 @@ let
   mysqlenv-common      = pkgs.buildEnv { name = "mysql-path-env-common";      pathsToLink = [ "/bin" ]; paths = with pkgs; [ bash gawk gnutar inetutils which ]; };
   mysqlenv-mariabackup = pkgs.buildEnv { name = "mysql-path-env-mariabackup"; pathsToLink = [ "/bin" ]; paths = with pkgs; [ gzip iproute2 netcat procps pv socat ]; };
 
+  # Common user configuration
+  users = { ... }:
+  {
+    users.users.testuser = {
+      isSystemUser = true;
+      group = "testusers";
+    };
+    users.groups.testusers = { };
+  };
+
 in {
   name = "mariadb-galera-mariabackup";
   meta = with pkgs.lib.maintainers; {
@@ -17,6 +27,7 @@ in {
     galera_01 =
       { pkgs, ... }:
       {
+      imports = [ users ];
       networking = {
         interfaces.eth1 = {
           ipv4.addresses = [
@@ -31,7 +42,6 @@ in {
         firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
         firewall.allowedUDPPorts = [ 4567 ];
       };
-      users.users.testuser = { isSystemUser = true; };
       systemd.services.mysql = with pkgs; {
         path = [ mysqlenv-common mysqlenv-mariabackup ];
       };
@@ -75,6 +85,7 @@ in {
     galera_02 =
       { pkgs, ... }:
       {
+      imports = [ users ];
       networking = {
         interfaces.eth1 = {
           ipv4.addresses = [
@@ -89,7 +100,6 @@ in {
         firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
         firewall.allowedUDPPorts = [ 4567 ];
       };
-      users.users.testuser = { isSystemUser = true; };
       systemd.services.mysql = with pkgs; {
         path = [ mysqlenv-common mysqlenv-mariabackup ];
       };
@@ -122,6 +132,7 @@ in {
     galera_03 =
       { pkgs, ... }:
       {
+      imports = [ users ];
       networking = {
         interfaces.eth1 = {
           ipv4.addresses = [
@@ -136,7 +147,6 @@ in {
         firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
         firewall.allowedUDPPorts = [ 4567 ];
       };
-      users.users.testuser = { isSystemUser = true; };
       systemd.services.mysql = with pkgs; {
         path = [ mysqlenv-common mysqlenv-mariabackup ];
       };
diff --git a/nixpkgs/nixos/tests/mysql/mariadb-galera-rsync.nix b/nixpkgs/nixos/tests/mysql/mariadb-galera-rsync.nix
index 709a8b5085cb..701e01e88718 100644
--- a/nixpkgs/nixos/tests/mysql/mariadb-galera-rsync.nix
+++ b/nixpkgs/nixos/tests/mysql/mariadb-galera-rsync.nix
@@ -4,6 +4,16 @@ let
   mysqlenv-common      = pkgs.buildEnv { name = "mysql-path-env-common";      pathsToLink = [ "/bin" ]; paths = with pkgs; [ bash gawk gnutar inetutils which ]; };
   mysqlenv-rsync       = pkgs.buildEnv { name = "mysql-path-env-rsync";       pathsToLink = [ "/bin" ]; paths = with pkgs; [ lsof procps rsync stunnel ]; };
 
+  # Common user configuration
+  users = { ... }:
+  {
+    users.users.testuser = {
+      isSystemUser = true;
+      group = "testusers";
+    };
+    users.groups.testusers = { };
+  };
+
 in {
   name = "mariadb-galera-rsync";
   meta = with pkgs.lib.maintainers; {
@@ -17,6 +27,7 @@ in {
     galera_04 =
       { pkgs, ... }:
       {
+      imports = [ users ];
       networking = {
         interfaces.eth1 = {
           ipv4.addresses = [
@@ -31,7 +42,6 @@ in {
         firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
         firewall.allowedUDPPorts = [ 4567 ];
       };
-      users.users.testuser = { isSystemUser = true; };
       systemd.services.mysql = with pkgs; {
         path = [ mysqlenv-common mysqlenv-rsync ];
       };
@@ -70,6 +80,7 @@ in {
     galera_05 =
       { pkgs, ... }:
       {
+      imports = [ users ];
       networking = {
         interfaces.eth1 = {
           ipv4.addresses = [
@@ -84,7 +95,6 @@ in {
         firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
         firewall.allowedUDPPorts = [ 4567 ];
       };
-      users.users.testuser = { isSystemUser = true; };
       systemd.services.mysql = with pkgs; {
         path = [ mysqlenv-common mysqlenv-rsync ];
       };
@@ -116,6 +126,7 @@ in {
     galera_06 =
       { pkgs, ... }:
       {
+      imports = [ users ];
       networking = {
         interfaces.eth1 = {
           ipv4.addresses = [
@@ -130,7 +141,6 @@ in {
         firewall.allowedTCPPorts = [ 3306 4444 4567 4568 ];
         firewall.allowedUDPPorts = [ 4567 ];
       };
-      users.users.testuser = { isSystemUser = true; };
       systemd.services.mysql = with pkgs; {
         path = [ mysqlenv-common mysqlenv-rsync ];
       };
diff --git a/nixpkgs/nixos/tests/mysql/mysql.nix b/nixpkgs/nixos/tests/mysql/mysql.nix
index 2ec9c3d50a3c..dce5fa26acf7 100644
--- a/nixpkgs/nixos/tests/mysql/mysql.nix
+++ b/nixpkgs/nixos/tests/mysql/mysql.nix
@@ -1,4 +1,26 @@
-import ./../make-test-python.nix ({ pkgs, ...} : {
+import ./../make-test-python.nix ({ pkgs, ...}:
+
+
+let
+  # Setup common users
+  users = { ... }:
+  {
+    users.groups.testusers = { };
+
+    users.users.testuser = {
+      isSystemUser = true;
+      group = "testusers";
+    };
+
+    users.users.testuser2 = {
+      isSystemUser = true;
+      group = "testusers";
+    };
+  };
+
+in
+
+{
   name = "mysql";
   meta = with pkgs.lib.maintainers; {
     maintainers = [ eelco shlevy ];
@@ -9,8 +31,8 @@ import ./../make-test-python.nix ({ pkgs, ...} : {
       { pkgs, ... }:
 
       {
-        users.users.testuser = { isSystemUser = true; };
-        users.users.testuser2 = { isSystemUser = true; };
+        imports = [ users ];
+
         services.mysql.enable = true;
         services.mysql.initialDatabases = [
           { name = "testdb3"; schema = ./testdb.sql; }
@@ -40,12 +62,12 @@ import ./../make-test-python.nix ({ pkgs, ...} : {
       { pkgs, ... }:
 
       {
+        imports = [ users ];
+
         # prevent oom:
         # Kernel panic - not syncing: Out of memory: compulsory panic_on_oom is enabled
         virtualisation.memorySize = 1024;
 
-        users.users.testuser = { isSystemUser = true; };
-        users.users.testuser2 = { isSystemUser = true; };
         services.mysql.enable = true;
         services.mysql.initialDatabases = [
           { name = "testdb3"; schema = ./testdb.sql; }
@@ -75,8 +97,8 @@ import ./../make-test-python.nix ({ pkgs, ...} : {
       { pkgs, ... }:
 
       {
-        users.users.testuser = { isSystemUser = true; };
-        users.users.testuser2 = { isSystemUser = true; };
+        imports = [ users ];
+
         services.mysql.enable = true;
         services.mysql.initialScript = pkgs.writeText "mariadb-init.sql" ''
           ALTER USER root@localhost IDENTIFIED WITH unix_socket;
diff --git a/nixpkgs/nixos/tests/owncast.nix b/nixpkgs/nixos/tests/owncast.nix
new file mode 100644
index 000000000000..e54d2cc5dd48
--- /dev/null
+++ b/nixpkgs/nixos/tests/owncast.nix
@@ -0,0 +1,21 @@
+{ system ? builtins.currentSystem, config ? { }
+, pkgs ? import ../.. { inherit system config; } }:
+
+with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; };
+makeTest {
+  name = "owncast";
+  meta = with pkgs.stdenv.lib.maintainers; { maintainers = [ MayNiklas ]; };
+
+  nodes = {
+    client = { ... }: {
+      environment.systemPackages = [ curl ];
+      services.owncast = { enable = true; };
+    };
+  };
+
+  testScript = ''
+    start_all()
+    client.wait_for_unit("owncast.service")
+    client.succeed("curl localhost:8080/api/status")
+  '';
+}
diff --git a/nixpkgs/nixos/tests/pantheon.nix b/nixpkgs/nixos/tests/pantheon.nix
index 3894440333c9..20aee2eb7a4c 100644
--- a/nixpkgs/nixos/tests/pantheon.nix
+++ b/nixpkgs/nixos/tests/pantheon.nix
@@ -1,10 +1,10 @@
-import ./make-test-python.nix ({ pkgs, ...} :
+import ./make-test-python.nix ({ pkgs, lib, ...} :
 
 {
   name = "pantheon";
 
-  meta = with pkgs.lib.maintainers; {
-    maintainers = pkgs.pantheon.maintainers;
+  meta = with lib; {
+    maintainers = teams.pantheon.members;
   };
 
   machine = { ... }:
@@ -45,8 +45,8 @@ import ./make-test-python.nix ({ pkgs, ...} :
     with subtest("Check if pantheon session components actually start"):
         machine.wait_until_succeeds("pgrep gala")
         machine.wait_for_window("gala")
-        machine.wait_until_succeeds("pgrep wingpanel")
-        machine.wait_for_window("wingpanel")
+        machine.wait_until_succeeds("pgrep -f io.elementary.wingpanel")
+        machine.wait_for_window("io.elementary.wingpanel")
         machine.wait_until_succeeds("pgrep plank")
         machine.wait_for_window("plank")
 
diff --git a/nixpkgs/nixos/tests/parsedmarc/default.nix b/nixpkgs/nixos/tests/parsedmarc/default.nix
new file mode 100644
index 000000000000..d838d3b6a39c
--- /dev/null
+++ b/nixpkgs/nixos/tests/parsedmarc/default.nix
@@ -0,0 +1,224 @@
+# This tests parsedmarc by sending a report to its monitored email
+# address and reading the results out of Elasticsearch.
+
+{ pkgs, ... }@args:
+let
+  inherit (import ../../lib/testing-python.nix args) makeTest;
+
+  dmarcTestReport = builtins.fetchurl {
+    name = "dmarc-test-report";
+    url = "https://github.com/domainaware/parsedmarc/raw/f45ab94e0608088e0433557608d9f4e9517d3afe/samples/aggregate/estadocuenta1.infonacot.gob.mx!example.com!1536853302!1536939702!2940.xml.zip";
+    sha256 = "0dq64cj49711kbja27pjl2hy0d3azrjxg91kqrh40x46fkn1dwkx";
+  };
+
+  sendEmail = address:
+    pkgs.writeScriptBin "send-email" ''
+      #!${pkgs.python3.interpreter}
+      import smtplib
+      from email import encoders
+      from email.mime.base import MIMEBase
+      from email.mime.multipart import MIMEMultipart
+      from email.mime.text import MIMEText
+
+      sender_email = "dmarc_tester@fake.domain"
+      receiver_email = "${address}"
+
+      message = MIMEMultipart()
+      message["From"] = sender_email
+      message["To"] = receiver_email
+      message["Subject"] = "DMARC test"
+
+      message.attach(MIMEText("Testing parsedmarc", "plain"))
+
+      attachment = MIMEBase("application", "zip")
+
+      with open("${dmarcTestReport}", "rb") as report:
+          attachment.set_payload(report.read())
+
+      encoders.encode_base64(attachment)
+
+      attachment.add_header(
+          "Content-Disposition",
+          "attachment; filename= estadocuenta1.infonacot.gob.mx!example.com!1536853302!1536939702!2940.xml.zip",
+      )
+
+      message.attach(attachment)
+      text = message.as_string()
+
+      with smtplib.SMTP('localhost') as server:
+          server.sendmail(sender_email, receiver_email, text)
+          server.quit()
+    '';
+in
+{
+  localMail = makeTest
+    {
+      name = "parsedmarc-local-mail";
+      meta = with pkgs.lib.maintainers; {
+        maintainers = [ talyz ];
+      };
+
+      nodes.parsedmarc =
+        { nodes, ... }:
+        {
+          virtualisation.memorySize = 2048;
+
+          services.postfix = {
+            enableSubmission = true;
+            enableSubmissions = true;
+            submissionsOptions = {
+              smtpd_sasl_auth_enable = "yes";
+              smtpd_client_restrictions = "permit";
+            };
+          };
+
+          services.parsedmarc = {
+            enable = true;
+            provision = {
+              geoIp = false;
+              localMail = {
+                enable = true;
+                hostname = "localhost";
+              };
+            };
+          };
+
+          services.elasticsearch.package = pkgs.elasticsearch7-oss;
+
+          environment.systemPackages = [
+            (sendEmail "dmarc@localhost")
+            pkgs.jq
+          ];
+        };
+
+      testScript = { nodes }:
+        let
+          esPort = toString nodes.parsedmarc.config.services.elasticsearch.port;
+        in ''
+          parsedmarc.start()
+          parsedmarc.wait_for_unit("postfix.service")
+          parsedmarc.wait_for_unit("dovecot2.service")
+          parsedmarc.wait_for_unit("parsedmarc.service")
+          parsedmarc.wait_until_succeeds(
+              "curl -sS -f http://localhost:${esPort}"
+          )
+
+          parsedmarc.fail(
+              "curl -sS -f http://localhost:${esPort}/_search?q=report_id:2940 | jq -e 'if .hits.total.value > 0 then true else null end'"
+          )
+          parsedmarc.succeed("send-email")
+          parsedmarc.wait_until_succeeds(
+              "curl -sS -f http://localhost:${esPort}/_search?q=report_id:2940 | jq -e 'if .hits.total.value > 0 then true else null end'"
+          )
+        '';
+    };
+
+  externalMail =
+    let
+      certs = import ../common/acme/server/snakeoil-certs.nix;
+      mailDomain = certs.domain;
+      parsedmarcDomain = "parsedmarc.fake.domain";
+    in
+      makeTest {
+        name = "parsedmarc-external-mail";
+        meta = with pkgs.lib.maintainers; {
+          maintainers = [ talyz ];
+        };
+
+        nodes = {
+          parsedmarc =
+            { nodes, ... }:
+            {
+              virtualisation.memorySize = 2048;
+
+              security.pki.certificateFiles = [
+                certs.ca.cert
+              ];
+
+              networking.extraHosts = ''
+                127.0.0.1 ${parsedmarcDomain}
+                ${nodes.mail.config.networking.primaryIPAddress} ${mailDomain}
+              '';
+
+              services.parsedmarc = {
+                enable = true;
+                provision.geoIp = false;
+                settings.imap = {
+                  host = mailDomain;
+                  port = 993;
+                  ssl = true;
+                  user = "alice";
+                  password = "${pkgs.writeText "imap-password" "foobar"}";
+                  watch = true;
+                };
+              };
+
+              services.elasticsearch.package = pkgs.elasticsearch7-oss;
+
+              environment.systemPackages = [
+                pkgs.jq
+              ];
+            };
+
+          mail =
+            { nodes, ... }:
+            {
+              imports = [ ../common/user-account.nix ];
+
+              networking.extraHosts = ''
+                127.0.0.1 ${mailDomain}
+                ${nodes.parsedmarc.config.networking.primaryIPAddress} ${parsedmarcDomain}
+              '';
+
+              services.dovecot2 = {
+                enable = true;
+                protocols = [ "imap" ];
+                sslCACert = "${certs.ca.cert}";
+                sslServerCert = "${certs.${mailDomain}.cert}";
+                sslServerKey = "${certs.${mailDomain}.key}";
+              };
+
+              services.postfix = {
+                enable = true;
+                origin = mailDomain;
+                config = {
+                  myhostname = mailDomain;
+                  mydestination = mailDomain;
+                };
+                enableSubmission = true;
+                enableSubmissions = true;
+                submissionsOptions = {
+                  smtpd_sasl_auth_enable = "yes";
+                  smtpd_client_restrictions = "permit";
+                };
+              };
+              environment.systemPackages = [ (sendEmail "alice@${mailDomain}") ];
+
+              networking.firewall.allowedTCPPorts = [ 993 ];
+            };
+        };
+
+        testScript = { nodes }:
+          let
+            esPort = toString nodes.parsedmarc.config.services.elasticsearch.port;
+          in ''
+            mail.start()
+            mail.wait_for_unit("postfix.service")
+            mail.wait_for_unit("dovecot2.service")
+
+            parsedmarc.start()
+            parsedmarc.wait_for_unit("parsedmarc.service")
+            parsedmarc.wait_until_succeeds(
+                "curl -sS -f http://localhost:${esPort}"
+            )
+
+            parsedmarc.fail(
+                "curl -sS -f http://localhost:${esPort}/_search?q=report_id:2940 | jq -e 'if .hits.total.value > 0 then true else null end'"
+            )
+            mail.succeed("send-email")
+            parsedmarc.wait_until_succeeds(
+                "curl -sS -f http://localhost:${esPort}/_search?q=report_id:2940 | jq -e 'if .hits.total.value > 0 then true else null end'"
+            )
+          '';
+      };
+}
diff --git a/nixpkgs/nixos/tests/postfixadmin.nix b/nixpkgs/nixos/tests/postfixadmin.nix
index aba5e3eed102..b2712f4699ae 100644
--- a/nixpkgs/nixos/tests/postfixadmin.nix
+++ b/nixpkgs/nixos/tests/postfixadmin.nix
@@ -1,6 +1,6 @@
 import ./make-test-python.nix ({ pkgs, ...} : {
   name = "postfixadmin";
-  meta = with pkgs.stdenv.lib.maintainers; {
+  meta = with pkgs.lib.maintainers; {
     maintainers = [ globin ];
   };
 
diff --git a/nixpkgs/nixos/tests/prometheus-exporters.nix b/nixpkgs/nixos/tests/prometheus-exporters.nix
index c6e8fa5a9ee1..38b93c4087c0 100644
--- a/nixpkgs/nixos/tests/prometheus-exporters.nix
+++ b/nixpkgs/nixos/tests/prometheus-exporters.nix
@@ -280,6 +280,7 @@ let
       };
       exporterTest = ''
         wait_for_unit("prometheus-influxdb-exporter.service")
+        wait_for_open_port(9122)
         succeed(
           "curl -XPOST http://localhost:9122/write --data-binary 'influxdb_exporter,distro=nixos,added_in=21.09 value=1'"
         )
@@ -554,7 +555,11 @@ let
             WorkingDirectory = "/var/spool/mail";
           };
         };
-        users.users.mailexporter.isSystemUser = true;
+        users.users.mailexporter = {
+          isSystemUser = true;
+          group = "mailexporter";
+        };
+        users.groups.mailexporter = {};
       };
       exporterTest = ''
         wait_for_unit("postfix.service")
diff --git a/nixpkgs/nixos/tests/run-in-machine.nix b/nixpkgs/nixos/tests/run-in-machine.nix
deleted file mode 100644
index 67840f3e9fe7..000000000000
--- a/nixpkgs/nixos/tests/run-in-machine.nix
+++ /dev/null
@@ -1,23 +0,0 @@
-{ system ? builtins.currentSystem,
-  config ? {},
-  pkgs ? import ../.. { inherit system config; }
-}:
-
-with import ../lib/testing-python.nix { inherit system pkgs; };
-
-let
-  output = runInMachine {
-    drv = pkgs.hello;
-    machine = { ... }: { /* services.sshd.enable = true; */ };
-  };
-
-  test = pkgs.runCommand "verify-output" { inherit output; } ''
-    if [ ! -e "$output/bin/hello" ]; then
-      echo "Derivation built using runInMachine produced incorrect output:" >&2
-      ls -laR "$output" >&2
-      exit 1
-    fi
-    "$output/bin/hello" > "$out"
-  '';
-
-in test // { inherit test; } # To emulate behaviour of makeTest
diff --git a/nixpkgs/nixos/tests/spark/default.nix b/nixpkgs/nixos/tests/spark/default.nix
new file mode 100644
index 000000000000..254cdec6e6b0
--- /dev/null
+++ b/nixpkgs/nixos/tests/spark/default.nix
@@ -0,0 +1,28 @@
+import ../make-test-python.nix ({...}: {
+  name = "spark";
+
+  nodes = {
+    worker = { nodes, pkgs, ... }: {
+      virtualisation.memorySize = 1024;
+      services.spark.worker = {
+        enable = true;
+        master = "master:7077";
+      };
+    };
+    master = { config, pkgs, ... }: {
+      services.spark.master = {
+        enable = true;
+        bind = "0.0.0.0";
+      };
+      networking.firewall.allowedTCPPorts = [ 22 7077 8080 ];
+    };
+  };
+
+  testScript = ''
+    master.wait_for_unit("spark-master.service")
+    worker.wait_for_unit("spark-worker.service")
+    worker.copy_from_host( "${./spark_sample.py}", "/spark_sample.py" )
+    assert "<title>Spark Master at spark://" in worker.succeed("curl -sSfkL http://master:8080/")
+    worker.succeed("spark-submit --master spark://master:7077 --executor-memory 512m --executor-cores 1 /spark_sample.py")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/spark/spark_sample.py b/nixpkgs/nixos/tests/spark/spark_sample.py
new file mode 100644
index 000000000000..c4939451eae0
--- /dev/null
+++ b/nixpkgs/nixos/tests/spark/spark_sample.py
@@ -0,0 +1,40 @@
+from pyspark.sql import Row, SparkSession
+from pyspark.sql import functions as F
+from pyspark.sql.functions import udf
+from pyspark.sql.types import *
+from pyspark.sql.functions import explode
+
+def explode_col(weight):
+    return int(weight//10) * [10.0] + ([] if weight%10==0 else [weight%10])
+
+spark = SparkSession.builder.getOrCreate()
+
+dataSchema = [
+    StructField("feature_1", FloatType()),
+    StructField("feature_2", FloatType()),
+    StructField("bias_weight", FloatType())
+]
+
+data = [
+    Row(0.1, 0.2, 10.32),
+    Row(0.32, 1.43, 12.8),
+    Row(1.28, 1.12, 0.23)
+]
+
+df = spark.createDataFrame(spark.sparkContext.parallelize(data), StructType(dataSchema))
+
+normalizing_constant = 100
+sum_bias_weight = df.select(F.sum('bias_weight')).collect()[0][0]
+normalizing_factor = normalizing_constant / sum_bias_weight
+df = df.withColumn('normalized_bias_weight', df.bias_weight * normalizing_factor)
+df = df.drop('bias_weight')
+df = df.withColumnRenamed('normalized_bias_weight', 'bias_weight')
+
+my_udf = udf(lambda x: explode_col(x), ArrayType(FloatType()))
+df1 = df.withColumn('explode_val', my_udf(df.bias_weight))
+df1 = df1.withColumn("explode_val_1", explode(df1.explode_val)).drop("explode_val")
+df1 = df1.drop('bias_weight').withColumnRenamed('explode_val_1', 'bias_weight')
+
+df1.show()
+
+assert(df1.count() == 12)
diff --git a/nixpkgs/nixos/tests/systemd-confinement.nix b/nixpkgs/nixos/tests/systemd-confinement.nix
index e6a308f46d27..8fafb11e1e8c 100644
--- a/nixpkgs/nixos/tests/systemd-confinement.nix
+++ b/nixpkgs/nixos/tests/systemd-confinement.nix
@@ -44,30 +44,26 @@ import ./make-test-python.nix {
       { config.confinement.mode = "chroot-only";
         testScript = ''
           with subtest("chroot-only confinement"):
-              machine.succeed(
-                  'test "$(chroot-exec ls -1 / | paste -sd,)" = bin,nix',
-                  'test "$(chroot-exec id -u)" = 0',
-                  "chroot-exec chown 65534 /bin",
-              )
+              paths = machine.succeed('chroot-exec ls -1 / | paste -sd,').strip()
+              assert_eq(paths, "bin,nix,run")
+              uid = machine.succeed('chroot-exec id -u').strip()
+              assert_eq(uid, "0")
+              machine.succeed("chroot-exec chown 65534 /bin")
         '';
       }
       { testScript = ''
           with subtest("full confinement with APIVFS"):
-              machine.fail(
-                  "chroot-exec ls -l /etc",
-                  "chroot-exec ls -l /run",
-                  "chroot-exec chown 65534 /bin",
-              )
-              machine.succeed(
-                  'test "$(chroot-exec id -u)" = 0',
-                  "chroot-exec chown 0 /bin",
-              )
+              machine.fail("chroot-exec ls -l /etc")
+              machine.fail("chroot-exec chown 65534 /bin")
+              assert_eq(machine.succeed('chroot-exec id -u').strip(), "0")
+              machine.succeed("chroot-exec chown 0 /bin")
         '';
       }
       { config.serviceConfig.BindReadOnlyPaths = [ "/etc" ];
         testScript = ''
           with subtest("check existence of bind-mounted /etc"):
-              machine.succeed('test -n "$(chroot-exec cat /etc/passwd)"')
+              passwd = machine.succeed('chroot-exec cat /etc/passwd').strip()
+              assert len(passwd) > 0, "/etc/passwd must not be empty"
         '';
       }
       { config.serviceConfig.User = "chroot-testuser";
@@ -75,7 +71,8 @@ import ./make-test-python.nix {
         testScript = ''
           with subtest("check if User/Group really runs as non-root"):
               machine.succeed("chroot-exec ls -l /dev")
-              machine.succeed('test "$(chroot-exec id -u)" != 0')
+              uid = machine.succeed('chroot-exec id -u').strip()
+              assert uid != "0", "UID of chroot-testuser shouldn't be 0"
               machine.fail("chroot-exec touch /bin/test")
         '';
       }
@@ -88,10 +85,8 @@ import ./make-test-python.nix {
         testScript = ''
           with subtest("check if symlinks are properly bind-mounted"):
               machine.fail("chroot-exec test -e /etc")
-              machine.succeed(
-                  "chroot-exec cat ${symlink} >&2",
-                  'test "$(chroot-exec cat ${symlink})" = "got me"',
-              )
+              text = machine.succeed('chroot-exec cat ${symlink}').strip()
+              assert_eq(text, "got me")
         '';
       })
       { config.serviceConfig.User = "chroot-testuser";
@@ -158,6 +153,9 @@ import ./make-test-python.nix {
   };
 
   testScript = { nodes, ... }: ''
+    def assert_eq(a, b):
+        assert a == b, f"{a} != {b}"
+
     machine.wait_for_unit("multi-user.target")
   '' + nodes.machine.config.__testSteps;
 }
diff --git a/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix b/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
index 94f17605e001..68836c730729 100644
--- a/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
+++ b/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
@@ -42,6 +42,8 @@ import ./make-test-python.nix ({pkgs, ...}: {
       # DO NOT COPY THIS TO PRODUCTION AS IS. Think about it at least twice.
       # Everyone on the "isp" machine will be able to add routes to the kernel.
       security.wrappers.add-dhcpd-lease = {
+        owner = "root";
+        group = "root";
         source = pkgs.writeShellScript "add-dhcpd-lease" ''
           exec ${pkgs.iproute2}/bin/ip -6 route replace "$1" via "$2"
         '';
diff --git a/nixpkgs/nixos/tests/tigervnc.nix b/nixpkgs/nixos/tests/tigervnc.nix
index c0a52808b279..092eaf238d80 100644
--- a/nixpkgs/nixos/tests/tigervnc.nix
+++ b/nixpkgs/nixos/tests/tigervnc.nix
@@ -6,7 +6,7 @@
 with import ../lib/testing-python.nix { inherit system pkgs; };
 makeTest {
   name = "tigervnc";
-  meta = with pkgs.stdenv.lib.maintainers; {
+  meta = with pkgs.lib.maintainers; {
     maintainers = [ lheckemann ];
   };
 
diff --git a/nixpkgs/nixos/tests/unbound.nix b/nixpkgs/nixos/tests/unbound.nix
index 58a717f98a16..576287a9fe5d 100644
--- a/nixpkgs/nixos/tests/unbound.nix
+++ b/nixpkgs/nixos/tests/unbound.nix
@@ -145,13 +145,22 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
           # user that is permitted to access the unix socket
           someuser = {
             isSystemUser = true;
+            group = "someuser";
             extraGroups = [
               config.users.users.unbound.group
             ];
           };
 
           # user that is not permitted to access the unix socket
-          unauthorizeduser = { isSystemUser = true; };
+          unauthorizeduser = {
+            isSystemUser = true;
+            group = "unauthorizeduser";
+          };
+
+        };
+        users.groups = {
+          someuser = {};
+          unauthorizeduser = {};
         };
 
         # Used for testing configuration reloading
diff --git a/nixpkgs/nixos/tests/user-activation-scripts.nix b/nixpkgs/nixos/tests/user-activation-scripts.nix
new file mode 100644
index 000000000000..0de8664c5ef0
--- /dev/null
+++ b/nixpkgs/nixos/tests/user-activation-scripts.nix
@@ -0,0 +1,33 @@
+import ./make-test-python.nix ({ lib, ... }: {
+  name = "user-activation-scripts";
+  meta = with lib.maintainers; { maintainers = [ chkno ]; };
+
+  machine = {
+    system.userActivationScripts.foo = "mktemp ~/user-activation-ran.XXXXXX";
+    users.users.alice = {
+      initialPassword = "pass1";
+      isNormalUser = true;
+    };
+  };
+
+  testScript = ''
+    def verify_user_activation_run_count(n):
+        machine.succeed(
+            '[[ "$(find /home/alice/ -name user-activation-ran.\\* | wc -l)" == %s ]]' % n
+        )
+
+
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_for_unit("getty@tty1.service")
+    machine.wait_until_tty_matches(1, "login: ")
+    machine.send_chars("alice\n")
+    machine.wait_until_tty_matches(1, "Password: ")
+    machine.send_chars("pass1\n")
+    machine.send_chars("touch login-ok\n")
+    machine.wait_for_file("/home/alice/login-ok")
+    verify_user_activation_run_count(1)
+
+    machine.succeed("/run/current-system/bin/switch-to-configuration test")
+    verify_user_activation_run_count(2)
+  '';
+})
diff --git a/nixpkgs/nixos/tests/wasabibackend.nix b/nixpkgs/nixos/tests/wasabibackend.nix
index 1832698ab698..75730fe24d09 100644
--- a/nixpkgs/nixos/tests/wasabibackend.nix
+++ b/nixpkgs/nixos/tests/wasabibackend.nix
@@ -14,7 +14,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
           port = 18332;
         };
       };
-      services.bitcoind = {
+      services.bitcoind."testnet" = {
         enable = true;
         testnet = true;
         rpc.users = {
diff --git a/nixpkgs/nixos/tests/wordpress.nix b/nixpkgs/nixos/tests/wordpress.nix
index 45c58b5b65c8..f7f39668c86e 100644
--- a/nixpkgs/nixos/tests/wordpress.nix
+++ b/nixpkgs/nixos/tests/wordpress.nix
@@ -45,6 +45,21 @@ import ./make-test-python.nix ({ pkgs, ... }:
       networking.firewall.allowedTCPPorts = [ 80 ];
       networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
     };
+
+    wp_caddy = { ... }: {
+      services.wordpress.webserver = "caddy";
+      services.wordpress.sites = {
+        "site1.local" = {
+          database.tablePrefix = "site1_";
+        };
+        "site2.local" = {
+          database.tablePrefix = "site2_";
+        };
+      };
+
+      networking.firewall.allowedTCPPorts = [ 80 ];
+      networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
+    };
   };
 
   testScript = ''
@@ -54,10 +69,11 @@ import ./make-test-python.nix ({ pkgs, ... }:
 
     wp_httpd.wait_for_unit("httpd")
     wp_nginx.wait_for_unit("nginx")
+    wp_caddy.wait_for_unit("caddy")
 
     site_names = ["site1.local", "site2.local"]
 
-    for machine in (wp_httpd, wp_nginx):
+    for machine in (wp_httpd, wp_nginx, wp_caddy):
         for site_name in site_names:
             machine.wait_for_unit(f"phpfpm-wordpress-{site_name}")