about summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/hardware/all-firmware.nix2
-rw-r--r--nixos/modules/hardware/video/hidpi.nix1
-rw-r--r--nixos/modules/hardware/video/nvidia.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/iso-image.nix2
-rw-r--r--nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh7
-rw-r--r--nixos/modules/installer/tools/nixos-enter.sh1
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl8
-rw-r--r--nixos/modules/installer/tools/nixos-install.sh3
-rw-r--r--nixos/modules/installer/tools/nixos-version.sh1
-rw-r--r--nixos/modules/misc/documentation.nix8
-rw-r--r--nixos/modules/misc/ids.nix2
-rw-r--r--nixos/modules/misc/locate.nix4
-rw-r--r--nixos/modules/module-list.nix3
-rw-r--r--nixos/modules/profiles/base.nix1
-rw-r--r--nixos/modules/programs/sway.nix2
-rw-r--r--nixos/modules/programs/zsh/zsh-autosuggestions.nix8
-rw-r--r--nixos/modules/security/acme.nix14
-rw-r--r--nixos/modules/security/acme.xml2
-rw-r--r--nixos/modules/security/pam.nix337
-rw-r--r--nixos/modules/services/backup/borgbackup.nix1
-rw-r--r--nixos/modules/services/continuous-integration/hercules-ci-agent/common.nix77
-rw-r--r--nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix6
-rw-r--r--nixos/modules/services/databases/clickhouse.nix17
-rw-r--r--nixos/modules/services/databases/hbase.nix41
-rw-r--r--nixos/modules/services/hardware/bluetooth.nix4
-rw-r--r--nixos/modules/services/logging/logrotate.nix4
-rw-r--r--nixos/modules/services/logging/logstash.nix13
-rw-r--r--nixos/modules/services/mail/dovecot.nix3
-rw-r--r--nixos/modules/services/matrix/mjolnir.nix2
-rw-r--r--nixos/modules/services/misc/gollum.nix1
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix4
-rw-r--r--nixos/modules/services/misc/xmrig.nix10
-rw-r--r--nixos/modules/services/monitoring/cadvisor.nix2
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/nginx.nix2
-rw-r--r--nixos/modules/services/monitoring/zabbix-server.nix7
-rw-r--r--nixos/modules/services/network-filesystems/webdav-server-rs.nix144
-rw-r--r--nixos/modules/services/network-filesystems/webdav.nix107
-rw-r--r--nixos/modules/services/networking/monero.nix2
-rw-r--r--nixos/modules/services/networking/networkmanager.nix1
-rw-r--r--nixos/modules/services/networking/nomad.nix19
-rw-r--r--nixos/modules/services/networking/radicale.nix1
-rw-r--r--nixos/modules/services/networking/sabnzbd.nix9
-rw-r--r--nixos/modules/services/ttys/getty.nix15
-rw-r--r--nixos/modules/services/web-apps/moodle.nix2
-rw-r--r--nixos/modules/services/web-servers/caddy/default.nix27
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/cinnamon.nix7
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix6
-rw-r--r--nixos/modules/services/x11/display-managers/startx.nix3
-rw-r--r--nixos/modules/services/x11/display-managers/sx.nix5
-rw-r--r--nixos/modules/services/x11/hardware/libinput.nix15
-rw-r--r--nixos/modules/services/x11/window-managers/xmonad.nix3
-rw-r--r--nixos/modules/services/x11/xserver.nix24
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl274
-rw-r--r--nixos/modules/system/activation/top-level.nix7
-rw-r--r--nixos/modules/system/boot/kernel.nix2
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl176
-rw-r--r--nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py20
-rw-r--r--nixos/modules/system/boot/systemd.nix1
-rw-r--r--nixos/modules/tasks/auto-upgrade.nix1
-rw-r--r--nixos/modules/tasks/network-interfaces.nix6
-rw-r--r--nixos/modules/virtualisation/azure-agent.nix2
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix8
-rw-r--r--nixos/modules/virtualisation/virtualbox-guest.nix2
-rw-r--r--nixos/modules/virtualisation/vmware-guest.nix7
65 files changed, 942 insertions, 558 deletions
diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix
index bdf90816740c..ce87f9e8be8a 100644
--- a/nixos/modules/hardware/all-firmware.nix
+++ b/nixos/modules/hardware/all-firmware.nix
@@ -83,7 +83,7 @@ in {
         b43Firmware_5_1_138
         b43Firmware_6_30_163_46
         b43FirmwareCutter
-      ] ++ optional (pkgs.stdenv.hostPlatform.isi686 || pkgs.stdenv.hostPlatform.isx86_64) facetimehd-firmware;
+      ] ++ optional pkgs.stdenv.hostPlatform.isx86 facetimehd-firmware;
     })
     (mkIf cfg.wirelessRegulatoryDatabase {
       hardware.firmware = [ pkgs.wireless-regdb ];
diff --git a/nixos/modules/hardware/video/hidpi.nix b/nixos/modules/hardware/video/hidpi.nix
index c480cc481dfc..ac72b652504e 100644
--- a/nixos/modules/hardware/video/hidpi.nix
+++ b/nixos/modules/hardware/video/hidpi.nix
@@ -12,6 +12,5 @@ with lib;
     boot.loader.systemd-boot.consoleMode = mkDefault "1";
 
     # TODO Find reasonable defaults X11 & wayland
-    services.xserver.dpi = lib.mkDefault 192;
   };
 }
diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix
index 5b379505608a..ff4225dc29ad 100644
--- a/nixos/modules/hardware/video/nvidia.nix
+++ b/nixos/modules/hardware/video/nvidia.nix
@@ -179,7 +179,7 @@ in
   in mkIf enabled {
     assertions = [
       {
-        assertion = with config.services.xserver.displayManager; gdm.nvidiaWayland -> cfg.modesetting.enable;
+        assertion = with config.services.xserver.displayManager; (gdm.enable && gdm.nvidiaWayland) -> cfg.modesetting.enable;
         message = "You cannot use wayland with GDM without modesetting enabled for NVIDIA drivers, set `hardware.nvidia.modesetting.enable = true`";
       }
 
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index 4812cacabaf3..30610b4f4260 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -467,7 +467,7 @@ let
       throw "Unsupported architecture";
 
   # Syslinux (and isolinux) only supports x86-based architectures.
-  canx86BiosBoot = pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64;
+  canx86BiosBoot = pkgs.stdenv.hostPlatform.isx86;
 
 in
 
diff --git a/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh b/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh
index 2a6c3ab11497..490ede04e6bb 100644
--- a/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh
+++ b/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh
@@ -1,4 +1,5 @@
 #! @runtimeShell@ -e
+# shellcheck shell=bash
 
 # Shows the usage of this command to the user
 
@@ -29,12 +30,12 @@ while [ $# -gt 0 ]; do
         nixBuildArgs+=("--option" "$1" "$2"); shift
         ;;
       *)
-        if [ ! -z "$networkExpr" ]; then
+        if [ -n "$networkExpr" ]; then
           echo "Network expression already set!"
           showUsage
           exit 1
         fi
-        networkExpr="$(readlink -f $1)"
+        networkExpr="$(readlink -f "$1")"
         ;;
     esac
 
@@ -49,4 +50,4 @@ fi
 
 # Build a network of VMs
 nix-build '<nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix>' \
-    --argstr networkExpr $networkExpr "${nixBuildArgs[@]}"
+    --argstr networkExpr "$networkExpr" "${nixBuildArgs[@]}"
diff --git a/nixos/modules/installer/tools/nixos-enter.sh b/nixos/modules/installer/tools/nixos-enter.sh
index 00883205e8b5..6469d9faa038 100644
--- a/nixos/modules/installer/tools/nixos-enter.sh
+++ b/nixos/modules/installer/tools/nixos-enter.sh
@@ -1,4 +1,5 @@
 #! @runtimeShell@
+# shellcheck shell=bash
 
 set -e
 
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index 7bc55e67134b..fe8c4fb1a6b5 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -91,6 +91,11 @@ sub hasCPUFeature {
 }
 
 
+sub cpuManufacturer {
+    my $id = shift;
+    return $cpuinfo =~ /^vendor_id\s*:.* $id$/m;
+}
+
 
 # Determine CPU governor to use
 if (-e "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") {
@@ -111,6 +116,9 @@ if (-e "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") {
 push @kernelModules, "kvm-intel" if hasCPUFeature "vmx";
 push @kernelModules, "kvm-amd" if hasCPUFeature "svm";
 
+push @attrs, "hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;" if cpuManufacturer "AuthenticAMD";
+push @attrs, "hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;" if cpuManufacturer "GenuineIntel";
+
 
 # Look at the PCI devices and add necessary modules.  Note that most
 # modules are auto-detected so we don't need to list them here.
diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh
index ea9667995e13..fc4a69aa17d3 100644
--- a/nixos/modules/installer/tools/nixos-install.sh
+++ b/nixos/modules/installer/tools/nixos-install.sh
@@ -1,4 +1,5 @@
 #! @runtimeShell@
+# shellcheck shell=bash
 
 set -e
 shopt -s nullglob
@@ -58,7 +59,7 @@ while [ "$#" -gt 0 ]; do
         --no-channel-copy)
             noChannelCopy=1
             ;;
-        --no-root-passwd)
+        --no-root-password|--no-root-passwd)
             noRootPasswd=1
             ;;
         --no-bootloader)
diff --git a/nixos/modules/installer/tools/nixos-version.sh b/nixos/modules/installer/tools/nixos-version.sh
index f5e3f32b3c63..59a9c572b418 100644
--- a/nixos/modules/installer/tools/nixos-version.sh
+++ b/nixos/modules/installer/tools/nixos-version.sh
@@ -1,4 +1,5 @@
 #! @runtimeShell@
+# shellcheck shell=bash
 
 case "$1" in
   -h|--help)
diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix
index c3ded4f1ea34..1f837f9efa22 100644
--- a/nixos/modules/misc/documentation.nix
+++ b/nixos/modules/misc/documentation.nix
@@ -80,6 +80,10 @@ let
       ];
     };
 
+  # list of man outputs currently active intended for use as default values
+  # for man-related options, thus "man" is included unconditionally.
+  activeManOutputs = [ "man" ] ++ lib.optionals cfg.dev.enable [ "devman" ];
+
 in
 
 {
@@ -130,7 +134,7 @@ in
           name = "man-paths";
           paths = config.environment.systemPackages;
           pathsToLink = [ "/share/man" ];
-          extraOutputsToInstall = ["man"];
+          extraOutputsToInstall = activeManOutputs;
           ignoreCollisions = true;
         };
         defaultText = literalDocBook "all man pages in <option>config.environment.systemPackages</option>";
@@ -226,7 +230,7 @@ in
     (mkIf cfg.man.enable {
       environment.systemPackages = [ pkgs.man-db ];
       environment.pathsToLink = [ "/share/man" ];
-      environment.extraOutputsToInstall = [ "man" ] ++ optional cfg.dev.enable "devman";
+      environment.extraOutputsToInstall = activeManOutputs;
       environment.etc."man_db.conf".text =
         let
           manualCache = pkgs.runCommandLocal "man-cache" { } ''
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index f392ca52566f..273ed95e1bce 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -351,6 +351,7 @@ in
       hqplayer = 319;
       moonraker = 320;
       distcc = 321;
+      webdav = 322;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -656,6 +657,7 @@ in
       hqplayer = 319;
       moonraker = 320;
       distcc = 321;
+      webdav = 322;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix
index 2f0f676a0ba3..461a2aa5a946 100644
--- a/nixos/modules/misc/locate.nix
+++ b/nixos/modules/misc/locate.nix
@@ -163,7 +163,7 @@ in {
 
     prunePaths = mkOption {
       type = listOf path;
-      default = ["/tmp" "/var/tmp" "/var/cache" "/var/lock" "/var/run" "/var/spool" "/nix/store"];
+      default = [ "/tmp" "/var/tmp" "/var/cache" "/var/lock" "/var/run" "/var/spool" "/nix/store" "/nix/var/log/nix" ];
       description = ''
         Which paths to exclude from indexing
       '';
@@ -171,7 +171,7 @@ in {
 
     pruneNames = mkOption {
       type = listOf str;
-      default = [];
+      default = [ ".bzr" ".cache" ".git" ".hg" ".svn" ];
       description = ''
         Directory components which should exclude paths containing them from indexing
       '';
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 4ee79b439602..1d51fca02fbf 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -611,6 +611,7 @@
   ./services/misc/uhub.nix
   ./services/misc/weechat.nix
   ./services/misc/xmr-stak.nix
+  ./services/misc/xmrig.nix
   ./services/misc/zigbee2mqtt.nix
   ./services/misc/zoneminder.nix
   ./services/misc/zookeeper.nix
@@ -683,6 +684,8 @@
   ./services/network-filesystems/tahoe.nix
   ./services/network-filesystems/diod.nix
   ./services/network-filesystems/u9fs.nix
+  ./services/network-filesystems/webdav.nix
+  ./services/network-filesystems/webdav-server-rs.nix
   ./services/network-filesystems/yandex-disk.nix
   ./services/network-filesystems/xtreemfs.nix
   ./services/network-filesystems/ceph.nix
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
index 3b67d628f9fd..33dd80d7c5ab 100644
--- a/nixos/modules/profiles/base.nix
+++ b/nixos/modules/profiles/base.nix
@@ -40,6 +40,7 @@
     # Tools to create / manipulate filesystems.
     pkgs.ntfsprogs # for resizing NTFS partitions
     pkgs.dosfstools
+    pkgs.mtools
     pkgs.xfsprogs.bin
     pkgs.jfsutils
     pkgs.f2fs-tools
diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix
index caf329c2536a..c64e01a20cb3 100644
--- a/nixos/modules/programs/sway.nix
+++ b/nixos/modules/programs/sway.nix
@@ -123,6 +123,8 @@ in {
     ];
     environment = {
       systemPackages = [ swayPackage ] ++ cfg.extraPackages;
+      # Needed for the default wallpaper:
+      pathsToLink = [ "/share/backgrounds/sway" ];
       etc = {
         "sway/config".source = mkOptionDefault "${swayPackage}/etc/sway/config";
         "sway/config.d/nixos.conf".source = pkgs.writeText "nixos.conf" ''
diff --git a/nixos/modules/programs/zsh/zsh-autosuggestions.nix b/nixos/modules/programs/zsh/zsh-autosuggestions.nix
index a8fcfff95e59..fee324cc7326 100644
--- a/nixos/modules/programs/zsh/zsh-autosuggestions.nix
+++ b/nixos/modules/programs/zsh/zsh-autosuggestions.nix
@@ -36,6 +36,13 @@ in
       '';
     };
 
+    async = mkOption {
+      type = types.bool;
+      default = true;
+      description = "Whether to fetch suggestions asynchronously";
+      example = false;
+    };
+
     extraConfig = mkOption {
       type = with types; attrsOf str;
       default = {};
@@ -56,6 +63,7 @@ in
 
       export ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="${cfg.highlightStyle}"
       export ZSH_AUTOSUGGEST_STRATEGY=("${cfg.strategy}")
+      ${optionalString (!cfg.async) "unset ZSH_AUTOSUGGEST_USE_ASYNC"}
 
       ${concatStringsSep "\n" (mapAttrsToList (key: value: ''export ${key}="${value}"'') cfg.extraConfig)}
     '';
diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix
index cfbc8e91903e..2815e2593b23 100644
--- a/nixos/modules/security/acme.nix
+++ b/nixos/modules/security/acme.nix
@@ -77,6 +77,7 @@ let
 
     unitConfig = {
       ConditionPathExists = "!/var/lib/acme/.minica/key.pem";
+      StartLimitIntervalSec = 0;
     };
 
     serviceConfig = commonServiceConfig // {
@@ -235,6 +236,7 @@ let
 
       unitConfig = {
         ConditionPathExists = "!/var/lib/acme/${cert}/key.pem";
+        StartLimitIntervalSec = 0;
       };
 
       serviceConfig = commonServiceConfig // {
@@ -314,6 +316,9 @@ let
           if [ -e renewed ]; then
             rm renewed
             ${data.postRun}
+            ${optionalString (data.reloadServices != [])
+                "systemctl --no-block try-reload-or-restart ${escapeShellArgs data.reloadServices}"
+            }
           fi
         '');
       };
@@ -474,6 +479,15 @@ let
         description = "Group running the ACME client.";
       };
 
+      reloadServices = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          The list of systemd services to call <code>systemctl try-reload-or-restart</code>
+          on.
+        '';
+      };
+
       postRun = mkOption {
         type = types.lines;
         default = "";
diff --git a/nixos/modules/security/acme.xml b/nixos/modules/security/acme.xml
index 8249da948c6d..bf93800a0af4 100644
--- a/nixos/modules/security/acme.xml
+++ b/nixos/modules/security/acme.xml
@@ -253,7 +253,7 @@ chmod 400 /var/lib/secrets/certs.secret
 </programlisting>
 
   <para>
-   Now you're all set to generate certs! You should monitor the first invokation
+   Now you're all set to generate certs! You should monitor the first invocation
    by running <literal>systemctl start acme-example.com.service &amp;
    journalctl -fu acme-example.com.service</literal> and watching its log output.
   </para>
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 40df6c67ef84..b03bf290fd23 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -401,6 +401,9 @@ let
 
     };
 
+    # The resulting /etc/pam.d/* file contents are verified in
+    # nixos/tests/pam/pam-file-contents.nix. Please update tests there when
+    # changing the derivation.
     config = {
       name = mkDefault name;
       setLoginUid = mkDefault cfg.startSession;
@@ -410,46 +413,64 @@ let
       # Samba stuff to the Samba module.  This requires that the PAM
       # module provides the right hooks.
       text = mkDefault
-        (''
-          # Account management.
-          account required pam_unix.so
-          ${optionalString use_ldap
-              "account sufficient ${pam_ldap}/lib/security/pam_ldap.so"}
-          ${optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false)
-              "account sufficient ${pkgs.sssd}/lib/security/pam_sss.so"}
-          ${optionalString (config.services.sssd.enable && cfg.sssdStrictAccess)
-              "account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so"}
-          ${optionalString config.krb5.enable
-              "account sufficient ${pam_krb5}/lib/security/pam_krb5.so"}
-          ${optionalString cfg.googleOsLoginAccountVerification ''
+        (
+          ''
+            # Account management.
+            account required pam_unix.so
+          '' +
+          optionalString use_ldap ''
+            account sufficient ${pam_ldap}/lib/security/pam_ldap.so
+          '' +
+          optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false) ''
+            account sufficient ${pkgs.sssd}/lib/security/pam_sss.so
+          '' +
+          optionalString (config.services.sssd.enable && cfg.sssdStrictAccess) ''
+            account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so
+          '' +
+          optionalString config.krb5.enable ''
+            account sufficient ${pam_krb5}/lib/security/pam_krb5.so
+          '' +
+          optionalString cfg.googleOsLoginAccountVerification ''
             account [success=ok ignore=ignore default=die] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so
             account [success=ok default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so
-          ''}
-
-          # Authentication management.
-          ${optionalString cfg.googleOsLoginAuthentication
-              "auth [success=done perm_denied=bad default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so"}
-          ${optionalString cfg.rootOK
-              "auth sufficient pam_rootok.so"}
-          ${optionalString cfg.requireWheel
-              "auth required pam_wheel.so use_uid"}
-          ${optionalString cfg.logFailures
-              "auth required pam_faillock.so"}
-          ${optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth)
-              "auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles}"}
-          ${let p11 = config.security.pam.p11; in optionalString cfg.p11Auth
-              "auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so"}
-          ${let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth
-              "auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"} ${optionalString (u2f.appId != null) "appid=${u2f.appId}"}"}
-          ${optionalString cfg.usbAuth
-              "auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"}
-          ${let oath = config.security.pam.oath; in optionalString cfg.oathAuth
-              "auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}"}
-          ${let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth
-              "auth ${yubi.control} ${pkgs.yubico-pam}/lib/security/pam_yubico.so mode=${toString yubi.mode} ${optionalString (yubi.challengeResponsePath != null) "chalresp_path=${yubi.challengeResponsePath}"} ${optionalString (yubi.mode == "client") "id=${toString yubi.id}"} ${optionalString yubi.debug "debug"}"}
-          ${optionalString cfg.fprintAuth
-              "auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so"}
-        '' +
+          '' +
+          ''
+
+            # Authentication management.
+          '' +
+          optionalString cfg.googleOsLoginAuthentication ''
+            auth [success=done perm_denied=bad default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so
+          '' +
+          optionalString cfg.rootOK ''
+            auth sufficient pam_rootok.so
+          '' +
+          optionalString cfg.requireWheel ''
+            auth required pam_wheel.so use_uid
+          '' +
+          optionalString cfg.logFailures ''
+            auth required pam_faillock.so
+          '' +
+          optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) ''
+            auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles}
+          '' +
+          (let p11 = config.security.pam.p11; in optionalString cfg.p11Auth ''
+            auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so
+          '') +
+          (let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth ''
+            auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"} ${optionalString (u2f.appId != null) "appid=${u2f.appId}"}
+          '') +
+          optionalString cfg.usbAuth ''
+            auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so
+          '' +
+          (let oath = config.security.pam.oath; in optionalString cfg.oathAuth ''
+            auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}
+          '') +
+          (let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth ''
+            auth ${yubi.control} ${pkgs.yubico-pam}/lib/security/pam_yubico.so mode=${toString yubi.mode} ${optionalString (yubi.challengeResponsePath != null) "chalresp_path=${yubi.challengeResponsePath}"} ${optionalString (yubi.mode == "client") "id=${toString yubi.id}"} ${optionalString yubi.debug "debug"}
+          '') +
+          optionalString cfg.fprintAuth ''
+            auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so
+          '' +
           # Modules in this block require having the password set in PAM_AUTHTOK.
           # pam_unix is marked as 'sufficient' on NixOS which means nothing will run
           # after it succeeds. Certain modules need to run after pam_unix
@@ -457,115 +478,151 @@ let
           # earlier point and it will run again with 'sufficient' further down.
           # We use try_first_pass the second time to avoid prompting password twice
           (optionalString (cfg.unixAuth &&
-          (config.security.pam.enableEcryptfs
-            || cfg.pamMount
-            || cfg.enableKwallet
-            || cfg.enableGnomeKeyring
-            || cfg.googleAuthenticator.enable
-            || cfg.gnupg.enable
-            || cfg.duoSecurity.enable)) ''
-              auth required pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth
-              ${optionalString config.security.pam.enableEcryptfs
-                "auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"}
-              ${optionalString cfg.pamMount
-                "auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive"}
-              ${optionalString cfg.enableKwallet
-                ("auth optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so" +
-                 " kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5")}
-              ${optionalString cfg.enableGnomeKeyring
-                "auth optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so"}
-              ${optionalString cfg.gnupg.enable
-                "auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"
-                + optionalString cfg.gnupg.storeOnly " store-only"
-               }
-              ${optionalString cfg.googleAuthenticator.enable
-                "auth required ${pkgs.googleAuthenticator}/lib/security/pam_google_authenticator.so no_increment_hotp"}
-              ${optionalString cfg.duoSecurity.enable
-                "auth required ${pkgs.duo-unix}/lib/security/pam_duo.so"}
-            '') + ''
-          ${optionalString cfg.unixAuth
-              "auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth try_first_pass"}
-          ${optionalString cfg.otpwAuth
-              "auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so"}
-          ${optionalString use_ldap
-              "auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass"}
-          ${optionalString config.services.sssd.enable
-              "auth sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_first_pass"}
-          ${optionalString config.krb5.enable ''
+            (config.security.pam.enableEcryptfs
+              || cfg.pamMount
+              || cfg.enableKwallet
+              || cfg.enableGnomeKeyring
+              || cfg.googleAuthenticator.enable
+              || cfg.gnupg.enable
+              || cfg.duoSecurity.enable))
+            (
+              ''
+                auth required pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth
+              '' +
+              optionalString config.security.pam.enableEcryptfs ''
+                auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap
+              '' +
+              optionalString cfg.pamMount ''
+                auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
+              '' +
+              optionalString cfg.enableKwallet ''
+               auth optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
+              '' +
+              optionalString cfg.enableGnomeKeyring ''
+                auth optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so
+              '' +
+              optionalString cfg.gnupg.enable ''
+                auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"}
+              '' +
+              optionalString cfg.googleAuthenticator.enable ''
+                auth required ${pkgs.googleAuthenticator}/lib/security/pam_google_authenticator.so no_increment_hotp
+              '' +
+              optionalString cfg.duoSecurity.enable ''
+                auth required ${pkgs.duo-unix}/lib/security/pam_duo.so
+              ''
+            )) +
+          optionalString cfg.unixAuth ''
+            auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth try_first_pass
+          '' +
+          optionalString cfg.otpwAuth ''
+            auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so
+          '' +
+          optionalString use_ldap ''
+            auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass
+          '' +
+          optionalString config.services.sssd.enable ''
+            auth sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_first_pass
+          '' +
+          optionalString config.krb5.enable ''
             auth [default=ignore success=1 service_err=reset] ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
             auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass
             auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass
-          ''}
-          auth required pam_deny.so
-
-          # Password management.
-          password sufficient pam_unix.so nullok sha512
-          ${optionalString config.security.pam.enableEcryptfs
-              "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
-          ${optionalString cfg.pamMount
-              "password optional ${pkgs.pam_mount}/lib/security/pam_mount.so"}
-          ${optionalString use_ldap
-              "password sufficient ${pam_ldap}/lib/security/pam_ldap.so"}
-          ${optionalString config.services.sssd.enable
-              "password sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_authtok"}
-          ${optionalString config.krb5.enable
-              "password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass"}
-          ${optionalString cfg.enableGnomeKeyring
-              "password optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so use_authtok"}
-
-          # Session management.
-          ${optionalString cfg.setEnvironment ''
+          '' +
+          ''
+            auth required pam_deny.so
+
+            # Password management.
+            password sufficient pam_unix.so nullok sha512
+          '' +
+          optionalString config.security.pam.enableEcryptfs ''
+            password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
+          '' +
+          optionalString cfg.pamMount ''
+            password optional ${pkgs.pam_mount}/lib/security/pam_mount.so
+          '' +
+          optionalString use_ldap ''
+            password sufficient ${pam_ldap}/lib/security/pam_ldap.so
+          '' +
+          optionalString config.services.sssd.enable ''
+            password sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_authtok
+          '' +
+          optionalString config.krb5.enable ''
+            password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
+          '' +
+          optionalString cfg.enableGnomeKeyring ''
+            password optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so use_authtok
+          '' +
+          ''
+
+            # Session management.
+          '' +
+          optionalString cfg.setEnvironment ''
             session required pam_env.so conffile=/etc/pam/environment readenv=0
-          ''}
-          session required pam_unix.so
-          ${optionalString cfg.setLoginUid
-              "session ${
-                if config.boot.isContainer then "optional" else "required"
-              } pam_loginuid.so"}
-          ${optionalString cfg.ttyAudit.enable
-              "session required ${pkgs.pam}/lib/security/pam_tty_audit.so
+          '' +
+          ''
+            session required pam_unix.so
+          '' +
+          optionalString cfg.setLoginUid ''
+            session ${if config.boot.isContainer then "optional" else "required"} pam_loginuid.so
+          '' +
+          optionalString cfg.ttyAudit.enable ''
+            session required ${pkgs.pam}/lib/security/pam_tty_audit.so
                 open_only=${toString cfg.ttyAudit.openOnly}
                 ${optionalString (cfg.ttyAudit.enablePattern != null) "enable=${cfg.ttyAudit.enablePattern}"}
                 ${optionalString (cfg.ttyAudit.disablePattern != null) "disable=${cfg.ttyAudit.disablePattern}"}
-              "}
-          ${optionalString cfg.makeHomeDir
-              "session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=${config.security.pam.makeHomeDir.skelDirectory} umask=0077"}
-          ${optionalString cfg.updateWtmp
-              "session required ${pkgs.pam}/lib/security/pam_lastlog.so silent"}
-          ${optionalString config.security.pam.enableEcryptfs
-              "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
-          ${optionalString cfg.pamMount
-              "session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive"}
-          ${optionalString use_ldap
-              "session optional ${pam_ldap}/lib/security/pam_ldap.so"}
-          ${optionalString config.services.sssd.enable
-              "session optional ${pkgs.sssd}/lib/security/pam_sss.so"}
-          ${optionalString config.krb5.enable
-              "session optional ${pam_krb5}/lib/security/pam_krb5.so"}
-          ${optionalString cfg.otpwAuth
-              "session optional ${pkgs.otpw}/lib/security/pam_otpw.so"}
-          ${optionalString cfg.startSession
-              "session optional ${pkgs.systemd}/lib/security/pam_systemd.so"}
-          ${optionalString cfg.forwardXAuth
-              "session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99"}
-          ${optionalString (cfg.limits != [])
-              "session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}"}
-          ${optionalString (cfg.showMotd && config.users.motd != null)
-              "session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}"}
-          ${optionalString (cfg.enableAppArmor && config.security.apparmor.enable)
-              "session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug"}
-          ${optionalString (cfg.enableKwallet)
-              ("session optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so" +
-               " kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5")}
-          ${optionalString (cfg.enableGnomeKeyring)
-              "session optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start"}
-          ${optionalString cfg.gnupg.enable
-              "session optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"
-              + optionalString cfg.gnupg.noAutostart " no-autostart"
-           }
-          ${optionalString (config.virtualisation.lxc.lxcfs.enable)
-               "session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all"}
-        '');
+          '' +
+          optionalString cfg.makeHomeDir ''
+            session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=${config.security.pam.makeHomeDir.skelDirectory} umask=0077
+          '' +
+          optionalString cfg.updateWtmp ''
+            session required ${pkgs.pam}/lib/security/pam_lastlog.so silent
+          '' +
+          optionalString config.security.pam.enableEcryptfs ''
+            session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
+          '' +
+          optionalString cfg.pamMount ''
+            session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
+          '' +
+          optionalString use_ldap ''
+            session optional ${pam_ldap}/lib/security/pam_ldap.so
+          '' +
+          optionalString config.services.sssd.enable ''
+            session optional ${pkgs.sssd}/lib/security/pam_sss.so
+          '' +
+          optionalString config.krb5.enable ''
+            session optional ${pam_krb5}/lib/security/pam_krb5.so
+          '' +
+          optionalString cfg.otpwAuth ''
+            session optional ${pkgs.otpw}/lib/security/pam_otpw.so
+          '' +
+          optionalString cfg.startSession ''
+            session optional ${pkgs.systemd}/lib/security/pam_systemd.so
+          '' +
+          optionalString cfg.forwardXAuth ''
+            session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99
+          '' +
+          optionalString (cfg.limits != []) ''
+            session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}
+          '' +
+          optionalString (cfg.showMotd && config.users.motd != null) ''
+            session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}
+          '' +
+          optionalString (cfg.enableAppArmor && config.security.apparmor.enable) ''
+            session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug
+          '' +
+          optionalString (cfg.enableKwallet) ''
+            session optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
+          '' +
+          optionalString (cfg.enableGnomeKeyring) ''
+            session optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start
+          '' +
+          optionalString cfg.gnupg.enable ''
+            session optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.noAutostart " no-autostart"}
+          '' +
+          optionalString (config.virtualisation.lxc.lxcfs.enable) ''
+            session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all
+          ''
+        );
     };
 
   };
diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix
index 220c571b927e..b2147c1bbfc9 100644
--- a/nixos/modules/services/backup/borgbackup.nix
+++ b/nixos/modules/services/backup/borgbackup.nix
@@ -152,6 +152,7 @@ let
       serviceConfig = {
         # The service's only task is to ensure that the specified path exists
         Type = "oneshot";
+        WorkingDirectory = cfg.path;
       };
       wantedBy = [ "multi-user.target" ];
     };
diff --git a/nixos/modules/services/continuous-integration/hercules-ci-agent/common.nix b/nixos/modules/services/continuous-integration/hercules-ci-agent/common.nix
index d53d68bdcf97..80c88714bfc1 100644
--- a/nixos/modules/services/continuous-integration/hercules-ci-agent/common.nix
+++ b/nixos/modules/services/continuous-integration/hercules-ci-agent/common.nix
@@ -1,10 +1,10 @@
 /*
 
-This file is for options that NixOS and nix-darwin have in common.
+  This file is for options that NixOS and nix-darwin have in common.
 
-Platform-specific code is in the respective default.nix files.
+  Platform-specific code is in the respective default.nix files.
 
- */
+*/
 
 { config, lib, options, pkgs, ... }:
 let
@@ -27,6 +27,16 @@ let
   settingsModule = { config, ... }: {
     freeformType = format.type;
     options = {
+      apiBaseUrl = mkOption {
+        description = ''
+          API base URL that the agent will connect to.
+
+          When using Hercules CI Enterprise, set this to the URL where your
+          Hercules CI server is reachable.
+        '';
+        type = types.str;
+        default = "https://hercules-ci.com";
+      };
       baseDirectory = mkOption {
         type = types.path;
         default = "/var/lib/hercules-ci-agent";
@@ -55,6 +65,25 @@ let
         type = types.either types.ints.positive (types.enum [ "auto" ]);
         default = "auto";
       };
+      labels = mkOption {
+        description = ''
+          A key-value map of user data.
+
+          This data will be available to organization members in the dashboard and API.
+
+          The values can be of any TOML type that corresponds to a JSON type, but arrays
+          can not contain tables/objects due to limitations of the TOML library. Values
+          involving arrays of non-primitive types may not be representable currently.
+        '';
+        type = format.type;
+        defaultText = literalExpression ''
+          {
+            agent.source = "..."; # One of "nixpkgs", "flake", "override"
+            lib.version = "...";
+            pkgs.version = "...";
+          }
+        '';
+      };
       workDirectory = mkOption {
         description = ''
           The directory in which temporary subdirectories are created for task state. This includes sources for Nix evaluation.
@@ -66,6 +95,8 @@ let
       staticSecretsDirectory = mkOption {
         description = ''
           This is the default directory to look for statically configured secrets like <literal>cluster-join-token.key</literal>.
+
+          See also <literal>clusterJoinTokenPath</literal> and <literal>binaryCachesPath</literal> for fine-grained configuration.
         '';
         type = types.path;
         default = config.baseDirectory + "/secrets";
@@ -74,24 +105,48 @@ let
       clusterJoinTokenPath = mkOption {
         description = ''
           Location of the cluster-join-token.key file.
+
+          You can retrieve the contents of the file when creating a new agent via
+          <link xlink:href="https://hercules-ci.com/dashboard">https://hercules-ci.com/dashboard</link>.
+
+          As this value is confidential, it should not be in the store, but
+          installed using other means, such as agenix, NixOps
+          <literal>deployment.keys</literal>, or manual installation.
+
+          The contents of the file are used for authentication between the agent and the API.
         '';
         type = types.path;
         default = config.staticSecretsDirectory + "/cluster-join-token.key";
         defaultText = literalExpression ''staticSecretsDirectory + "/cluster-join-token.key"'';
-        # internal: It's a bit too detailed to show by default in the docs,
-        # but useful to define explicitly to allow reuse by other modules.
-        internal = true;
       };
       binaryCachesPath = mkOption {
         description = ''
-          Location of the binary-caches.json file.
+          Path to a JSON file containing binary cache secret keys.
+
+          As these values are confidential, they should not be in the store, but
+          copied over using other means, such as agenix, NixOps
+          <literal>deployment.keys</literal>, or manual installation.
+
+          The format is described on <link xlink:href="https://docs.hercules-ci.com/hercules-ci-agent/binary-caches-json/">https://docs.hercules-ci.com/hercules-ci-agent/binary-caches-json/</link>.
         '';
         type = types.path;
         default = config.staticSecretsDirectory + "/binary-caches.json";
         defaultText = literalExpression ''staticSecretsDirectory + "/binary-caches.json"'';
-        # internal: It's a bit too detailed to show by default in the docs,
-        # but useful to define explicitly to allow reuse by other modules.
-        internal = true;
+      };
+      secretsJsonPath = mkOption {
+        description = ''
+          Path to a JSON file containing secrets for effects.
+
+          As these values are confidential, they should not be in the store, but
+          copied over using other means, such as agenix, NixOps
+          <literal>deployment.keys</literal>, or manual installation.
+
+          The format is described on <link xlink:href="https://docs.hercules-ci.com/hercules-ci-agent/secrets-json/">https://docs.hercules-ci.com/hercules-ci-agent/secrets-json/</link>.
+
+        '';
+        type = types.path;
+        default = config.staticSecretsDirectory + "/secrets.json";
+        defaultText = literalExpression ''staticSecretsDirectory + "/secrets.json"'';
       };
     };
   };
@@ -177,7 +232,7 @@ in
 
       These are written as options instead of let binding to allow sharing with
       default.nix on both NixOS and nix-darwin.
-     */
+    */
     tomlFile = mkOption {
       type = types.path;
       internal = true;
diff --git a/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix b/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix
index 06c174e7d376..968bc8f1e54e 100644
--- a/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix
+++ b/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix
@@ -1,10 +1,10 @@
 /*
 
-This file is for NixOS-specific options and configs.
+  This file is for NixOS-specific options and configs.
 
-Code that is shared with nix-darwin goes in common.nix.
+  Code that is shared with nix-darwin goes in common.nix.
 
- */
+*/
 
 { pkgs, config, lib, ... }:
 let
diff --git a/nixos/modules/services/databases/clickhouse.nix b/nixos/modules/services/databases/clickhouse.nix
index f2f4e9d25542..3a161d56107e 100644
--- a/nixos/modules/services/databases/clickhouse.nix
+++ b/nixos/modules/services/databases/clickhouse.nix
@@ -13,6 +13,15 @@ with lib;
 
       enable = mkEnableOption "ClickHouse database server";
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.clickhouse;
+        defaultText = "pkgs.clickhouse";
+        description = ''
+          ClickHouse package to use.
+        '';
+      };
+
     };
 
   };
@@ -45,21 +54,21 @@ with lib;
         AmbientCapabilities = "CAP_SYS_NICE";
         StateDirectory = "clickhouse";
         LogsDirectory = "clickhouse";
-        ExecStart = "${pkgs.clickhouse}/bin/clickhouse-server --config-file=${pkgs.clickhouse}/etc/clickhouse-server/config.xml";
+        ExecStart = "${cfg.package}/bin/clickhouse-server --config-file=${cfg.package}/etc/clickhouse-server/config.xml";
       };
     };
 
     environment.etc = {
       "clickhouse-server/config.xml" = {
-        source = "${pkgs.clickhouse}/etc/clickhouse-server/config.xml";
+        source = "${cfg.package}/etc/clickhouse-server/config.xml";
       };
 
       "clickhouse-server/users.xml" = {
-        source = "${pkgs.clickhouse}/etc/clickhouse-server/users.xml";
+        source = "${cfg.package}/etc/clickhouse-server/users.xml";
       };
     };
 
-    environment.systemPackages = [ pkgs.clickhouse ];
+    environment.systemPackages = [ cfg.package ];
 
     # startup requires a `/etc/localtime` which only if exists if `time.timeZone != null`
     time.timeZone = mkDefault "UTC";
diff --git a/nixos/modules/services/databases/hbase.nix b/nixos/modules/services/databases/hbase.nix
index ff01a1bcd98b..181be2d6b0b8 100644
--- a/nixos/modules/services/databases/hbase.nix
+++ b/nixos/modules/services/databases/hbase.nix
@@ -5,18 +5,27 @@ with lib;
 let
   cfg = config.services.hbase;
 
-  configFile = pkgs.writeText "hbase-site.xml" ''
-    <configuration>
-      <property>
-        <name>hbase.rootdir</name>
-        <value>file://${cfg.dataDir}/hbase</value>
-      </property>
-      <property>
-        <name>hbase.zookeeper.property.dataDir</name>
-        <value>${cfg.dataDir}/zookeeper</value>
-      </property>
-    </configuration>
-  '';
+  defaultConfig = {
+    "hbase.rootdir" = "file://${cfg.dataDir}/hbase";
+    "hbase.zookeeper.property.dataDir" = "${cfg.dataDir}/zookeeper";
+  };
+
+  buildProperty = configAttr:
+    (builtins.concatStringsSep "\n"
+      (lib.mapAttrsToList
+        (name: value: ''
+          <property>
+            <name>${name}</name>
+            <value>${builtins.toString value}</value>
+          </property>
+        '')
+        configAttr));
+
+  configFile = pkgs.writeText "hbase-site.xml"
+    ''<configuration>
+        ${buildProperty (defaultConfig // cfg.settings)}
+      </configuration>
+    '';
 
   configDir = pkgs.runCommand "hbase-config-dir" { preferLocalBuild = true; } ''
     mkdir -p $out
@@ -85,6 +94,14 @@ in {
         '';
       };
 
+      settings = mkOption {
+        type = with lib.types; attrsOf (oneOf [ str int bool ]);
+        default = defaultConfig;
+        description = ''
+          configurations in hbase-site.xml, see <link xlink:href="https://github.com/apache/hbase/blob/master/hbase-server/src/test/resources/hbase-site.xml"/> for details.
+        '';
+      };
+
     };
 
   };
diff --git a/nixos/modules/services/hardware/bluetooth.nix b/nixos/modules/services/hardware/bluetooth.nix
index 7f75ac272d40..69a66723e76c 100644
--- a/nixos/modules/services/hardware/bluetooth.nix
+++ b/nixos/modules/services/hardware/bluetooth.nix
@@ -11,12 +11,8 @@ let
 
   cfgFmt = pkgs.formats.ini { };
 
-  # bluez will complain if some of the sections are not found, so just make them
-  # empty (but present in the file) for now
   defaults = {
     General.ControllerMode = "dual";
-    Controller = { };
-    GATT = { };
     Policy.AutoEnable = cfg.powerOnBoot;
   };
 
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
index 624b6cfb1215..ba5d6e29d0bd 100644
--- a/nixos/modules/services/logging/logrotate.nix
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -40,7 +40,7 @@ let
       };
 
       frequency = mkOption {
-        type = types.enum [ "daily" "weekly" "monthly" "yearly" ];
+        type = types.enum [ "hourly" "daily" "weekly" "monthly" "yearly" ];
         default = "daily";
         description = ''
           How often to rotate the logs.
@@ -155,7 +155,7 @@ in
     systemd.services.logrotate = {
       description = "Logrotate Service";
       wantedBy = [ "multi-user.target" ];
-      startAt = "*-*-* *:05:00";
+      startAt = "hourly";
       script = ''
         exec ${pkgs.logrotate}/sbin/logrotate ${configFile}
       '';
diff --git a/nixos/modules/services/logging/logstash.nix b/nixos/modules/services/logging/logstash.nix
index 044d5330231e..a08203dffe78 100644
--- a/nixos/modules/services/logging/logstash.nix
+++ b/nixos/modules/services/logging/logstash.nix
@@ -23,12 +23,16 @@ let
 
   logstashSettingsYml = pkgs.writeText "logstash.yml" cfg.extraSettings;
 
+  logstashJvmOptionsFile = pkgs.writeText "jvm.options" cfg.extraJvmOptions;
+
   logstashSettingsDir = pkgs.runCommand "logstash-settings" {
+      inherit logstashJvmOptionsFile;
       inherit logstashSettingsYml;
       preferLocalBuild = true;
     } ''
     mkdir -p $out
     ln -s $logstashSettingsYml $out/logstash.yml
+    ln -s $logstashJvmOptionsFile $out/jvm.options
   '';
 in
 
@@ -152,6 +156,15 @@ in
         '';
       };
 
+      extraJvmOptions = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Extra JVM options, one per line (jvm.options format).";
+        example = ''
+          -Xms2g
+          -Xmx2g
+        '';
+      };
 
     };
   };
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index 223f3bef77db..c39827c5b867 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -103,11 +103,12 @@ let
 
         plugin {
           quota_rule = *:storage=${cfg.quotaGlobalPerUser}
-          quota = maildir:User quota # per virtual mail user quota # BUG/FIXME broken, we couldn't get this working
+          quota = count:User quota # per virtual mail user quota
           quota_status_success = DUNNO
           quota_status_nouser = DUNNO
           quota_status_overquota = "552 5.2.2 Mailbox is full"
           quota_grace = 10%%
+          quota_vsizes = yes
         }
       ''
     )
diff --git a/nixos/modules/services/matrix/mjolnir.nix b/nixos/modules/services/matrix/mjolnir.nix
index 8a54f93d98d8..278924b05cf2 100644
--- a/nixos/modules/services/matrix/mjolnir.nix
+++ b/nixos/modules/services/matrix/mjolnir.nix
@@ -14,6 +14,8 @@ let
       else
         cfg.homeserverUrl;
 
+    rawHomeserverUrl = cfg.homeserverUrl;
+
     pantalaimon = {
       inherit (cfg.pantalaimon) username;
 
diff --git a/nixos/modules/services/misc/gollum.nix b/nixos/modules/services/misc/gollum.nix
index 4053afa69be5..cad73a871ba6 100644
--- a/nixos/modules/services/misc/gollum.nix
+++ b/nixos/modules/services/misc/gollum.nix
@@ -100,6 +100,7 @@ in
       serviceConfig = {
         User = config.users.users.gollum.name;
         Group = config.users.groups.gollum.name;
+        WorkingDirectory = cfg.stateDir;
         ExecStart = ''
           ${pkgs.gollum}/bin/gollum \
             --port ${toString cfg.port} \
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 4ea45888e5fc..fb643e7a66e1 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -74,6 +74,8 @@ in
   imports = [
     (mkRenamedOptionModule [ "nix" "useChroot" ] [ "nix" "useSandbox" ])
     (mkRenamedOptionModule [ "nix" "chrootDirs" ] [ "nix" "sandboxPaths" ])
+    (mkRenamedOptionModule [ "nix" "daemonIONiceLevel" ] [ "nix" "daemonIOSchedPriority" ])
+    (mkRemovedOptionModule [ "nix" "daemonNiceLevel" ] "Consider nix.daemonCPUSchedPolicy instead.")
   ];
 
   ###### interface
@@ -546,7 +548,7 @@ in
       [ nix
         pkgs.nix-info
       ]
-      ++ optional (config.programs.bash.enableCompletion && !versionAtLeast nixVersion "2.4pre") pkgs.nix-bash-completions;
+      ++ optional (config.programs.bash.enableCompletion) pkgs.nix-bash-completions;
 
     environment.etc."nix/nix.conf".source = nixConf;
 
diff --git a/nixos/modules/services/misc/xmrig.nix b/nixos/modules/services/misc/xmrig.nix
index 15c7d2a7b14c..cf01bb119e89 100644
--- a/nixos/modules/services/misc/xmrig.nix
+++ b/nixos/modules/services/misc/xmrig.nix
@@ -51,6 +51,8 @@ with lib;
   };
 
   config = mkIf cfg.enable {
+    boot.kernelModules = [ "msr" ];
+
     systemd.services.xmrig = {
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
@@ -58,14 +60,16 @@ with lib;
       serviceConfig = {
         ExecStartPre = "${cfg.package}/bin/xmrig --config=${configFile} --dry-run";
         ExecStart = "${cfg.package}/bin/xmrig --config=${configFile}";
-        DynamicUser = true;
+        # https://xmrig.com/docs/miner/randomx-optimization-guide/msr
+        # If you use recent XMRig with root privileges (Linux) or admin
+        # privileges (Windows) the miner configure all MSR registers
+        # automatically.
+        DynamicUser = lib.mkDefault false;
       };
     };
   };
 
   meta = with lib; {
-    description = "XMRig Mining Software Service";
-    license = licenses.gpl3Only;
     maintainers = with maintainers; [ ratsclub ];
   };
 }
diff --git a/nixos/modules/services/monitoring/cadvisor.nix b/nixos/modules/services/monitoring/cadvisor.nix
index da051dbe4655..dfbf07efcaea 100644
--- a/nixos/modules/services/monitoring/cadvisor.nix
+++ b/nixos/modules/services/monitoring/cadvisor.nix
@@ -111,6 +111,8 @@ in {
         wantedBy = [ "multi-user.target" ];
         after = [ "network.target" "docker.service" "influxdb.service" ];
 
+        path = optionals config.boot.zfs.enabled [ pkgs.zfs ];
+
         postStart = mkBefore ''
           until ${pkgs.curl.bin}/bin/curl -s -o /dev/null 'http://${cfg.listenAddress}:${toString cfg.port}/containers/'; do
             sleep 1;
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix b/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix
index 5ee8c346be1d..3cdd7866bd4d 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix
@@ -47,7 +47,7 @@ in
       ExecStart = ''
         ${pkgs.prometheus-nginx-exporter}/bin/nginx-prometheus-exporter \
           --nginx.scrape-uri '${cfg.scrapeUri}' \
-          --nginx.ssl-verify ${toString cfg.sslVerify} \
+          --nginx.ssl-verify ${boolToString cfg.sslVerify} \
           --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
           --web.telemetry-path ${cfg.telemetryPath} \
           --prometheus.const-labels ${concatStringsSep "," cfg.constLabels} \
diff --git a/nixos/modules/services/monitoring/zabbix-server.nix b/nixos/modules/services/monitoring/zabbix-server.nix
index 9b0fd9dbff13..0141c073da25 100644
--- a/nixos/modules/services/monitoring/zabbix-server.nix
+++ b/nixos/modules/services/monitoring/zabbix-server.nix
@@ -250,7 +250,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-server = {
diff --git a/nixos/modules/services/network-filesystems/webdav-server-rs.nix b/nixos/modules/services/network-filesystems/webdav-server-rs.nix
new file mode 100644
index 000000000000..1c5c299cb673
--- /dev/null
+++ b/nixos/modules/services/network-filesystems/webdav-server-rs.nix
@@ -0,0 +1,144 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.services.webdav-server-rs;
+  format = pkgs.formats.toml { };
+  settings = recursiveUpdate
+    {
+      server.uid = config.users.users."${cfg.user}".uid;
+      server.gid = config.users.groups."${cfg.group}".gid;
+    }
+    cfg.settings;
+in
+{
+  options = {
+    services.webdav-server-rs = {
+      enable = mkEnableOption "WebDAV server";
+
+      user = mkOption {
+        type = types.str;
+        default = "webdav";
+        description = "User to run under when setuid is not enabled.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "webdav";
+        description = "Group to run under when setuid is not enabled.";
+      };
+
+      settings = mkOption {
+        type = format.type;
+        default = { };
+        description = ''
+          Attrset that is converted and passed as config file. Available
+          options can be found at
+          <link xlink:href="https://github.com/miquels/webdav-server-rs/blob/master/webdav-server.toml">here</link>.
+        '';
+        example = literalExpression ''
+          {
+            server.listen = [ "0.0.0.0:4918" "[::]:4918" ];
+            accounts = {
+              auth-type = "htpasswd.default";
+              acct-type = "unix";
+            };
+            htpasswd.default = {
+              htpasswd = "/etc/htpasswd";
+            };
+            location = [
+              {
+                route = [ "/public/*path" ];
+                directory = "/srv/public";
+                handler = "filesystem";
+                methods = [ "webdav-ro" ];
+                autoindex = true;
+                auth = "false";
+              }
+              {
+                route = [ "/user/:user/*path" ];
+                directory = "~";
+                handler = "filesystem";
+                methods = [ "webdav-rw" ];
+                autoindex = true;
+                auth = "true";
+                setuid = true;
+              }
+            ];
+          }
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.path;
+        default = format.generate "webdav-server.toml" settings;
+        defaultText = "Config file generated from services.webdav-server-rs.settings";
+        description = ''
+          Path to config file. If this option is set, it will override any
+          configuration done in services.webdav-server-rs.settings.
+        '';
+        example = "/etc/webdav-server.toml";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    assertions = [
+      {
+        assertion = hasAttr cfg.user config.users.users && config.users.users."${cfg.user}".uid != null;
+        message = "users.users.${cfg.user} and users.users.${cfg.user}.uid must be defined.";
+      }
+      {
+        assertion = hasAttr cfg.group config.users.groups && config.users.groups."${cfg.group}".gid != null;
+        message = "users.groups.${cfg.group} and users.groups.${cfg.group}.gid must be defined.";
+      }
+    ];
+
+    users.users = optionalAttrs (cfg.user == "webdav") {
+      webdav = {
+        description = "WebDAV user";
+        group = cfg.group;
+        uid = config.ids.uids.webdav;
+      };
+    };
+
+    users.groups = optionalAttrs (cfg.group == "webdav") {
+      webdav.gid = config.ids.gids.webdav;
+    };
+
+    systemd.services.webdav-server-rs = {
+      description = "WebDAV server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = "${pkgs.webdav-server-rs}/bin/webdav-server -c ${cfg.configFile}";
+
+        CapabilityBoundingSet = [
+          "CAP_SETUID"
+          "CAP_SETGID"
+        ];
+
+        NoExecPaths = [ "/" ];
+        ExecPaths = [ "/nix/store" ];
+
+        # This program actively detects if it is running in root user account
+        # when it starts and uses root privilege to switch process uid to
+        # respective unix user when a user logs in.  Maybe we can enable
+        # DynamicUser in the future when it's able to detect CAP_SETUID and
+        # CAP_SETGID capabilities.
+
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateTmp = true;
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectSystem = true;
+      };
+    };
+  };
+
+  meta.maintainers = with maintainers; [ pmy ];
+}
diff --git a/nixos/modules/services/network-filesystems/webdav.nix b/nixos/modules/services/network-filesystems/webdav.nix
new file mode 100644
index 000000000000..a810af40fd47
--- /dev/null
+++ b/nixos/modules/services/network-filesystems/webdav.nix
@@ -0,0 +1,107 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.services.webdav;
+  format = pkgs.formats.yaml { };
+in
+{
+  options = {
+    services.webdav = {
+      enable = mkEnableOption "WebDAV server";
+
+      user = mkOption {
+        type = types.str;
+        default = "webdav";
+        description = "User account under which WebDAV runs.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "webdav";
+        description = "Group under which WebDAV runs.";
+      };
+
+      settings = mkOption {
+        type = format.type;
+        default = { };
+        description = ''
+          Attrset that is converted and passed as config file. Available options
+          can be found at
+          <link xlink:href="https://github.com/hacdias/webdav">here</link>.
+
+          This program supports reading username and password configuration
+          from environment variables, so it's strongly recommended to store
+          username and password in a separate
+          <link xlink:href="https://www.freedesktop.org/software/systemd/man/systemd.exec.html#EnvironmentFile=">EnvironmentFile</link>.
+          This prevents adding secrets to the world-readable Nix store.
+        '';
+        example = literalExpression ''
+          {
+              address = "0.0.0.0";
+              port = 8080;
+              scope = "/srv/public";
+              modify = true;
+              auth = true;
+              users = [
+                {
+                  username = "{env}ENV_USERNAME";
+                  password = "{env}ENV_PASSWORD";
+                }
+              ];
+          }
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.path;
+        default = format.generate "webdav.yaml" cfg.settings;
+        defaultText = "Config file generated from services.webdav.settings";
+        description = ''
+          Path to config file. If this option is set, it will override any
+          configuration done in options.services.webdav.settings.
+        '';
+        example = "/etc/webdav/config.yaml";
+      };
+
+      environmentFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = ''
+          Environment file as defined in <citerefentry>
+          <refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum>
+          </citerefentry>.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.users = mkIf (cfg.user == "webdav") {
+      webdav = {
+        description = "WebDAV daemon user";
+        group = cfg.group;
+        uid = config.ids.uids.webdav;
+      };
+    };
+
+    users.groups = mkIf (cfg.group == "webdav") {
+      webdav.gid = config.ids.gids.webdav;
+    };
+
+    systemd.services.webdav = {
+      description = "WebDAV server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = "${pkgs.webdav}/bin/webdav -c ${cfg.configFile}";
+        Restart = "on-failure";
+        User = cfg.user;
+        Group = cfg.group;
+        EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ];
+      };
+    };
+  };
+
+  meta.maintainers = with maintainers; [ pmy ];
+}
diff --git a/nixos/modules/services/networking/monero.nix b/nixos/modules/services/networking/monero.nix
index 9a9084e4ce1a..8bed89917c85 100644
--- a/nixos/modules/services/networking/monero.nix
+++ b/nixos/modules/services/networking/monero.nix
@@ -222,7 +222,7 @@ in
       serviceConfig = {
         User  = "monero";
         Group = "monero";
-        ExecStart = "${pkgs.monero}/bin/monerod --config-file=${configFile} --non-interactive";
+        ExecStart = "${pkgs.monero-cli}/bin/monerod --config-file=${configFile} --non-interactive";
         Restart = "always";
         SuccessExitStatus = [ 0 1 ];
       };
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index 74daf0ae9faf..73e63e2ee99b 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -527,7 +527,6 @@ in {
 
       {
         networkmanager.connectionConfig = {
-          "ipv6.ip6-privacy" = 2;
           "ethernet.cloned-mac-address" = cfg.ethernet.macAddress;
           "wifi.cloned-mac-address" = cfg.wifi.macAddress;
           "wifi.powersave" =
diff --git a/nixos/modules/services/networking/nomad.nix b/nixos/modules/services/networking/nomad.nix
index 3bd15bd5c808..43333af5e2fe 100644
--- a/nixos/modules/services/networking/nomad.nix
+++ b/nixos/modules/services/networking/nomad.nix
@@ -51,7 +51,7 @@ in
 
       extraSettingsPaths = mkOption {
         type = types.listOf types.path;
-        default = [];
+        default = [ ];
         description = ''
           Additional settings paths used to configure nomad. These can be files or directories.
         '';
@@ -60,9 +60,21 @@ in
         '';
       };
 
+      extraSettingsPlugins = mkOption {
+        type = types.listOf (types.either types.package types.path);
+        default = [ ];
+        description = ''
+          Additional plugins dir used to configure nomad.
+        '';
+        example = literalExpression ''
+          [ "<pluginDir>" "pkgs.<plugins-name>"]
+        '';
+      };
+
+
       settings = mkOption {
         type = format.type;
-        default = {};
+        default = { };
         description = ''
           Configuration for Nomad. See the <link xlink:href="https://www.nomadproject.io/docs/configuration">documentation</link>
           for supported values.
@@ -128,7 +140,8 @@ in
           DynamicUser = cfg.dropPrivileges;
           ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
           ExecStart = "${cfg.package}/bin/nomad agent -config=/etc/nomad.json" +
-            concatMapStrings (path: " -config=${path}") cfg.extraSettingsPaths;
+            concatMapStrings (path: " -config=${path}") cfg.extraSettingsPaths +
+            concatMapStrings (path: " -plugin-dir=${path}/bin") cfg.extraSettingsPlugins;
           KillMode = "process";
           KillSignal = "SIGINT";
           LimitNOFILE = 65536;
diff --git a/nixos/modules/services/networking/radicale.nix b/nixos/modules/services/networking/radicale.nix
index c121008d5294..c6c40777ed7c 100644
--- a/nixos/modules/services/networking/radicale.nix
+++ b/nixos/modules/services/networking/radicale.nix
@@ -195,6 +195,7 @@ in {
         SystemCallArchitectures = "native";
         SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
         UMask = "0027";
+        WorkingDirectory = "/var/lib/radicale";
       };
     };
   };
diff --git a/nixos/modules/services/networking/sabnzbd.nix b/nixos/modules/services/networking/sabnzbd.nix
index 43566dfd25c5..54eeba1a9ec1 100644
--- a/nixos/modules/services/networking/sabnzbd.nix
+++ b/nixos/modules/services/networking/sabnzbd.nix
@@ -17,6 +17,13 @@ in
     services.sabnzbd = {
       enable = mkEnableOption "the sabnzbd server";
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.sabnzbd;
+        defaultText = "pkgs.sabnzbd";
+        description = "The sabnzbd executable package run by the service.";
+      };
+
       configFile = mkOption {
         type = types.path;
         default = "/var/lib/sabnzbd/sabnzbd.ini";
@@ -63,7 +70,7 @@ in
           GuessMainPID = "no";
           User = "${cfg.user}";
           Group = "${cfg.group}";
-          ExecStart = "${sabnzbd}/bin/sabnzbd -d -f ${cfg.configFile}";
+          ExecStart = "${lib.getBin cfg.package}/bin/sabnzbd -d -f ${cfg.configFile}";
         };
     };
   };
diff --git a/nixos/modules/services/ttys/getty.nix b/nixos/modules/services/ttys/getty.nix
index 8c5b6e5e0cbc..7021a2c80f85 100644
--- a/nixos/modules/services/ttys/getty.nix
+++ b/nixos/modules/services/ttys/getty.nix
@@ -24,6 +24,7 @@ in
 
   imports = [
     (mkRenamedOptionModule [ "services" "mingetty" ] [ "services" "getty" ])
+    (mkRemovedOptionModule [ "services" "getty" "serialSpeed" ] ''set non-standard baudrates with `boot.kernelParams` i.e. boot.kernelParams = ["console=ttyS2,1500000"];'')
   ];
 
   options = {
@@ -92,17 +93,6 @@ in
         '';
       };
 
-      serialSpeed = mkOption {
-        type = types.listOf types.int;
-        default = [ 115200 57600 38400 9600 ];
-        example = [ 38400 9600 ];
-        description = ''
-            Bitrates to allow for agetty's listening on serial ports. Listing more
-            bitrates gives more interoperability but at the cost of long delays
-            for getting a sync on the line.
-        '';
-      };
-
     };
 
   };
@@ -124,10 +114,9 @@ in
       };
 
     systemd.services."serial-getty@" =
-      let speeds = concatStringsSep "," (map toString config.services.getty.serialSpeed); in
       { serviceConfig.ExecStart = [
           "" # override upstream default with an empty ExecStart
-          (gettyCmd "%I --keep-baud ${speeds} $TERM")
+          (gettyCmd "%I --keep-baud $TERM")
         ];
         restartIfChanged = false;
       };
diff --git a/nixos/modules/services/web-apps/moodle.nix b/nixos/modules/services/web-apps/moodle.nix
index 6f5cfa2e3481..19f3e754691e 100644
--- a/nixos/modules/services/web-apps/moodle.nix
+++ b/nixos/modules/services/web-apps/moodle.nix
@@ -57,7 +57,7 @@ let
   pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql";
 
   phpExt = pkgs.php74.withExtensions
-        ({ enabled, all }: with all; [ iconv mbstring curl openssl tokenizer xmlrpc soap ctype zip gd simplexml dom  intl json sqlite3 pgsql pdo_sqlite pdo_pgsql pdo_odbc pdo_mysql pdo mysqli session zlib xmlreader fileinfo filter ]);
+        ({ enabled, all }: with all; [ iconv mbstring curl openssl tokenizer xmlrpc soap ctype zip gd simplexml dom  intl json sqlite3 pgsql pdo_sqlite pdo_pgsql pdo_odbc pdo_mysql pdo mysqli session zlib xmlreader fileinfo filter opcache ]);
 in
 {
   # interface
diff --git a/nixos/modules/services/web-servers/caddy/default.nix b/nixos/modules/services/web-servers/caddy/default.nix
index cef27e2e59f3..ed27dd375c86 100644
--- a/nixos/modules/services/web-servers/caddy/default.nix
+++ b/nixos/modules/services/web-servers/caddy/default.nix
@@ -171,34 +171,27 @@ in
   };
 
   config = mkIf cfg.enable {
+    systemd.packages = [ cfg.package ];
     systemd.services.caddy = {
-      description = "Caddy web server";
-      # upstream unit: https://github.com/caddyserver/dist/blob/master/init/caddy.service
-      after = [ "network-online.target" ];
-      wants = [ "network-online.target" ]; # systemd-networkd-wait-online.service
       wantedBy = [ "multi-user.target" ];
       startLimitIntervalSec = 14400;
       startLimitBurst = 10;
+
       serviceConfig = {
-        ExecStart = "${cfg.package}/bin/caddy run ${optionalString cfg.resume "--resume"} --config ${configJSON}";
-        ExecReload = "${cfg.package}/bin/caddy reload --config ${configJSON}";
-        Type = "simple";
+        # https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
+        # If the empty string is assigned to this option, the list of commands to start is reset, prior assignments of this option will have no effect.
+        ExecStart = [ "" "${cfg.package}/bin/caddy run ${optionalString cfg.resume "--resume"} --config ${configJSON}" ];
+        ExecReload = [ "" "${cfg.package}/bin/caddy reload --config ${configJSON}" ];
+
         User = cfg.user;
         Group = cfg.group;
+        ReadWriteDirectories = cfg.dataDir;
         Restart = "on-abnormal";
-        AmbientCapabilities = "cap_net_bind_service";
-        CapabilityBoundingSet = "cap_net_bind_service";
+
+        # TODO: attempt to upstream these options
         NoNewPrivileges = true;
-        LimitNPROC = 512;
-        LimitNOFILE = 1048576;
-        PrivateTmp = true;
         PrivateDevices = true;
         ProtectHome = true;
-        ProtectSystem = "full";
-        ReadWriteDirectories = cfg.dataDir;
-        KillMode = "mixed";
-        KillSignal = "SIGQUIT";
-        TimeoutStopSec = "5s";
       };
     };
 
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index be589e42ddd6..5717b86b3bea 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -896,7 +896,7 @@ in
         PrivateMounts = true;
         # System Call Filtering
         SystemCallArchitectures = "native";
-        SystemCallFilter = "~@cpu-emulation @debug @keyring @ipc @mount @obsolete @privileged @setuid";
+        SystemCallFilter = "~@cpu-emulation @debug @keyring @ipc @mount @obsolete @privileged @setuid @mincore";
       };
     };
 
diff --git a/nixos/modules/services/x11/desktop-managers/cinnamon.nix b/nixos/modules/services/x11/desktop-managers/cinnamon.nix
index a0a5873f72fe..82b07206a8b6 100644
--- a/nixos/modules/services/x11/desktop-managers/cinnamon.nix
+++ b/nixos/modules/services/x11/desktop-managers/cinnamon.nix
@@ -202,6 +202,13 @@ in
         blueberry
         warpinator
 
+        # cinnamon xapps
+        xviewer
+        xreader
+        xed
+        xplayer
+        pix
+
         # external apps shipped with linux-mint
         hexchat
         gnome-calculator
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index e036c684c886..6f0d645725e9 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -83,14 +83,14 @@ in
         default = true;
         description = ''
           Allow GDM to run on Wayland instead of Xserver.
-          Note to enable Wayland with Nvidia you need to
-          enable the <option>nvidiaWayland</option>.
+          Note to enable Wayland with Nvidia the <option>nvidiaWayland</option>
+          must not be disabled.
         '';
       };
 
       nvidiaWayland = mkOption {
         type = types.bool;
-        default = false;
+        default = true;
         description = ''
           Whether to allow wayland to be used with the proprietary
           NVidia graphics driver.
diff --git a/nixos/modules/services/x11/display-managers/startx.nix b/nixos/modules/services/x11/display-managers/startx.nix
index 6cd46cdf9649..a48566ae0684 100644
--- a/nixos/modules/services/x11/display-managers/startx.nix
+++ b/nixos/modules/services/x11/display-managers/startx.nix
@@ -35,10 +35,7 @@ in
   config = mkIf cfg.enable {
     services.xserver = {
       exportConfiguration = true;
-      displayManager.job.execCmd = "";
-      displayManager.lightdm.enable = lib.mkForce false;
     };
-    systemd.services.display-manager.enable = false;
 
     # Other displayManagers log to /dev/null because they're services and put
     # Xorg's stdout in the journal
diff --git a/nixos/modules/services/x11/display-managers/sx.nix b/nixos/modules/services/x11/display-managers/sx.nix
index 73d27390a580..e30977364300 100644
--- a/nixos/modules/services/x11/display-managers/sx.nix
+++ b/nixos/modules/services/x11/display-managers/sx.nix
@@ -26,13 +26,8 @@ in {
     environment.systemPackages = [ pkgs.sx ];
     services.xserver = {
       exportConfiguration = true;
-      displayManager = {
-        job.execCmd = "";
-        lightdm.enable = mkForce false;
-      };
       logFile = mkDefault null;
     };
-    systemd.services.display-manager.enable = false;
   };
 
   meta.maintainers = with maintainers; [ figsoda ];
diff --git a/nixos/modules/services/x11/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix
index e2fb7d0918e3..efdb7c61dfae 100644
--- a/nixos/modules/services/x11/hardware/libinput.nix
+++ b/nixos/modules/services/x11/hardware/libinput.nix
@@ -13,7 +13,7 @@ let cfg = config.services.xserver.libinput;
         example = "/dev/input/event0";
         description =
           ''
-            Path for ${deviceType} device.  Set to null to apply to any
+            Path for ${deviceType} device.  Set to <literal>null</literal> to apply to any
             auto-detected ${deviceType}.
           '';
       };
@@ -24,8 +24,8 @@ let cfg = config.services.xserver.libinput;
         example = "flat";
         description =
           ''
-            Sets  the pointer acceleration profile to the given profile.
-            Permitted values are adaptive, flat.
+            Sets the pointer acceleration profile to the given profile.
+            Permitted values are <literal>adaptive</literal>, <literal>flat</literal>.
             Not all devices support this option or all profiles.
             If a profile is unsupported, the default profile for this is used.
             <literal>flat</literal>: Pointer motion is accelerated by a constant
@@ -38,12 +38,14 @@ let cfg = config.services.xserver.libinput;
       accelSpeed = mkOption {
         type = types.nullOr types.str;
         default = null;
+        example = "-0.5";
         description = "Cursor acceleration (how fast speed increases from minSpeed to maxSpeed).";
       };
 
       buttonMapping = mkOption {
         type = types.nullOr types.str;
         default = null;
+        example = "1 6 3 4 5 0 7";
         description =
           ''
             Sets the logical button mapping for this device, see XSetPointerMapping(3). The string  must
@@ -58,9 +60,10 @@ let cfg = config.services.xserver.libinput;
       calibrationMatrix = mkOption {
         type = types.nullOr types.str;
         default = null;
+        example = "0.5 0 0 0 0.8 0.1 0 0 1";
         description =
           ''
-            A  string  of  9 space-separated floating point numbers.  Sets the calibration matrix to the
+            A string of 9 space-separated floating point numbers. Sets the calibration matrix to the
             3x3 matrix where the first row is (abc), the second row is (def) and the third row is (ghi).
           '';
       };
@@ -68,6 +71,7 @@ let cfg = config.services.xserver.libinput;
       clickMethod = mkOption {
         type = types.nullOr (types.enum [ "none" "buttonareas" "clickfinger" ]);
         default = null;
+        example = "buttonareas";
         description =
           ''
             Enables a click method. Permitted values are <literal>none</literal>,
@@ -166,8 +170,9 @@ let cfg = config.services.xserver.libinput;
       transformationMatrix = mkOption {
         type = types.nullOr types.str;
         default = null;
+        example = "0.5 0 0 0 0.8 0.1 0 0 1";
         description = ''
-          A  string  of  9 space-separated floating point numbers.  Sets the transformation matrix to
+          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).
         '';
       };
diff --git a/nixos/modules/services/x11/window-managers/xmonad.nix b/nixos/modules/services/x11/window-managers/xmonad.nix
index 6aa0d5f76f26..a8f38046137a 100644
--- a/nixos/modules/services/x11/window-managers/xmonad.nix
+++ b/nixos/modules/services/x11/window-managers/xmonad.nix
@@ -29,7 +29,6 @@ let
       } ''
         install -D ${xmonadEnv}/share/man/man1/xmonad.1.gz $out/share/man/man1/xmonad.1.gz
         makeWrapper ${configured}/bin/xmonad $out/bin/xmonad \
-          --set NIX_GHC "${xmonadEnv}/bin/ghc" \
           --set XMONAD_XMESSAGE "${pkgs.xorg.xmessage}/bin/xmessage"
       '';
 
@@ -93,6 +92,8 @@ in {
           <literal>(restart "xmonad" True)</literal> instead, which will just restart
           xmonad from PATH. This allows e.g. switching to the new xmonad binary
           after rebuilding your system with nixos-rebuild.
+          For the same reason, ghc is not added to the environment when this
+          option is set.
 
           If you actually want to run xmonad with a config specified here, but
           also be able to recompile and restart it from a copy of that source in
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index cb620f10b13f..24d925734423 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -588,11 +588,22 @@ in
   config = mkIf cfg.enable {
 
     services.xserver.displayManager.lightdm.enable =
-      let dmconf = cfg.displayManager;
-          default = !(dmconf.gdm.enable
-                    || dmconf.sddm.enable
-                    || dmconf.xpra.enable );
-      in mkIf (default) true;
+      let dmConf = cfg.displayManager;
+          default = !(dmConf.gdm.enable
+                    || dmConf.sddm.enable
+                    || dmConf.xpra.enable
+                    || dmConf.sx.enable
+                    || dmConf.startx.enable);
+      in mkIf (default) (mkDefault true);
+
+    # so that the service won't be enabled when only startx is used
+    systemd.services.display-manager.enable  =
+      let dmConf = cfg.displayManager;
+          noDmUsed = !(dmConf.gdm.enable
+                    || dmConf.sddm.enable
+                    || dmConf.xpra.enable
+                    || dmConf.lightdm.enable);
+      in mkIf (noDmUsed) (mkDefault false);
 
     hardware.opengl.enable = mkDefault true;
 
@@ -702,7 +713,8 @@ in
             rm -f /tmp/.X0-lock
           '';
 
-        script = "${cfg.displayManager.job.execCmd}";
+        # TODO: move declaring the systemd service to its own mkIf
+        script = mkIf (config.systemd.services.display-manager.enable == true) "${cfg.displayManager.job.execCmd}";
 
         # Stop restarting if the display manager stops (crashes) 2 times
         # in one minute. Starting X typically takes 3-4s.
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index e105502cf3a4..053496441d81 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -11,6 +11,7 @@ use Cwd 'abs_path';
 
 my $out = "@out@";
 
+# FIXME: maybe we should use /proc/1/exe to get the current systemd.
 my $curSystemd = abs_path("/run/current-system/sw/bin");
 
 # To be robust against interruption, record what units need to be started etc.
@@ -18,16 +19,13 @@ my $startListFile = "/run/nixos/start-list";
 my $restartListFile = "/run/nixos/restart-list";
 my $reloadListFile = "/run/nixos/reload-list";
 
-# Parse restart/reload requests by the activation script.
-# Activation scripts may write newline-separated units to this
-# file and switch-to-configuration will handle them. While
-# `stopIfChanged = true` is ignored, switch-to-configuration will
-# handle `restartIfChanged = false` and `reloadIfChanged = true`.
-# This also works for socket-activated units.
+# Parse restart/reload requests by the activation script
 my $restartByActivationFile = "/run/nixos/activation-restart-list";
+my $reloadByActivationFile = "/run/nixos/activation-reload-list";
 my $dryRestartByActivationFile = "/run/nixos/dry-activation-restart-list";
+my $dryReloadByActivationFile = "/run/nixos/dry-activation-reload-list";
 
-make_path("/run/nixos", { mode => oct(755) });
+make_path("/run/nixos", { mode => 0755 });
 
 my $action = shift @ARGV;
 
@@ -149,92 +147,6 @@ sub fingerprintUnit {
     return abs_path($s) . (-f "${s}.d/overrides.conf" ? " " . abs_path "${s}.d/overrides.conf" : "");
 }
 
-sub handleModifiedUnit {
-    my ($unit, $baseName, $newUnitFile, $activePrev, $unitsToStop, $unitsToStart, $unitsToReload, $unitsToRestart, $unitsToSkip) = @_;
-
-    if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target" || $unit =~ /\.slice$/ || $unit =~ /\.path$/) {
-        # Do nothing.  These cannot be restarted directly.
-        # Slices and Paths don't have to be restarted since
-        # properties (resource limits and inotify watches)
-        # seem to get applied on daemon-reload.
-    } elsif ($unit =~ /\.mount$/) {
-        # Reload the changed mount unit to force a remount.
-        $unitsToReload->{$unit} = 1;
-        recordUnit($reloadListFile, $unit);
-    } else {
-        my $unitInfo = parseUnit($newUnitFile);
-        if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) {
-            $unitsToReload->{$unit} = 1;
-            recordUnit($reloadListFile, $unit);
-        }
-        elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) {
-            $unitsToSkip->{$unit} = 1;
-        } else {
-            # If this unit is socket-activated, then stop it instead
-            # of restarting it to make sure the new version of it is
-            # socket-activated.
-            my $socketActivated = 0;
-            if ($unit =~ /\.service$/) {
-                my @sockets = split / /, ($unitInfo->{Sockets} // "");
-                if (scalar @sockets == 0) {
-                    @sockets = ("$baseName.socket");
-                }
-                foreach my $socket (@sockets) {
-                    if (-e "$out/etc/systemd/system/$socket") {
-                        $socketActivated = 1;
-                        $unitsToStop->{$unit} = 1;
-                        # If the socket was not running previously,
-                        # start it now.
-                        if (not defined $activePrev->{$socket}) {
-                            $unitsToStart->{$socket} = 1;
-                        }
-                    }
-                }
-            }
-
-            # Don't do the rest of this for socket-activated units
-            # because we handled these above where we stop the unit.
-            # Since only services can be socket-activated, the
-            # following condition always evaluates to `true` for
-            # non-service units.
-            if ($socketActivated) {
-                return;
-            }
-
-            # If we are restarting a socket, also stop the corresponding
-            # service. This is required because restarting a socket
-            # when the service is already activated fails.
-            if ($unit =~ /\.socket$/) {
-                my $service = $unitInfo->{Service} // "";
-                if ($service eq "") {
-                    $service = "$baseName.service";
-                }
-                if (defined $activePrev->{$service}) {
-                    $unitsToStop->{$service} = 1;
-                }
-                $unitsToRestart->{$unit} = 1;
-                recordUnit($restartListFile, $unit);
-            } else {
-                # Always restart non-services instead of stopping and starting them
-                # because it doesn't make sense to stop them with a config from
-                # the old evaluation.
-                if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes") || $unit !~ /\.service$/) {
-                    # This unit should be restarted instead of
-                    # stopped and started.
-                    $unitsToRestart->{$unit} = 1;
-                    recordUnit($restartListFile, $unit);
-                } else {
-                    # We write to a file to ensure that the
-                    # service gets restarted if we're interrupted.
-                    $unitsToStart->{$unit} = 1;
-                    recordUnit($startListFile, $unit);
-                    $unitsToStop->{$unit} = 1;
-                }
-            }
-        }
-    }
-}
-
 # Figure out what units need to be stopped, started, restarted or reloaded.
 my (%unitsToStop, %unitsToSkip, %unitsToStart, %unitsToRestart, %unitsToReload);
 
@@ -307,7 +219,65 @@ while (my ($unit, $state) = each %{$activePrev}) {
         }
 
         elsif (fingerprintUnit($prevUnitFile) ne fingerprintUnit($newUnitFile)) {
-            handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, %unitsToSkip);
+            if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target") {
+                # Do nothing.  These cannot be restarted directly.
+            } elsif ($unit =~ /\.mount$/) {
+                # Reload the changed mount unit to force a remount.
+                $unitsToReload{$unit} = 1;
+                recordUnit($reloadListFile, $unit);
+            } elsif ($unit =~ /\.socket$/ || $unit =~ /\.path$/ || $unit =~ /\.slice$/) {
+                # FIXME: do something?
+            } else {
+                my $unitInfo = parseUnit($newUnitFile);
+                if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) {
+                    $unitsToReload{$unit} = 1;
+                    recordUnit($reloadListFile, $unit);
+                }
+                elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) {
+                    $unitsToSkip{$unit} = 1;
+                } else {
+                    if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes")) {
+                        # This unit should be restarted instead of
+                        # stopped and started.
+                        $unitsToRestart{$unit} = 1;
+                        recordUnit($restartListFile, $unit);
+                    } else {
+                        # If this unit is socket-activated, then stop the
+                        # socket unit(s) as well, and restart the
+                        # socket(s) instead of the service.
+                        my $socketActivated = 0;
+                        if ($unit =~ /\.service$/) {
+                            my @sockets = split / /, ($unitInfo->{Sockets} // "");
+                            if (scalar @sockets == 0) {
+                                @sockets = ("$baseName.socket");
+                            }
+                            foreach my $socket (@sockets) {
+                                if (defined $activePrev->{$socket}) {
+                                    $unitsToStop{$socket} = 1;
+                                    # Only restart sockets that actually
+                                    # exist in new configuration:
+                                    if (-e "$out/etc/systemd/system/$socket") {
+                                        $unitsToStart{$socket} = 1;
+                                        recordUnit($startListFile, $socket);
+                                        $socketActivated = 1;
+                                    }
+                                }
+                            }
+                        }
+
+                        # If the unit is not socket-activated, record
+                        # that this unit needs to be started below.
+                        # We write this to a file to ensure that the
+                        # service gets restarted if we're interrupted.
+                        if (!$socketActivated) {
+                            $unitsToStart{$unit} = 1;
+                            recordUnit($startListFile, $unit);
+                        }
+
+                        $unitsToStop{$unit} = 1;
+                    }
+                }
+            }
         }
     }
 }
@@ -392,6 +362,8 @@ sub filterUnits {
 }
 
 my @unitsToStopFiltered = filterUnits(\%unitsToStop);
+my @unitsToStartFiltered = filterUnits(\%unitsToStart);
+
 
 # Show dry-run actions.
 if ($action eq "dry-activate") {
@@ -403,44 +375,21 @@ if ($action eq "dry-activate") {
     print STDERR "would activate the configuration...\n";
     system("$out/dry-activate", "$out");
 
-    # Handle the activation script requesting the restart or reload of a unit.
-    my %unitsToAlsoStop;
-    my %unitsToAlsoSkip;
-    foreach (split('\n', read_file($dryRestartByActivationFile, err_mode => 'quiet') // "")) {
-        my $unit = $_;
-        my $baseUnit = $unit;
-        my $newUnitFile = "$out/etc/systemd/system/$baseUnit";
-
-        # Detect template instances.
-        if (!-e $newUnitFile && $unit =~ /^(.*)@[^\.]*\.(.*)$/) {
-          $baseUnit = "$1\@.$2";
-          $newUnitFile = "$out/etc/systemd/system/$baseUnit";
-        }
-
-        my $baseName = $baseUnit;
-        $baseName =~ s/\.[a-z]*$//;
+    $unitsToRestart{$_} = 1 foreach
+        split('\n', read_file($dryRestartByActivationFile, err_mode => 'quiet') // "");
 
-        handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToAlsoStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, %unitsToAlsoSkip);
-    }
-    unlink($dryRestartByActivationFile);
-
-    my @unitsToAlsoStopFiltered = filterUnits(\%unitsToAlsoStop);
-    if (scalar(keys %unitsToAlsoStop) > 0) {
-        print STDERR "would stop the following units as well: ", join(", ", @unitsToAlsoStopFiltered), "\n"
-            if scalar @unitsToAlsoStopFiltered;
-    }
-
-    print STDERR "would NOT restart the following changed units as well: ", join(", ", sort(keys %unitsToAlsoSkip)), "\n"
-        if scalar(keys %unitsToAlsoSkip) > 0;
+    $unitsToReload{$_} = 1 foreach
+        split('\n', read_file($dryReloadByActivationFile, err_mode => 'quiet') // "");
 
     print STDERR "would restart systemd\n" if $restartSystemd;
-    print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n"
-        if scalar(keys %unitsToReload) > 0;
     print STDERR "would restart the following units: ", join(", ", sort(keys %unitsToRestart)), "\n"
         if scalar(keys %unitsToRestart) > 0;
-    my @unitsToStartFiltered = filterUnits(\%unitsToStart);
     print STDERR "would start the following units: ", join(", ", @unitsToStartFiltered), "\n"
         if scalar @unitsToStartFiltered;
+    print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n"
+        if scalar(keys %unitsToReload) > 0;
+    unlink($dryRestartByActivationFile);
+    unlink($dryReloadByActivationFile);
     exit 0;
 }
 
@@ -451,7 +400,7 @@ if (scalar (keys %unitsToStop) > 0) {
     print STDERR "stopping the following units: ", join(", ", @unitsToStopFiltered), "\n"
         if scalar @unitsToStopFiltered;
     # Use current version of systemctl binary before daemon is reexeced.
-    system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToStop));
+    system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToStop)); # FIXME: ignore errors?
 }
 
 print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n"
@@ -465,38 +414,12 @@ system("$out/activate", "$out") == 0 or $res = 2;
 
 # Handle the activation script requesting the restart or reload of a unit.
 # We can only restart and reload (not stop/start) because the units to be
-# stopped are already stopped before the activation script is run. We do however
-# make an exception for services that are socket-activated and that have to be stopped
-# instead of being restarted.
-my %unitsToAlsoStop;
-my %unitsToAlsoSkip;
-foreach (split('\n', read_file($restartByActivationFile, err_mode => 'quiet') // "")) {
-    my $unit = $_;
-    my $baseUnit = $unit;
-    my $newUnitFile = "$out/etc/systemd/system/$baseUnit";
-
-    # Detect template instances.
-    if (!-e $newUnitFile && $unit =~ /^(.*)@[^\.]*\.(.*)$/) {
-      $baseUnit = "$1\@.$2";
-      $newUnitFile = "$out/etc/systemd/system/$baseUnit";
-    }
-
-    my $baseName = $baseUnit;
-    $baseName =~ s/\.[a-z]*$//;
-
-    handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToAlsoStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, %unitsToAlsoSkip);
-}
-unlink($restartByActivationFile);
-
-my @unitsToAlsoStopFiltered = filterUnits(\%unitsToAlsoStop);
-if (scalar(keys %unitsToAlsoStop) > 0) {
-    print STDERR "stopping the following units as well: ", join(", ", @unitsToAlsoStopFiltered), "\n"
-        if scalar @unitsToAlsoStopFiltered;
-    system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToAlsoStop));
-}
+# stopped are already stopped before the activation script is run.
+$unitsToRestart{$_} = 1 foreach
+    split('\n', read_file($restartByActivationFile, err_mode => 'quiet') // "");
 
-print STDERR "NOT restarting the following changed units as well: ", join(", ", sort(keys %unitsToAlsoSkip)), "\n"
-    if scalar(keys %unitsToAlsoSkip) > 0;
+$unitsToReload{$_} = 1 foreach
+    split('\n', read_file($reloadByActivationFile, err_mode => 'quiet') // "");
 
 # Restart systemd if necessary. Note that this is done using the
 # current version of systemd, just in case the new one has trouble
@@ -537,40 +460,14 @@ if (scalar(keys %unitsToReload) > 0) {
     print STDERR "reloading the following units: ", join(", ", sort(keys %unitsToReload)), "\n";
     system("@systemd@/bin/systemctl", "reload", "--", sort(keys %unitsToReload)) == 0 or $res = 4;
     unlink($reloadListFile);
+    unlink($reloadByActivationFile);
 }
 
 # Restart changed services (those that have to be restarted rather
 # than stopped and started).
 if (scalar(keys %unitsToRestart) > 0) {
     print STDERR "restarting the following units: ", join(", ", sort(keys %unitsToRestart)), "\n";
-
-    # We split the units to be restarted into sockets and non-sockets.
-    # This is because restarting sockets may fail which is not bad by
-    # itself but which will prevent changes on the sockets. We usually
-    # restart the socket and stop the service before that. Restarting
-    # the socket will fail however when the service was re-activated
-    # in the meantime. There is no proper way to prevent that from happening.
-    my @unitsWithErrorHandling = grep { $_ !~ /\.socket$/ } sort(keys %unitsToRestart);
-    my @unitsWithoutErrorHandling = grep { $_ =~ /\.socket$/ } sort(keys %unitsToRestart);
-
-    if (scalar(@unitsWithErrorHandling) > 0) {
-        system("@systemd@/bin/systemctl", "restart", "--", @unitsWithErrorHandling) == 0 or $res = 4;
-    }
-    if (scalar(@unitsWithoutErrorHandling) > 0) {
-        # Don't print warnings from systemctl
-        no warnings 'once';
-        open(OLDERR, ">&", \*STDERR);
-        close(STDERR);
-
-        my $ret = system("@systemd@/bin/systemctl", "restart", "--", @unitsWithoutErrorHandling);
-
-        # Print stderr again
-        open(STDERR, ">&OLDERR");
-
-        if ($ret ne 0) {
-            print STDERR "warning: some sockets failed to restart. Please check your journal (journalctl -eb) and act accordingly.\n";
-        }
-    }
+    system("@systemd@/bin/systemctl", "restart", "--", sort(keys %unitsToRestart)) == 0 or $res = 4;
     unlink($restartListFile);
     unlink($restartByActivationFile);
 }
@@ -581,7 +478,6 @@ if (scalar(keys %unitsToRestart) > 0) {
 # that are symlinks to other units.  We shouldn't start both at the
 # same time because we'll get a "Failed to add path to set" error from
 # systemd.
-my @unitsToStartFiltered = filterUnits(\%unitsToStart);
 print STDERR "starting the following units: ", join(", ", @unitsToStartFiltered), "\n"
     if scalar @unitsToStartFiltered;
 system("@systemd@/bin/systemctl", "start", "--", sort(keys %unitsToStart)) == 0 or $res = 4;
@@ -589,7 +485,7 @@ unlink($startListFile);
 
 
 # Print failed and new units.
-my (@failed, @new);
+my (@failed, @new, @restarting);
 my $activeNew = getActiveUnits;
 while (my ($unit, $state) = each %{$activeNew}) {
     if ($state->{state} eq "failed") {
@@ -605,9 +501,7 @@ while (my ($unit, $state) = each %{$activeNew}) {
             push @failed, $unit;
         }
     }
-    # Ignore scopes since they are not managed by this script but rather
-    # created and managed by third-party services via the systemd dbus API.
-    elsif ($state->{state} ne "failed" && !defined $activePrev->{$unit} && $unit !~ /\.scope$/) {
+    elsif ($state->{state} ne "failed" && !defined $activePrev->{$unit}) {
         push @new, $unit;
     }
 }
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index 68da910d29cc..026fd1791d33 100644
--- a/nixos/modules/system/activation/top-level.nix
+++ b/nixos/modules/system/activation/top-level.nix
@@ -84,13 +84,6 @@ let
       export localeArchive="${config.i18n.glibcLocales}/lib/locale/locale-archive"
       substituteAll ${./switch-to-configuration.pl} $out/bin/switch-to-configuration
       chmod +x $out/bin/switch-to-configuration
-      ${optionalString (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) ''
-        if ! output=$($perl/bin/perl -c $out/bin/switch-to-configuration 2>&1); then
-          echo "switch-to-configuration syntax is not valid:"
-          echo "$output"
-          exit 1
-        fi
-      ''}
 
       echo -n "${toString config.system.extraDependencies}" > $out/extra-dependencies
 
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix
index 4a9da9394519..d147155d796c 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -243,7 +243,7 @@ in
             "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat"
             "hid_logitech_hidpp" "hid_logitech_dj" "hid_microsoft"
 
-          ] ++ optionals (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [
+          ] ++ optionals pkgs.stdenv.hostPlatform.isx86 [
             # Misc. x86 keyboard stuff.
             "pcips2" "atkbd" "i8042"
 
diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl
index 4d8537d4c327..0c93b288fc65 100644
--- a/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ b/nixos/modules/system/boot/loader/grub/install-grub.pl
@@ -103,10 +103,10 @@ if (stat($bootPath)->dev != stat("/nix/store")->dev) {
 
 # Discover information about the location of the bootPath
 struct(Fs => {
-        device => '$',
-        type => '$',
-        mount => '$',
-    });
+    device => '$',
+    type => '$',
+    mount => '$',
+});
 sub PathInMount {
     my ($path, $mount) = @_;
     my @splitMount = split /\//, $mount;
@@ -155,9 +155,9 @@ sub GetFs {
     return $bestFs;
 }
 struct (Grub => {
-        path => '$',
-        search => '$',
-    });
+    path => '$',
+    search => '$',
+});
 my $driveid = 1;
 sub GrubFs {
     my ($dir) = @_;
@@ -254,8 +254,8 @@ if ($grubVersion == 1) {
     # $defaultEntry might be "saved", indicating that we want to use the last selected configuration as default.
     # Incidentally this is already the correct value for the grub 1 config to achieve this behaviour.
     $conf .= "
-    default $defaultEntry
-    timeout $timeout
+        default $defaultEntry
+        timeout $timeout
     ";
     if ($splashImage) {
         copy $splashImage, "$bootPath/background.xpm.gz" or die "cannot copy $splashImage to $bootPath: $!\n";
@@ -305,7 +305,7 @@ else {
 
     if ($copyKernels == 0) {
         $conf .= "
-        " . $grubStore->search;
+            " . $grubStore->search;
     }
     # FIXME: should use grub-mkconfig.
     my $defaultEntryText = $defaultEntry;
@@ -313,55 +313,55 @@ else {
         $defaultEntryText = "\"\${saved_entry}\"";
     }
     $conf .= "
-    " . $grubBoot->search . "
-    if [ -s \$prefix/grubenv ]; then
-    load_env
-    fi
-
-    # ‘grub-reboot’ sets a one-time saved entry, which we process here and
-    # then delete.
-    if [ \"\${next_entry}\" ]; then
-    set default=\"\${next_entry}\"
-    set next_entry=
-    save_env next_entry
-    set timeout=1
-    set boot_once=true
-    else
-    set default=$defaultEntryText
-    set timeout=$timeout
-    fi
-
-    function savedefault {
-        if [ -z \"\${boot_once}\"]; then
-        saved_entry=\"\${chosen}\"
-        save_env saved_entry
+        " . $grubBoot->search . "
+        if [ -s \$prefix/grubenv ]; then
+          load_env
         fi
-    }
 
-    # Setup the graphics stack for bios and efi systems
-    if [ \"\${grub_platform}\" = \"efi\" ]; then
-    insmod efi_gop
-    insmod efi_uga
-    else
-    insmod vbe
-    fi
+        # ‘grub-reboot’ sets a one-time saved entry, which we process here and
+        # then delete.
+        if [ \"\${next_entry}\" ]; then
+          set default=\"\${next_entry}\"
+          set next_entry=
+          save_env next_entry
+          set timeout=1
+          set boot_once=true
+        else
+          set default=$defaultEntryText
+          set timeout=$timeout
+        fi
+
+        function savedefault {
+            if [ -z \"\${boot_once}\"]; then
+            saved_entry=\"\${chosen}\"
+            save_env saved_entry
+            fi
+        }
+
+        # Setup the graphics stack for bios and efi systems
+        if [ \"\${grub_platform}\" = \"efi\" ]; then
+          insmod efi_gop
+          insmod efi_uga
+        else
+          insmod vbe
+        fi
     ";
 
     if ($font) {
         copy $font, "$bootPath/converted-font.pf2" or die "cannot copy $font to $bootPath: $!\n";
         $conf .= "
-        insmod font
-        if loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/converted-font.pf2; then
-        insmod gfxterm
-        if [ \"\${grub_platform}\" = \"efi\" ]; then
-        set gfxmode=$gfxmodeEfi
-        set gfxpayload=$gfxpayloadEfi
-        else
-        set gfxmode=$gfxmodeBios
-        set gfxpayload=$gfxpayloadBios
-        fi
-        terminal_output gfxterm
-        fi
+            insmod font
+            if loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/converted-font.pf2; then
+              insmod gfxterm
+              if [ \"\${grub_platform}\" = \"efi\" ]; then
+                set gfxmode=$gfxmodeEfi
+                set gfxpayload=$gfxpayloadEfi
+              else
+                set gfxmode=$gfxmodeBios
+                set gfxpayload=$gfxpayloadBios
+              fi
+              terminal_output gfxterm
+            fi
         ";
     }
     if ($splashImage) {
@@ -378,14 +378,14 @@ else {
         }
         copy $splashImage, "$bootPath/background$suffix" or die "cannot copy $splashImage to $bootPath: $!\n";
         $conf .= "
-        insmod " . substr($suffix, 1) . "
-        if background_image --mode '$splashMode' " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/background$suffix; then
-        set color_normal=white/black
-        set color_highlight=black/white
-        else
-        set menu_color_normal=cyan/blue
-        set menu_color_highlight=white/blue
-        fi
+            insmod " . substr($suffix, 1) . "
+            if background_image --mode '$splashMode' " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/background$suffix; then
+              set color_normal=white/black
+              set color_highlight=black/white
+            else
+              set menu_color_normal=cyan/blue
+              set menu_color_highlight=white/blue
+            fi
         ";
     }
 
@@ -395,20 +395,20 @@ else {
         # Copy theme
         rcopy($theme, "$bootPath/theme") or die "cannot copy $theme to $bootPath\n";
         $conf .= "
-        # Sets theme.
-        set theme=" . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/theme.txt
-        export theme
-        # Load theme fonts, if any
+            # Sets theme.
+            set theme=" . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/theme.txt
+            export theme
+            # Load theme fonts, if any
         ";
 
         find( { wanted => sub {
-                    if ($_ =~ /\.pf2$/i) {
-                        $font = File::Spec->abs2rel($File::Find::name, $theme);
-                        $conf .= "
-                        loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/$font
-                        ";
-                    }
-                }, no_chdir => 1 }, $theme );
+            if ($_ =~ /\.pf2$/i) {
+                $font = File::Spec->abs2rel($File::Find::name, $theme);
+                $conf .= "
+                    loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/$font
+                ";
+            }
+        }, no_chdir => 1 }, $theme );
     }
 }
 
@@ -474,8 +474,8 @@ sub addEntry {
     # FIXME: $confName
 
     my $kernelParams =
-    "init=" . Cwd::abs_path("$path/init") . " " .
-    readFile("$path/kernel-params");
+        "init=" . Cwd::abs_path("$path/init") . " " .
+        readFile("$path/kernel-params");
     my $xenParams = $xen && -e "$path/xen-params" ? readFile("$path/xen-params") : "";
 
     if ($grubVersion == 1) {
@@ -524,9 +524,9 @@ foreach my $link (@links) {
 
     my $date = strftime("%F", localtime(lstat($link)->mtime));
     my $version =
-    -e "$link/nixos-version"
-    ? readFile("$link/nixos-version")
-    : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]);
+        -e "$link/nixos-version"
+        ? readFile("$link/nixos-version")
+        : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]);
 
     if ($cfgName) {
         $entryName = $cfgName;
@@ -551,8 +551,8 @@ sub addProfile {
     sub nrFromGen { my ($x) = @_; $x =~ /\/\w+-(\d+)-link/; return $1; }
 
     my @links = sort
-    { nrFromGen($b) <=> nrFromGen($a) }
-    (glob "$profile-*-link");
+        { nrFromGen($b) <=> nrFromGen($a) }
+        (glob "$profile-*-link");
 
     my $curEntry = 0;
     foreach my $link (@links) {
@@ -563,9 +563,9 @@ sub addProfile {
         }
         my $date = strftime("%F", localtime(lstat($link)->mtime));
         my $version =
-        -e "$link/nixos-version"
-        ? readFile("$link/nixos-version")
-        : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]);
+            -e "$link/nixos-version"
+            ? readFile("$link/nixos-version")
+            : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]);
         addEntry("NixOS - Configuration " . nrFromGen($link) . " ($date - $version)", $link);
     }
 
@@ -653,13 +653,13 @@ foreach my $fn (glob "$bootPath/kernels/*") {
 #
 
 struct(GrubState => {
-        name => '$',
-        version => '$',
-        efi => '$',
-        devices => '$',
-        efiMountPoint => '$',
-        extraGrubInstallArgs => '@',
-    });
+    name => '$',
+    version => '$',
+    efi => '$',
+    devices => '$',
+    efiMountPoint => '$',
+    extraGrubInstallArgs => '@',
+});
 # If you add something to the state file, only add it to the end
 # because it is read line-by-line.
 sub readGrubState {
diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
index c38bef9d6d4b..e9697b5f0e64 100644
--- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
+++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
@@ -244,19 +244,27 @@ def main() -> None:
         subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@"] + flags + ["install"])
     else:
         # Update bootloader to latest if needed
-        systemd_version = subprocess.check_output(["@systemd@/bin/bootctl", "--version"], universal_newlines=True).split()[1]
+        systemd_version = subprocess.check_output(["@systemd@/bin/bootctl", "--version"], universal_newlines=True).split()[2]
         sdboot_status = subprocess.check_output(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "status"], universal_newlines=True)
 
         # See status_binaries() in systemd bootctl.c for code which generates this
-        m = re.search("^\W+File:.*/EFI/(BOOT|systemd)/.*\.efi \(systemd-boot (\d+)\)$",
+        m = re.search("^\W+File:.*/EFI/(BOOT|systemd)/.*\.efi \(systemd-boot ([\d.]+[^)]*)\)$",
                       sdboot_status, re.IGNORECASE | re.MULTILINE)
+
+        needs_install = False
+
         if m is None:
-            print("could not find any previously installed systemd-boot")
+            print("could not find any previously installed systemd-boot, installing.")
+            # Let systemd-boot attempt an installation if a previous one wasn't found
+            needs_install = True
         else:
-            sdboot_version = m.group(2)
-            if systemd_version > sdboot_version:
+            sdboot_version = f'({m.group(2)})'
+            if systemd_version != sdboot_version:
                 print("updating systemd-boot from %s to %s" % (sdboot_version, systemd_version))
-                subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "update"])
+                needs_install = True
+
+        if needs_install:
+            subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "update"])
 
     mkdir_p("@efiSysMountPoint@/efi/nixos")
     mkdir_p("@efiSysMountPoint@/loader/entries")
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 8fcf62d7fbff..6e0ee437d915 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -67,6 +67,7 @@ let
       "systemd-user-sessions.service"
       "dbus-org.freedesktop.import1.service"
       "dbus-org.freedesktop.machine1.service"
+      "dbus-org.freedesktop.login1.service"
       "user@.service"
       "user-runtime-dir@.service"
 
diff --git a/nixos/modules/tasks/auto-upgrade.nix b/nixos/modules/tasks/auto-upgrade.nix
index b19b688a1fb8..b931b27ad817 100644
--- a/nixos/modules/tasks/auto-upgrade.nix
+++ b/nixos/modules/tasks/auto-upgrade.nix
@@ -139,6 +139,7 @@ in {
         gzip
         gitMinimal
         config.nix.package.out
+        config.programs.ssh.package
       ];
 
       script = let
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 4e20ec118464..49901cda848d 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -417,7 +417,11 @@ in
         network node hostname (uname --nodename) the option
         boot.kernel.sysctl."kernel.hostname" can be used as a workaround (but
         the 64 character limit still applies).
+
+        WARNING: Do not use underscores (_) or you may run into unexpected issues.
       '';
+       # warning until the issues in https://github.com/NixOS/nixpkgs/pull/138978
+       # are resolved
     };
 
     networking.fqdn = mkOption {
@@ -1233,6 +1237,8 @@ in
       "net.ipv4.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces);
       "net.ipv6.conf.all.disable_ipv6" = mkDefault (!cfg.enableIPv6);
       "net.ipv6.conf.default.disable_ipv6" = mkDefault (!cfg.enableIPv6);
+      # networkmanager falls back to "/proc/sys/net/ipv6/conf/default/use_tempaddr"
+      "net.ipv6.conf.default.use_tempaddr" = tempaddrValues.${cfg.tempAddresses}.sysctl;
     } // listToAttrs (flip concatMap (filter (i: i.proxyARP) interfaces)
         (i: [(nameValuePair "net.ipv4.conf.${replaceChars ["."] ["/"] i.name}.proxy_arp" true)]))
       // listToAttrs (forEach interfaces
diff --git a/nixos/modules/virtualisation/azure-agent.nix b/nixos/modules/virtualisation/azure-agent.nix
index 41f3fa0e6642..bd8c7f8c1eea 100644
--- a/nixos/modules/virtualisation/azure-agent.nix
+++ b/nixos/modules/virtualisation/azure-agent.nix
@@ -76,7 +76,7 @@ in
 
   config = mkIf cfg.enable {
     assertions = [ {
-      assertion = pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64;
+      assertion = pkgs.stdenv.hostPlatform.isx86;
       message = "Azure not currently supported on ${pkgs.stdenv.hostPlatform.system}";
     } {
       assertion = config.networking.networkmanager.enable == false;
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 6ce4461babc7..91356ac1d984 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -97,7 +97,7 @@ let
     imap1 (idx: drive: drive // { device = driveDeviceName idx; });
 
   efiPrefix =
-    if (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) then "${pkgs.OVMF.fd}/FV/OVMF"
+    if pkgs.stdenv.hostPlatform.isx86 then "${pkgs.OVMF.fd}/FV/OVMF"
     else if pkgs.stdenv.isAarch64 then "${pkgs.OVMF.fd}/FV/AAVMF"
     else throw "No EFI firmware available for platform";
   efiFirmware = "${efiPrefix}_CODE.fd";
@@ -296,7 +296,7 @@ in
     virtualisation.memorySize =
       mkOption {
         type = types.ints.positive;
-        default = 384;
+        default = 1024;
         description =
           ''
             The memory size in megabytes of the virtual machine.
@@ -833,7 +833,7 @@ in
 
     # FIXME: Consolidate this one day.
     virtualisation.qemu.options = mkMerge [
-      (mkIf (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [
+      (mkIf pkgs.stdenv.hostPlatform.isx86 [
         "-usb" "-device usb-tablet,bus=usb-bus.0"
       ])
       (mkIf (pkgs.stdenv.isAarch32 || pkgs.stdenv.isAarch64) [
@@ -845,7 +845,7 @@ in
         ''-append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.toplevel}/init regInfo=${regInfo}/registration ${consoles} $QEMU_KERNEL_PARAMS"''
       ])
       (mkIf cfg.useEFIBoot [
-        "-drive if=pflash,format=raw,unit=0,readonly,file=${efiFirmware}"
+        "-drive if=pflash,format=raw,unit=0,readonly=on,file=${efiFirmware}"
         "-drive if=pflash,format=raw,unit=1,file=$NIX_EFI_VARS"
       ])
       (mkIf (cfg.bios != null) [
diff --git a/nixos/modules/virtualisation/virtualbox-guest.nix b/nixos/modules/virtualisation/virtualbox-guest.nix
index 486951983d30..f702fb4e525c 100644
--- a/nixos/modules/virtualisation/virtualbox-guest.nix
+++ b/nixos/modules/virtualisation/virtualbox-guest.nix
@@ -33,7 +33,7 @@ in
 
   config = mkIf cfg.enable (mkMerge [{
     assertions = [{
-      assertion = pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64;
+      assertion = pkgs.stdenv.hostPlatform.isx86;
       message = "Virtualbox not currently supported on ${pkgs.stdenv.hostPlatform.system}";
     }];
 
diff --git a/nixos/modules/virtualisation/vmware-guest.nix b/nixos/modules/virtualisation/vmware-guest.nix
index 480a9703cef3..481dedf84054 100644
--- a/nixos/modules/virtualisation/vmware-guest.nix
+++ b/nixos/modules/virtualisation/vmware-guest.nix
@@ -23,7 +23,7 @@ in
 
   config = mkIf cfg.enable {
     assertions = [ {
-      assertion = pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64;
+      assertion = pkgs.stdenv.hostPlatform.isx86;
       message = "VMWare guest is not currently supported on ${pkgs.stdenv.hostPlatform.system}";
     } ];
 
@@ -34,6 +34,8 @@ in
     systemd.services.vmware =
       { description = "VMWare Guest Service";
         wantedBy = [ "multi-user.target" ];
+        after = [ "display-manager.service" ];
+        unitConfig.ConditionVirtualization = "vmware";
         serviceConfig.ExecStart = "${open-vm-tools}/bin/vmtoolsd";
       };
 
@@ -42,8 +44,7 @@ in
       {
         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" ];
+        unitConfig.ConditionVirtualization = "vmware";
         what = "${open-vm-tools}/bin/vmware-vmblock-fuse";
         where = "/run/vmblock-fuse";
         type = "fuse";