summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/config/fonts/fontdir.nix1
-rw-r--r--nixos/modules/config/gtk/gtk-icon-cache.nix1
-rw-r--r--nixos/modules/config/i18n.nix6
-rw-r--r--nixos/modules/config/users-groups.nix1
-rw-r--r--nixos/modules/hardware/gpgsmartcards.nix37
-rw-r--r--nixos/modules/hardware/keyboard/zsa.nix3
-rw-r--r--nixos/modules/hardware/pcmcia.nix1
-rw-r--r--nixos/modules/misc/documentation.nix20
-rw-r--r--nixos/modules/misc/extra-arguments.nix4
-rw-r--r--nixos/modules/misc/ids.nix2
-rw-r--r--nixos/modules/misc/meta.nix2
-rw-r--r--nixos/modules/module-list.nix5
-rw-r--r--nixos/modules/programs/bcc.nix6
-rw-r--r--nixos/modules/security/acme.nix47
-rw-r--r--nixos/modules/security/pam.nix62
-rw-r--r--nixos/modules/security/systemd-confinement.nix6
-rw-r--r--nixos/modules/services/audio/icecast.nix1
-rw-r--r--nixos/modules/services/audio/navidrome.nix2
-rw-r--r--nixos/modules/services/audio/ympd.nix1
-rw-r--r--nixos/modules/services/backup/bacula.nix3
-rw-r--r--nixos/modules/services/backup/borgbackup.nix1
-rw-r--r--nixos/modules/services/backup/restic.nix4
-rw-r--r--nixos/modules/services/cluster/kubernetes/kubelet.nix1
-rw-r--r--nixos/modules/services/cluster/kubernetes/pki.nix1
-rw-r--r--nixos/modules/services/cluster/kubernetes/proxy.nix1
-rw-r--r--nixos/modules/services/computing/slurm/slurm.nix1
-rw-r--r--nixos/modules/services/continuous-integration/github-runner.nix1
-rw-r--r--nixos/modules/services/continuous-integration/hydra/default.nix1
-rw-r--r--nixos/modules/services/databases/postgresql.nix8
-rw-r--r--nixos/modules/services/development/hoogle.nix1
-rw-r--r--nixos/modules/services/games/factorio.nix4
-rw-r--r--nixos/modules/services/hardware/rasdaemon.nix1
-rw-r--r--nixos/modules/services/logging/journalwatch.nix1
-rw-r--r--nixos/modules/services/logging/klogd.nix1
-rw-r--r--nixos/modules/services/mail/maddy.nix247
-rw-r--r--nixos/modules/services/mail/opendkim.nix1
-rw-r--r--nixos/modules/services/misc/dysnomia.nix6
-rw-r--r--nixos/modules/services/misc/etcd.nix1
-rw-r--r--nixos/modules/services/misc/gitea.nix2
-rw-r--r--nixos/modules/services/misc/gitlab.nix2
-rw-r--r--nixos/modules/services/misc/matrix-appservice-discord.nix3
-rw-r--r--nixos/modules/services/misc/matrix-synapse.nix6
-rw-r--r--nixos/modules/services/misc/mautrix-telegram.nix3
-rw-r--r--nixos/modules/services/misc/moonraker.nix1
-rw-r--r--nixos/modules/services/misc/mx-puppet-discord.nix9
-rw-r--r--nixos/modules/services/misc/nitter.nix2
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix52
-rw-r--r--nixos/modules/services/misc/sourcehut/default.nix3
-rw-r--r--nixos/modules/services/misc/xmrig.nix1
-rw-r--r--nixos/modules/services/misc/zigbee2mqtt.nix11
-rw-r--r--nixos/modules/services/monitoring/collectd.nix5
-rw-r--r--nixos/modules/services/monitoring/graphite.nix1
-rw-r--r--nixos/modules/services/monitoring/nagios.nix1
-rw-r--r--nixos/modules/services/monitoring/parsedmarc.nix1
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters.nix1
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix64
-rw-r--r--nixos/modules/services/monitoring/smartd.nix3
-rw-r--r--nixos/modules/services/network-filesystems/drbd.nix12
-rw-r--r--nixos/modules/services/network-filesystems/glusterfs.nix2
-rw-r--r--nixos/modules/services/network-filesystems/ipfs.nix5
-rw-r--r--nixos/modules/services/network-filesystems/openafs/server.nix2
-rw-r--r--nixos/modules/services/networking/adguardhome.nix2
-rw-r--r--nixos/modules/services/networking/bind.nix1
-rw-r--r--nixos/modules/services/networking/coturn.nix1
-rw-r--r--nixos/modules/services/networking/ddclient.nix4
-rw-r--r--nixos/modules/services/networking/dnscrypt-wrapper.nix1
-rw-r--r--nixos/modules/services/networking/eternal-terminal.nix2
-rw-r--r--nixos/modules/services/networking/flannel.nix3
-rw-r--r--nixos/modules/services/networking/freeradius.nix2
-rw-r--r--nixos/modules/services/networking/jitsi-videobridge.nix2
-rw-r--r--nixos/modules/services/networking/knot.nix49
-rw-r--r--nixos/modules/services/networking/ncdns.nix1
-rw-r--r--nixos/modules/services/networking/nsd.nix1
-rw-r--r--nixos/modules/services/networking/ntp/chrony.nix1
-rw-r--r--nixos/modules/services/networking/ntp/ntpd.nix1
-rw-r--r--nixos/modules/services/networking/ntp/openntpd.nix1
-rw-r--r--nixos/modules/services/networking/pleroma.nix11
-rw-r--r--nixos/modules/services/networking/resilio.nix1
-rw-r--r--nixos/modules/services/networking/seafile.nix1
-rw-r--r--nixos/modules/services/networking/skydns.nix1
-rw-r--r--nixos/modules/services/networking/smokeping.nix6
-rw-r--r--nixos/modules/services/networking/soju.nix1
-rw-r--r--nixos/modules/services/networking/unifi.nix1
-rw-r--r--nixos/modules/services/networking/xrdp.nix9
-rw-r--r--nixos/modules/services/security/oauth2_proxy_nginx.nix1
-rw-r--r--nixos/modules/services/security/torsocks.nix1
-rw-r--r--nixos/modules/services/torrent/transmission.nix42
-rw-r--r--nixos/modules/services/video/epgstation/default.nix2
-rw-r--r--nixos/modules/services/video/mirakurun.nix2
-rw-r--r--nixos/modules/services/web-apps/discourse.nix16
-rw-r--r--nixos/modules/services/web-apps/discourse.xml2
-rw-r--r--nixos/modules/services/web-apps/dokuwiki.nix4
-rw-r--r--nixos/modules/services/web-apps/ihatemoney/default.nix1
-rw-r--r--nixos/modules/services/web-apps/invidious.nix2
-rw-r--r--nixos/modules/services/web-apps/openwebrx.nix1
-rw-r--r--nixos/modules/services/web-apps/peertube.nix1
-rw-r--r--nixos/modules/services/web-apps/tt-rss.nix8
-rw-r--r--nixos/modules/services/web-servers/nginx/location-options.nix2
-rw-r--r--nixos/modules/services/web-servers/uwsgi.nix2
-rw-r--r--nixos/modules/services/web-servers/varnish/default.nix1
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.nix5
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.xml8
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix233
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/xmonad.nix2
-rw-r--r--nixos/modules/system/activation/activation-script.nix2
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl29
-rw-r--r--nixos/modules/system/activation/top-level.nix8
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix1
-rw-r--r--nixos/modules/system/boot/networkd.nix52
-rw-r--r--nixos/modules/system/boot/resolved.nix1
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh12
-rw-r--r--nixos/modules/system/boot/stage-1.nix4
-rw-r--r--nixos/modules/system/boot/systemd-lib.nix237
-rw-r--r--nixos/modules/system/boot/systemd-nspawn.nix6
-rw-r--r--nixos/modules/system/boot/systemd-unit-options.nix536
-rw-r--r--nixos/modules/system/boot/systemd.nix4
-rw-r--r--nixos/modules/system/boot/timesyncd.nix2
-rw-r--r--nixos/modules/tasks/snapraid.nix2
-rw-r--r--nixos/modules/virtualisation/amazon-options.nix3
-rw-r--r--nixos/modules/virtualisation/nixos-containers.nix4
-rw-r--r--nixos/modules/virtualisation/podman/default.nix (renamed from nixos/modules/virtualisation/podman.nix)4
-rw-r--r--nixos/modules/virtualisation/podman/dnsname.nix (renamed from nixos/modules/virtualisation/podman-dnsname.nix)0
-rw-r--r--nixos/modules/virtualisation/podman/network-socket-ghostunnel.nix (renamed from nixos/modules/virtualisation/podman-network-socket-ghostunnel.nix)0
-rw-r--r--nixos/modules/virtualisation/podman/network-socket.nix (renamed from nixos/modules/virtualisation/podman-network-socket.nix)4
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix3
126 files changed, 1072 insertions, 968 deletions
diff --git a/nixos/modules/config/fonts/fontdir.nix b/nixos/modules/config/fonts/fontdir.nix
index db4b6c638ab..560918302ca 100644
--- a/nixos/modules/config/fonts/fontdir.nix
+++ b/nixos/modules/config/fonts/fontdir.nix
@@ -39,6 +39,7 @@ in
       decompressFonts = mkOption {
         type = types.bool;
         default = config.programs.xwayland.enable;
+        defaultText = literalExpression "config.programs.xwayland.enable";
         description = ''
           Whether to decompress fonts in
           <filename>/run/current-system/sw/share/X11/fonts</filename>.
diff --git a/nixos/modules/config/gtk/gtk-icon-cache.nix b/nixos/modules/config/gtk/gtk-icon-cache.nix
index 7441f4de40e..ff9aa7c6a04 100644
--- a/nixos/modules/config/gtk/gtk-icon-cache.nix
+++ b/nixos/modules/config/gtk/gtk-icon-cache.nix
@@ -6,6 +6,7 @@ with lib;
     gtk.iconCache.enable = mkOption {
       type = types.bool;
       default = config.services.xserver.enable;
+      defaultText = literalExpression "config.services.xserver.enable";
       description = ''
         Whether to build icon theme caches for GTK applications.
       '';
diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix
index 545d4a3dca6..5b8d5b21449 100644
--- a/nixos/modules/config/i18n.nix
+++ b/nixos/modules/config/i18n.nix
@@ -14,6 +14,12 @@ with lib;
           allLocales = any (x: x == "all") config.i18n.supportedLocales;
           locales = config.i18n.supportedLocales;
         };
+        defaultText = literalExpression ''
+          pkgs.buildPackages.glibcLocales.override {
+            allLocales = any (x: x == "all") config.i18n.supportedLocales;
+            locales = config.i18n.supportedLocales;
+          }
+        '';
         example = literalExpression "pkgs.glibcLocales";
         description = ''
           Customized pkg.glibcLocales package.
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 629905e6095..a34d2814341 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -558,6 +558,7 @@ in {
       input.gid = ids.gids.input;
       kvm.gid = ids.gids.kvm;
       render.gid = ids.gids.render;
+      sgx.gid = ids.gids.sgx;
       shadow.gid = ids.gids.shadow;
     };
 
diff --git a/nixos/modules/hardware/gpgsmartcards.nix b/nixos/modules/hardware/gpgsmartcards.nix
new file mode 100644
index 00000000000..6e5fcda6b85
--- /dev/null
+++ b/nixos/modules/hardware/gpgsmartcards.nix
@@ -0,0 +1,37 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  # gnupg's manual describes how to setup ccid udev rules:
+  #   https://www.gnupg.org/howtos/card-howto/en/ch02s03.html
+  # gnupg folks advised me (https://dev.gnupg.org/T5409) to look at debian's rules:
+  # https://salsa.debian.org/debian/gnupg2/-/blob/debian/main/debian/scdaemon.udev
+
+  # the latest rev of the entire debian gnupg2 repo as of 2021-04-28
+  # the scdaemon.udev file was last commited on 2021-01-05 (7817a03):
+  scdaemonUdevRev = "01898735a015541e3ffb43c7245ac1e612f40836";
+
+  scdaemonRules = pkgs.fetchurl {
+    url = "https://salsa.debian.org/debian/gnupg2/-/raw/${scdaemonUdevRev}/debian/scdaemon.udev";
+    sha256 = "08v0vp6950bz7galvc92zdss89y9vcwbinmbfcdldy8x72w6rqr3";
+  };
+
+  # per debian's udev deb hook (https://man7.org/linux/man-pages/man1/dh_installudev.1.html)
+  destination = "60-scdaemon.rules";
+
+  scdaemonUdevRulesPkg = pkgs.runCommandNoCC "scdaemon-udev-rules" {} ''
+    loc="$out/lib/udev/rules.d/"
+    mkdir -p "''${loc}"
+    cp "${scdaemonRules}" "''${loc}/${destination}"
+  '';
+
+  cfg = config.hardware.gpgSmartcards;
+in {
+  options.hardware.gpgSmartcards = {
+    enable = mkEnableOption "udev rules for gnupg smart cards";
+  };
+
+  config = mkIf cfg.enable {
+    services.udev.packages = [ scdaemonUdevRulesPkg ];
+  };
+}
diff --git a/nixos/modules/hardware/keyboard/zsa.nix b/nixos/modules/hardware/keyboard/zsa.nix
index 5cb09e5af49..bb69cfa0bf0 100644
--- a/nixos/modules/hardware/keyboard/zsa.nix
+++ b/nixos/modules/hardware/keyboard/zsa.nix
@@ -5,7 +5,6 @@ let
   cfg = config.hardware.keyboard.zsa;
 in
 {
-  # TODO: make group configurable like in https://github.com/NixOS/nixpkgs/blob/0b2b4b8c4e729535a61db56468809c5c2d3d175c/pkgs/tools/security/nitrokey-app/udev-rules.nix ?
   options.hardware.keyboard.zsa = {
     enable = mkOption {
       type = types.bool;
@@ -14,7 +13,6 @@ in
         Enables udev rules for keyboards from ZSA like the ErgoDox EZ, Planck EZ and Moonlander Mark I.
         You need it when you want to flash a new configuration on the keyboard
         or use their live training in the browser.
-        Access to the keyboard is granted to users in the "plugdev" group.
         You may want to install the wally-cli package.
       '';
     };
@@ -22,6 +20,5 @@ in
 
   config = mkIf cfg.enable {
     services.udev.packages = [ pkgs.zsa-udev-rules ];
-    users.groups.plugdev = {};
   };
 }
diff --git a/nixos/modules/hardware/pcmcia.nix b/nixos/modules/hardware/pcmcia.nix
index d7d002ae6c8..aef35a28e54 100644
--- a/nixos/modules/hardware/pcmcia.nix
+++ b/nixos/modules/hardware/pcmcia.nix
@@ -35,6 +35,7 @@ in
 
       config = mkOption {
         default = null;
+        type = types.nullOr types.path;
         description = ''
           Path to the configuration file which maps the memory, IRQs
           and ports used by the PCMCIA hardware.
diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix
index 1f837f9efa2..64b1c15086f 100644
--- a/nixos/modules/misc/documentation.nix
+++ b/nixos/modules/misc/documentation.nix
@@ -1,4 +1,4 @@
-{ config, lib, pkgs, baseModules, extraModules, modules, modulesPath, ... }:
+{ config, lib, pkgs, extendModules, noUserModules, ... }:
 
 with lib;
 
@@ -6,11 +6,8 @@ let
 
   cfg = config.documentation;
 
-  manualModules =
-    baseModules
-    # Modules for which to show options even when not imported
-    ++ [ ../virtualisation/qemu-vm.nix ]
-    ++ optionals cfg.nixos.includeAllModules (extraModules ++ modules);
+  /* Modules for which to show options even when not imported. */
+  extraDocModules = [ ../virtualisation/qemu-vm.nix ];
 
   /* For the purpose of generating docs, evaluate options with each derivation
     in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}".
@@ -24,13 +21,10 @@ let
     extraSources = cfg.nixos.extraModuleSources;
     options =
       let
-        scrubbedEval = evalModules {
-          modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ manualModules;
-          args = (config._module.args) // { modules = [ ]; };
-          specialArgs = {
-            pkgs = scrubDerivations "pkgs" pkgs;
-            inherit modulesPath;
-          };
+        extendNixOS = if cfg.nixos.includeAllModules then extendModules else noUserModules.extendModules;
+        scrubbedEval = extendNixOS {
+          modules = extraDocModules;
+          specialArgs.pkgs = scrubDerivations "pkgs" pkgs;
         };
         scrubDerivations = namePrefix: pkgSet: mapAttrs
           (name: value:
diff --git a/nixos/modules/misc/extra-arguments.nix b/nixos/modules/misc/extra-arguments.nix
index 8716e3d9fef..48891b44049 100644
--- a/nixos/modules/misc/extra-arguments.nix
+++ b/nixos/modules/misc/extra-arguments.nix
@@ -1,7 +1,7 @@
-{ pkgs, ... }:
+{ lib, config, pkgs, ... }:
 
 {
   _module.args = {
-    utils = import ../../lib/utils.nix pkgs;
+    utils = import ../../lib/utils.nix { inherit lib config pkgs; };
   };
 }
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 273ed95e1bc..a9f2031d1e1 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -639,7 +639,7 @@ in
       qemu-libvirtd = 301;
       kvm = 302; # default udev rules from systemd requires these
       render = 303; # default udev rules from systemd requires these
-      # zeronet = 304; # removed 2019-01-03
+      sgx = 304; # default udev rules from systemd requires these
       lirc = 305;
       lidarr = 306;
       slurm = 307;
diff --git a/nixos/modules/misc/meta.nix b/nixos/modules/misc/meta.nix
index 1410e33342a..3dd97cbec23 100644
--- a/nixos/modules/misc/meta.nix
+++ b/nixos/modules/misc/meta.nix
@@ -37,7 +37,7 @@ in
         type = listOfMaintainers;
         internal = true;
         default = [];
-        example = [ lib.maintainers.all ];
+        example = literalExpression ''[ lib.maintainers.all ]'';
         description = ''
           List of maintainers of each module.  This option should be defined at
           most once per module.
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index f36e7dd67ea..3cc9ea88e17 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -50,6 +50,7 @@
   ./hardware/device-tree.nix
   ./hardware/gkraken.nix
   ./hardware/flirc.nix
+  ./hardware/gpgsmartcards.nix
   ./hardware/i2c.nix
   ./hardware/sensor/hddtemp.nix
   ./hardware/sensor/iio.nix
@@ -467,6 +468,7 @@
   ./services/mail/dovecot.nix
   ./services/mail/dspam.nix
   ./services/mail/exim.nix
+  ./services/mail/maddy.nix
   ./services/mail/mail.nix
   ./services/mail/mailcatcher.nix
   ./services/mail/mailhog.nix
@@ -1191,8 +1193,7 @@
   ./virtualisation/kvmgt.nix
   ./virtualisation/openvswitch.nix
   ./virtualisation/parallels-guest.nix
-  ./virtualisation/podman.nix
-  ./virtualisation/podman-network-socket-ghostunnel.nix
+  ./virtualisation/podman/default.nix
   ./virtualisation/qemu-guest-agent.nix
   ./virtualisation/railcar.nix
   ./virtualisation/spice-usb-redirection.nix
diff --git a/nixos/modules/programs/bcc.nix b/nixos/modules/programs/bcc.nix
index d76249bb5ca..e475c6ceaa6 100644
--- a/nixos/modules/programs/bcc.nix
+++ b/nixos/modules/programs/bcc.nix
@@ -1,9 +1,9 @@
-{ config, lib, ... }:
+{ config, pkgs, lib, ... }:
 {
   options.programs.bcc.enable = lib.mkEnableOption "bcc";
 
   config = lib.mkIf config.programs.bcc.enable {
-    environment.systemPackages = [ config.boot.kernelPackages.bcc ];
-    boot.extraModulePackages = [ config.boot.kernelPackages.bcc ];
+    environment.systemPackages = [ pkgs.bcc ];
+    boot.extraModulePackages = [ pkgs.bcc ];
   };
 }
diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix
index 2815e2593b2..b50eeddfa40 100644
--- a/nixos/modules/security/acme.nix
+++ b/nixos/modules/security/acme.nix
@@ -163,9 +163,8 @@ let
       [ "--dns" data.dnsProvider ]
       ++ optionals (!data.dnsPropagationCheck) [ "--dns.disable-cp" ]
       ++ optionals (data.dnsResolver != null) [ "--dns.resolvers" data.dnsResolver ]
-    ) else (
-      [ "--http" "--http.webroot" data.webroot ]
-    );
+    ) else if data.listenHTTP != null then [ "--http" "--http.port" data.listenHTTP ]
+    else [ "--http" "--http.webroot" data.webroot ];
 
     commonOpts = [
       "--accept-tos" # Checking the option is covered by the assertions
@@ -321,11 +320,14 @@ let
             }
           fi
         '');
+      } // optionalAttrs (data.listenHTTP != null && toInt (elemAt (splitString ":" data.listenHTTP) 1) < 1024) {
+        AmbientCapabilities = "CAP_NET_BIND_SERVICE";
       };
 
       # Working directory will be /tmp
       script = ''
-        set -euxo pipefail
+        ${optionalString data.enableDebugLogs "set -x"}
+        set -euo pipefail
 
         # This reimplements the expiration date check, but without querying
         # the acme server first. By doing this offline, we avoid errors
@@ -438,6 +440,8 @@ let
         default = "_mkMergedOptionModule";
       };
 
+      enableDebugLogs = mkEnableOption "debug logging for this certificate" // { default = cfg.enableDebugLogs; };
+
       webroot = mkOption {
         type = types.nullOr types.str;
         default = null;
@@ -451,6 +455,17 @@ let
         '';
       };
 
+      listenHTTP = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = ":1360";
+        description = ''
+          Interface and port to listen on to solve HTTP challenges
+          in the form [INTERFACE]:PORT.
+          If you use a port other than 80, you must proxy port 80 to this port.
+        '';
+      };
+
       server = mkOption {
         type = types.nullOr types.str;
         default = null;
@@ -616,6 +631,8 @@ in {
   options = {
     security.acme = {
 
+      enableDebugLogs = mkEnableOption "debug logging for all certificates by default" // { default = true; };
+
       validMinDays = mkOption {
         type = types.int;
         default = 30;
@@ -778,6 +795,28 @@ in {
             `security.acme.certs.${cert}.webroot` are mutually exclusive.
           '';
         }
+        {
+          assertion = data.webroot == null || data.listenHTTP == null;
+          message = ''
+            Options `security.acme.certs.${cert}.webroot` and
+            `security.acme.certs.${cert}.listenHTTP` are mutually exclusive.
+          '';
+        }
+        {
+          assertion = data.listenHTTP == null || data.dnsProvider == null;
+          message = ''
+            Options `security.acme.certs.${cert}.listenHTTP` and
+            `security.acme.certs.${cert}.dnsProvider` are mutually exclusive.
+          '';
+        }
+        {
+          assertion = data.dnsProvider != null || data.webroot != null || data.listenHTTP != null;
+          message = ''
+            One of `security.acme.certs.${cert}.dnsProvider`,
+            `security.acme.certs.${cert}.webroot`, or
+            `security.acme.certs.${cert}.listenHTTP` must be provided.
+          '';
+        }
       ]) cfg.certs));
 
       users.users.acme = {
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index b03bf290fd2..0944b36c6d1 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -38,6 +38,7 @@ let
 
       p11Auth = mkOption {
         default = config.security.pam.p11.enable;
+        defaultText = literalExpression "config.security.pam.p11.enable";
         type = types.bool;
         description = ''
           If set, keys listed in
@@ -49,6 +50,7 @@ let
 
       u2fAuth = mkOption {
         default = config.security.pam.u2f.enable;
+        defaultText = literalExpression "config.security.pam.u2f.enable";
         type = types.bool;
         description = ''
           If set, users listed in
@@ -61,6 +63,7 @@ let
 
       yubicoAuth = mkOption {
         default = config.security.pam.yubico.enable;
+        defaultText = literalExpression "config.security.pam.yubico.enable";
         type = types.bool;
         description = ''
           If set, users listed in
@@ -83,6 +86,7 @@ let
 
       usbAuth = mkOption {
         default = config.security.pam.usb.enable;
+        defaultText = literalExpression "config.security.pam.usb.enable";
         type = types.bool;
         description = ''
           If set, users listed in
@@ -93,6 +97,7 @@ let
 
       otpwAuth = mkOption {
         default = config.security.pam.enableOTPW;
+        defaultText = literalExpression "config.security.pam.enableOTPW";
         type = types.bool;
         description = ''
           If set, the OTPW system will be used (if
@@ -126,6 +131,7 @@ let
 
       fprintAuth = mkOption {
         default = config.services.fprintd.enable;
+        defaultText = literalExpression "config.services.fprintd.enable";
         type = types.bool;
         description = ''
           If set, fingerprint reader will be used (if exists and
@@ -135,6 +141,7 @@ let
 
       oathAuth = mkOption {
         default = config.security.pam.oath.enable;
+        defaultText = literalExpression "config.security.pam.oath.enable";
         type = types.bool;
         description = ''
           If set, the OATH Toolkit will be used.
@@ -249,6 +256,7 @@ let
 
       pamMount = mkOption {
         default = config.security.pam.mount.enable;
+        defaultText = literalExpression "config.security.pam.mount.enable";
         type = types.bool;
         description = ''
           Enable PAM mount (pam_mount) system to mount fileystems on user login.
@@ -287,9 +295,14 @@ let
       };
 
       limits = mkOption {
+        default = [];
+        type = limitsType;
         description = ''
           Attribute set describing resource limits.  Defaults to the
           value of <option>security.pam.loginLimits</option>.
+          The meaning of the values is explained in <citerefentry>
+          <refentrytitle>limits.conf</refentrytitle><manvolnum>5</manvolnum>
+          </citerefentry>.
         '';
       };
 
@@ -640,6 +653,51 @@ let
          "${domain} ${type} ${item} ${toString value}\n")
          limits);
 
+  limitsType = with lib.types; listOf (submodule ({ ... }: {
+    options = {
+      domain = mkOption {
+        description = "Username, groupname, or wildcard this limit applies to";
+        example = "@wheel";
+        type = str;
+      };
+
+      type = mkOption {
+        description = "Type of this limit";
+        type = enum [ "-" "hard" "soft" ];
+        default = "-";
+      };
+
+      item = mkOption {
+        description = "Item this limit applies to";
+        type = enum [
+          "core"
+          "data"
+          "fsize"
+          "memlock"
+          "nofile"
+          "rss"
+          "stack"
+          "cpu"
+          "nproc"
+          "as"
+          "maxlogins"
+          "maxsyslogins"
+          "priority"
+          "locks"
+          "sigpending"
+          "msgqueue"
+          "nice"
+          "rtprio"
+        ];
+      };
+
+      value = mkOption {
+        description = "Value of this limit";
+        type = oneOf [ str int ];
+      };
+    };
+  }));
+
   motd = pkgs.writeText "motd" config.users.motd;
 
   makePAMService = name: service:
@@ -661,6 +719,7 @@ in
 
     security.pam.loginLimits = mkOption {
       default = [];
+      type = limitsType;
       example =
         [ { domain = "ftp";
             type   = "hard";
@@ -680,7 +739,8 @@ in
           <varname>domain</varname>, <varname>type</varname>,
           <varname>item</varname>, and <varname>value</varname>
           attribute.  The syntax and semantics of these attributes
-          must be that described in the limits.conf(5) man page.
+          must be that described in <citerefentry><refentrytitle>limits.conf</refentrytitle>
+          <manvolnum>5</manvolnum></citerefentry>.
 
           Note that these limits do not apply to systemd services,
           whose limits can be changed via <option>systemd.extraConfig</option>
diff --git a/nixos/modules/security/systemd-confinement.nix b/nixos/modules/security/systemd-confinement.nix
index d859c45c74f..0e3ec5af323 100644
--- a/nixos/modules/security/systemd-confinement.nix
+++ b/nixos/modules/security/systemd-confinement.nix
@@ -1,11 +1,9 @@
-{ config, pkgs, lib, ... }:
+{ config, pkgs, lib, utils, ... }:
 
 let
   toplevelConfig = config;
   inherit (lib) types;
-  inherit (import ../system/boot/systemd-lib.nix {
-    inherit config pkgs lib;
-  }) mkPathSafeName;
+  inherit (utils.systemdUtils.lib) mkPathSafeName;
 in {
   options.systemd.services = lib.mkOption {
     type = types.attrsOf (types.submodule ({ name, config, ... }: {
diff --git a/nixos/modules/services/audio/icecast.nix b/nixos/modules/services/audio/icecast.nix
index 6ca20a7a108..5ee5bd745f9 100644
--- a/nixos/modules/services/audio/icecast.nix
+++ b/nixos/modules/services/audio/icecast.nix
@@ -50,6 +50,7 @@ in {
         type = types.nullOr types.str;
         description = "DNS name or IP address that will be used for the stream directory lookups or possibily the playlist generation if a Host header is not provided.";
         default = config.networking.domain;
+        defaultText = literalExpression "config.networking.domain";
       };
 
       admin = {
diff --git a/nixos/modules/services/audio/navidrome.nix b/nixos/modules/services/audio/navidrome.nix
index c2fe429f984..3660e05310b 100644
--- a/nixos/modules/services/audio/navidrome.nix
+++ b/nixos/modules/services/audio/navidrome.nix
@@ -9,7 +9,7 @@ in {
   options = {
     services.navidrome = {
 
-      enable = mkEnableOption pkgs.navidrome.meta.description;
+      enable = mkEnableOption "Navidrome music server";
 
       settings = mkOption rec {
         type = settingsFormat.type;
diff --git a/nixos/modules/services/audio/ympd.nix b/nixos/modules/services/audio/ympd.nix
index 36c5527027f..84b72d14251 100644
--- a/nixos/modules/services/audio/ympd.nix
+++ b/nixos/modules/services/audio/ympd.nix
@@ -31,6 +31,7 @@ in {
         port = mkOption {
           type = types.int;
           default = config.services.mpd.network.port;
+          defaultText = literalExpression "config.services.mpd.network.port";
           description = "The port where MPD is listening.";
           example = 6600;
         };
diff --git a/nixos/modules/services/backup/bacula.nix b/nixos/modules/services/backup/bacula.nix
index cc8b77cbfbe..59890204234 100644
--- a/nixos/modules/services/backup/bacula.nix
+++ b/nixos/modules/services/backup/bacula.nix
@@ -302,6 +302,7 @@ in {
 
       name = mkOption {
         default = "${config.networking.hostName}-fd";
+        defaultText = literalExpression ''"''${config.networking.hostName}-fd"'';
         type = types.str;
         description = ''
           The client name that must be used by the Director when connecting.
@@ -364,6 +365,7 @@ in {
 
       name = mkOption {
         default = "${config.networking.hostName}-sd";
+        defaultText = literalExpression ''"''${config.networking.hostName}-sd"'';
         type = types.str;
         description = ''
           Specifies the Name of the Storage daemon.
@@ -439,6 +441,7 @@ in {
 
       name = mkOption {
         default = "${config.networking.hostName}-dir";
+        defaultText = literalExpression ''"''${config.networking.hostName}-dir"'';
         type = types.str;
         description = ''
           The director name used by the system administrator. This directive is
diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix
index b2147c1bbfc..220c571b927 100644
--- a/nixos/modules/services/backup/borgbackup.nix
+++ b/nixos/modules/services/backup/borgbackup.nix
@@ -152,7 +152,6 @@ 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/backup/restic.nix b/nixos/modules/services/backup/restic.nix
index 67fef55614b..8ff8e31864b 100644
--- a/nixos/modules/services/backup/restic.nix
+++ b/nixos/modules/services/backup/restic.nix
@@ -1,10 +1,10 @@
-{ config, lib, pkgs, ... }:
+{ config, lib, pkgs, utils, ... }:
 
 with lib;
 
 let
   # Type for a valid systemd unit option. Needed for correctly passing "timerConfig" to "systemd.timers"
-  unitOption = (import ../../system/boot/systemd-unit-options.nix { inherit config lib; }).unitOption;
+  inherit (utils.systemdUtils.unitOptions) unitOption;
 in
 {
   options.services.restic.backups = mkOption {
diff --git a/nixos/modules/services/cluster/kubernetes/kubelet.nix b/nixos/modules/services/cluster/kubernetes/kubelet.nix
index eb0cb1f3dbc..2806f73375b 100644
--- a/nixos/modules/services/cluster/kubernetes/kubelet.nix
+++ b/nixos/modules/services/cluster/kubernetes/kubelet.nix
@@ -168,6 +168,7 @@ in
     hostname = mkOption {
       description = "Kubernetes kubelet hostname override.";
       default = config.networking.hostName;
+      defaultText = literalExpression "config.networking.hostName";
       type = str;
     };
 
diff --git a/nixos/modules/services/cluster/kubernetes/pki.nix b/nixos/modules/services/cluster/kubernetes/pki.nix
index faf951d8157..76ab03cd520 100644
--- a/nixos/modules/services/cluster/kubernetes/pki.nix
+++ b/nixos/modules/services/cluster/kubernetes/pki.nix
@@ -98,6 +98,7 @@ in
         the public and private keys respectively.
       '';
       default = "${config.services.cfssl.dataDir}/ca";
+      defaultText = literalExpression ''"''${config.services.cfssl.dataDir}/ca"'';
       type = str;
     };
 
diff --git a/nixos/modules/services/cluster/kubernetes/proxy.nix b/nixos/modules/services/cluster/kubernetes/proxy.nix
index a92043d5259..a09efcef94e 100644
--- a/nixos/modules/services/cluster/kubernetes/proxy.nix
+++ b/nixos/modules/services/cluster/kubernetes/proxy.nix
@@ -37,6 +37,7 @@ in
     hostname = mkOption {
       description = "Kubernetes proxy hostname override.";
       default = config.networking.hostName;
+      defaultText = literalExpression "config.networking.hostName";
       type = str;
     };
 
diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix
index 0c96f323132..d2f3feffc97 100644
--- a/nixos/modules/services/computing/slurm/slurm.nix
+++ b/nixos/modules/services/computing/slurm/slurm.nix
@@ -80,6 +80,7 @@ in
         dbdHost = mkOption {
           type = types.str;
           default = config.networking.hostName;
+          defaultText = literalExpression "config.networking.hostName";
           description = ''
             Hostname of the machine where <literal>slurmdbd</literal>
             is running (i.e. name returned by <literal>hostname -s</literal>).
diff --git a/nixos/modules/services/continuous-integration/github-runner.nix b/nixos/modules/services/continuous-integration/github-runner.nix
index 943c1e4598d..59370f43fe7 100644
--- a/nixos/modules/services/continuous-integration/github-runner.nix
+++ b/nixos/modules/services/continuous-integration/github-runner.nix
@@ -58,6 +58,7 @@ in
       '';
       example = "nixos";
       default = config.networking.hostName;
+      defaultText = literalExpression "config.networking.hostName";
     };
 
     runnerGroup = mkOption {
diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix
index d6cde77c0a3..ccb7cc21734 100644
--- a/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -203,6 +203,7 @@ in
       buildMachinesFiles = mkOption {
         type = types.listOf types.path;
         default = optional (config.nix.buildMachines != []) "/etc/nix/machines";
+        defaultText = literalExpression ''optional (config.nix.buildMachines != []) "/etc/nix/machines"'';
         example = [ "/etc/nix/machines" "/var/lib/hydra/provisioner/machines" ];
         description = "List of files containing build machines.";
       };
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index d49cb4c51a7..2919022496a 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -289,14 +289,16 @@ in
         port = cfg.port;
       };
 
-    services.postgresql.package =
+    services.postgresql.package = let
+        mkThrow = ver: throw "postgresql_${ver} was removed, please upgrade your postgresql version.";
+    in
       # Note: when changing the default, make it conditional on
       # ‘system.stateVersion’ to maintain compatibility with existing
       # systems!
       mkDefault (if versionAtLeast config.system.stateVersion "21.11" then pkgs.postgresql_13
             else if versionAtLeast config.system.stateVersion "20.03" then pkgs.postgresql_11
-            else if versionAtLeast config.system.stateVersion "17.09" then pkgs.postgresql_9_6
-            else throw "postgresql_9_5 was removed, please upgrade your postgresql version.");
+            else if versionAtLeast config.system.stateVersion "17.09" then mkThrow "9_6"
+            else mkThrow "9_5");
 
     services.postgresql.dataDir = mkDefault "/var/lib/postgresql/${cfg.package.psqlSchema}";
 
diff --git a/nixos/modules/services/development/hoogle.nix b/nixos/modules/services/development/hoogle.nix
index 7c635f7a5b8..7c2a1c8e162 100644
--- a/nixos/modules/services/development/hoogle.nix
+++ b/nixos/modules/services/development/hoogle.nix
@@ -40,6 +40,7 @@ in {
 
     haskellPackages = mkOption {
       description = "Which haskell package set to use.";
+      type = types.attrs;
       default = pkgs.haskellPackages;
       defaultText = literalExpression "pkgs.haskellPackages";
     };
diff --git a/nixos/modules/services/games/factorio.nix b/nixos/modules/services/games/factorio.nix
index 0e8860a0281..96fcd6d2c8b 100644
--- a/nixos/modules/services/games/factorio.nix
+++ b/nixos/modules/services/games/factorio.nix
@@ -75,8 +75,8 @@ in
         description = ''
           The name of the savegame that will be used by the server.
 
-          When not present in ${stateDir}/saves, a new map with default
-          settings will be generated before starting the service.
+          When not present in /var/lib/''${config.services.factorio.stateDirName}/saves,
+          a new map with default settings will be generated before starting the service.
         '';
       };
       # TODO Add more individual settings as nixos-options?
diff --git a/nixos/modules/services/hardware/rasdaemon.nix b/nixos/modules/services/hardware/rasdaemon.nix
index b1efe0f18c8..2d4c6d2ce95 100644
--- a/nixos/modules/services/hardware/rasdaemon.nix
+++ b/nixos/modules/services/hardware/rasdaemon.nix
@@ -137,7 +137,6 @@ in
         description = "the RAS logging daemon";
         documentation = [ "man:rasdaemon(1)" ];
         wantedBy = [ "multi-user.target" ];
-        after = [ "syslog.target" ];
 
         serviceConfig = {
           StateDirectory = optionalString (cfg.record) "rasdaemon";
diff --git a/nixos/modules/services/logging/journalwatch.nix b/nixos/modules/services/logging/journalwatch.nix
index 576c646c0f5..fb86904d1ea 100644
--- a/nixos/modules/services/logging/journalwatch.nix
+++ b/nixos/modules/services/logging/journalwatch.nix
@@ -74,6 +74,7 @@ in {
       mailFrom = mkOption {
         type = types.str;
         default = "journalwatch@${config.networking.hostName}";
+        defaultText = literalExpression ''"journalwatch@''${config.networking.hostName}"'';
         description = ''
           Mail address to send journalwatch reports from.
         '';
diff --git a/nixos/modules/services/logging/klogd.nix b/nixos/modules/services/logging/klogd.nix
index 2d1f515da92..8d371c161eb 100644
--- a/nixos/modules/services/logging/klogd.nix
+++ b/nixos/modules/services/logging/klogd.nix
@@ -10,6 +10,7 @@ with lib;
     services.klogd.enable = mkOption {
       type = types.bool;
       default = versionOlder (getVersion config.boot.kernelPackages.kernel) "3.5";
+      defaultText = literalExpression ''versionOlder (getVersion config.boot.kernelPackages.kernel) "3.5"'';
       description = ''
         Whether to enable klogd, the kernel log message processing
         daemon.  Since systemd handles logging of kernel messages on
diff --git a/nixos/modules/services/mail/maddy.nix b/nixos/modules/services/mail/maddy.nix
new file mode 100644
index 00000000000..44cfa3c2908
--- /dev/null
+++ b/nixos/modules/services/mail/maddy.nix
@@ -0,0 +1,247 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  name = "maddy";
+  cfg = config.services.maddy;
+  defaultConfig = ''
+    tls off
+
+    auth.pass_table local_authdb {
+      table sql_table {
+        driver sqlite3
+        dsn credentials.db
+        table_name passwords
+      }
+    }
+
+    storage.imapsql local_mailboxes {
+      driver sqlite3
+      dsn imapsql.db
+    }
+
+    table.chain local_rewrites {
+      optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
+      optional_step static {
+        entry postmaster postmaster@$(primary_domain)
+      }
+      optional_step file /etc/maddy/aliases
+    }
+    msgpipeline local_routing {
+      destination postmaster $(local_domains) {
+        modify {
+          replace_rcpt &local_rewrites
+        }
+        deliver_to &local_mailboxes
+      }
+      default_destination {
+        reject 550 5.1.1 "User doesn't exist"
+      }
+    }
+
+    smtp tcp://0.0.0.0:25 {
+      limits {
+        all rate 20 1s
+        all concurrency 10
+      }
+      dmarc yes
+      check {
+        require_mx_record
+        dkim
+        spf
+      }
+      source $(local_domains) {
+        reject 501 5.1.8 "Use Submission for outgoing SMTP"
+      }
+      default_source {
+        destination postmaster $(local_domains) {
+          deliver_to &local_routing
+        }
+        default_destination {
+          reject 550 5.1.1 "User doesn't exist"
+        }
+      }
+    }
+
+    submission tcp://0.0.0.0:587 {
+      limits {
+        all rate 50 1s
+      }
+      auth &local_authdb
+      source $(local_domains) {
+        check {
+            authorize_sender {
+                prepare_email &local_rewrites
+                user_to_email identity
+            }
+        }
+        destination postmaster $(local_domains) {
+            deliver_to &local_routing
+        }
+        default_destination {
+            modify {
+                dkim $(primary_domain) $(local_domains) default
+            }
+            deliver_to &remote_queue
+        }
+      }
+      default_source {
+        reject 501 5.1.8 "Non-local sender domain"
+      }
+    }
+
+    target.remote outbound_delivery {
+      limits {
+        destination rate 20 1s
+        destination concurrency 10
+      }
+      mx_auth {
+        dane
+        mtasts {
+          cache fs
+          fs_dir mtasts_cache/
+        }
+        local_policy {
+            min_tls_level encrypted
+            min_mx_level none
+        }
+      }
+    }
+
+    target.queue remote_queue {
+      target &outbound_delivery
+      autogenerated_msg_domain $(primary_domain)
+      bounce {
+        destination postmaster $(local_domains) {
+          deliver_to &local_routing
+        }
+        default_destination {
+            reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
+        }
+      }
+    }
+
+    imap tcp://0.0.0.0:143 {
+      auth &local_authdb
+      storage &local_mailboxes
+    }
+  '';
+
+in {
+  options = {
+    services.maddy = {
+      enable = mkEnableOption "Maddy, a free an open source mail server";
+
+      user = mkOption {
+        default = "maddy";
+        type = with types; uniq string;
+        description = ''
+          Name of the user under which maddy will run. If not specified, a
+          default user will be created.
+        '';
+      };
+      group = mkOption {
+        default = "maddy";
+        type = with types; uniq string;
+        description = ''
+          Name of the group under which maddy will run. If not specified, a
+          default group will be created.
+        '';
+      };
+
+      hostname = mkOption {
+        default = "localhost";
+        type = with types; uniq string;
+        example = ''example.com'';
+        description = ''
+          Hostname to use. It should be FQDN.
+        '';
+      };
+      primaryDomain = mkOption {
+        default = "localhost";
+        type = with types; uniq string;
+        example = ''mail.example.com'';
+        description = ''
+          Primary MX domain to use. It should be FQDN.
+        '';
+      };
+      localDomains = mkOption {
+        type = with types; listOf str;
+        default = ["$(primary_domain)"];
+        example = [
+          "$(primary_domain)"
+          "example.com"
+          "other.example.com"
+        ];
+        description = ''
+          Define list of allowed domains.
+        '';
+      };
+      config = mkOption {
+        type = with types; nullOr lines;
+        default = defaultConfig;
+        description = ''
+          Server configuration.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open the configured incoming and outgoing mail server ports.
+        '';
+      };
+
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd = {
+      packages = [ pkgs.maddy ];
+      services.maddy = {
+        serviceConfig = {
+          User = "${cfg.user}";
+          Group = "${cfg.group}";
+        };
+        wantedBy = [ "multi-user.target" ];
+      };
+    };
+
+    environment.etc."maddy/maddy.conf" = {
+      text = ''
+        $(hostname) = ${cfg.hostname}
+        $(primary_domain) = ${cfg.primaryDomain}
+        $(local_domains) = ${toString cfg.localDomains}
+        hostname ${cfg.hostname}
+        ${cfg.config}
+      '';
+    };
+
+    users.users = optionalAttrs (cfg.user == "maddy") {
+      maddy = {
+        description = "Maddy service user";
+        group = cfg.group;
+        home = "/var/lib/maddy";
+        createHome = true;
+        isSystemUser = true;
+      };
+    };
+
+    users.groups = mkIf (cfg.group == "maddy") {
+      maddy = pkgs.lib.mkForce {
+        name = cfg.group;
+      };
+    };
+
+    networking.firewall = mkIf cfg.openFirewall {
+      allowedTCPPorts = [ 25 143 587 ];
+    };
+
+    environment.systemPackages = [
+      pkgs.maddy
+    ];
+  };
+}
diff --git a/nixos/modules/services/mail/opendkim.nix b/nixos/modules/services/mail/opendkim.nix
index beff57613af..f1ffc5d3aee 100644
--- a/nixos/modules/services/mail/opendkim.nix
+++ b/nixos/modules/services/mail/opendkim.nix
@@ -55,6 +55,7 @@ in {
       domains = mkOption {
         type = types.str;
         default = "csl:${config.networking.hostName}";
+        defaultText = literalExpression ''"csl:''${config.networking.hostName}"'';
         example = "csl:example.com,mydomain.net";
         description = ''
           Local domains set (see <literal>opendkim(8)</literal> for more information on datasets).
diff --git a/nixos/modules/services/misc/dysnomia.nix b/nixos/modules/services/misc/dysnomia.nix
index 333ba651cde..7d9c39a6973 100644
--- a/nixos/modules/services/misc/dysnomia.nix
+++ b/nixos/modules/services/misc/dysnomia.nix
@@ -104,31 +104,37 @@ in
       properties = mkOption {
         description = "An attribute set in which each attribute represents a machine property. Optionally, these values can be shell substitutions.";
         default = {};
+        type = types.attrs;
       };
 
       containers = mkOption {
         description = "An attribute set in which each key represents a container and each value an attribute set providing its configuration properties";
         default = {};
+        type = types.attrsOf types.attrs;
       };
 
       components = mkOption {
         description = "An atttribute set in which each key represents a container and each value an attribute set in which each key represents a component and each value a derivation constructing its initial state";
         default = {};
+        type = types.attrsOf types.attrs;
       };
 
       extraContainerProperties = mkOption {
         description = "An attribute set providing additional container settings in addition to the default properties";
         default = {};
+        type = types.attrs;
       };
 
       extraContainerPaths = mkOption {
         description = "A list of paths containing additional container configurations that are added to the search folders";
         default = [];
+        type = types.listOf types.path;
       };
 
       extraModulePaths = mkOption {
         description = "A list of paths containing additional modules that are added to the search folders";
         default = [];
+        type = types.listOf types.path;
       };
 
       enableLegacyModules = mkOption {
diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix
index c4ea091a038..26ad1ad5536 100644
--- a/nixos/modules/services/misc/etcd.nix
+++ b/nixos/modules/services/misc/etcd.nix
@@ -17,6 +17,7 @@ in {
     name = mkOption {
       description = "Etcd unique node name.";
       default = config.networking.hostName;
+      defaultText = literalExpression "config.networking.hostName";
       type = types.str;
     };
 
diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix
index c0f7661c569..022a73c2b59 100644
--- a/nixos/modules/services/misc/gitea.nix
+++ b/nixos/modules/services/misc/gitea.nix
@@ -299,7 +299,7 @@ in
               ENABLED = true;
               MAILER_TYPE = "sendmail";
               FROM = "do-not-reply@example.org";
-              SENDMAIL_PATH = "${pkgs.system-sendmail}/bin/sendmail";
+              SENDMAIL_PATH = "''${pkgs.system-sendmail}/bin/sendmail";
             };
             other = {
               SHOW_FOOTER_VERSION = false;
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index b2abe70627d..01a7ea42d9d 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -475,6 +475,7 @@ in {
       host = mkOption {
         type = types.str;
         default = config.networking.hostName;
+        defaultText = literalExpression "config.networking.hostName";
         description = "GitLab host name. Used e.g. for copy-paste URLs.";
       };
 
@@ -534,6 +535,7 @@ in {
         host = mkOption {
           type = types.str;
           default = config.services.gitlab.host;
+          defaultText = literalExpression "config.services.gitlab.host";
           description = "GitLab container registry host name.";
         };
         port = mkOption {
diff --git a/nixos/modules/services/misc/matrix-appservice-discord.nix b/nixos/modules/services/misc/matrix-appservice-discord.nix
index c448614eca3..947471e56b4 100644
--- a/nixos/modules/services/misc/matrix-appservice-discord.nix
+++ b/nixos/modules/services/misc/matrix-appservice-discord.nix
@@ -98,6 +98,9 @@ in {
       serviceDependencies = mkOption {
         type = with types; listOf str;
         default = optional config.services.matrix-synapse.enable "matrix-synapse.service";
+        defaultText = literalExpression ''
+          optional config.services.matrix-synapse.enable "matrix-synapse.service"
+        '';
         description = ''
           List of Systemd services to require and wait for when starting the application service,
           such as the Matrix homeserver if it's running on the same host.
diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix
index 950c72c6e58..0f96f6b1ee2 100644
--- a/nixos/modules/services/misc/matrix-synapse.nix
+++ b/nixos/modules/services/misc/matrix-synapse.nix
@@ -227,6 +227,7 @@ in {
         type = types.str;
         example = "example.com";
         default = config.networking.hostName;
+        defaultText = literalExpression "config.networking.hostName";
         description = ''
           The domain name of the server, with optional explicit port.
           This is used by remote servers to look up the server address.
@@ -379,6 +380,11 @@ in {
         default = if versionAtLeast config.system.stateVersion "18.03"
           then "psycopg2"
           else "sqlite3";
+        defaultText = literalExpression ''
+          if versionAtLeast config.system.stateVersion "18.03"
+            then "psycopg2"
+            else "sqlite3"
+        '';
         description = ''
           The database engine name. Can be sqlite or psycopg2.
         '';
diff --git a/nixos/modules/services/misc/mautrix-telegram.nix b/nixos/modules/services/misc/mautrix-telegram.nix
index 59d0b682409..3b070b873b0 100644
--- a/nixos/modules/services/misc/mautrix-telegram.nix
+++ b/nixos/modules/services/misc/mautrix-telegram.nix
@@ -108,6 +108,9 @@ in {
       serviceDependencies = mkOption {
         type = with types; listOf str;
         default = optional config.services.matrix-synapse.enable "matrix-synapse.service";
+        defaultText = literalExpression ''
+          optional config.services.matrix-synapse.enable "matrix-synapse.service"
+        '';
         description = ''
           List of Systemd services to require and wait for when starting the application service.
         '';
diff --git a/nixos/modules/services/misc/moonraker.nix b/nixos/modules/services/misc/moonraker.nix
index de8668a0c06..e08d2f84212 100644
--- a/nixos/modules/services/misc/moonraker.nix
+++ b/nixos/modules/services/misc/moonraker.nix
@@ -18,6 +18,7 @@ in {
       klipperSocket = mkOption {
         type = types.path;
         default = config.services.klipper.apiSocket;
+        defaultText = literalExpression "config.services.klipper.apiSocket";
         description = "Path to Klipper's API socket.";
       };
 
diff --git a/nixos/modules/services/misc/mx-puppet-discord.nix b/nixos/modules/services/misc/mx-puppet-discord.nix
index c34803f9722..b6f5e04511a 100644
--- a/nixos/modules/services/misc/mx-puppet-discord.nix
+++ b/nixos/modules/services/misc/mx-puppet-discord.nix
@@ -39,7 +39,7 @@ in {
 
           #defaults to sqlite but can be configured to use postgresql with
           #connstring
-          database.filename = "${dataDir}/mx-puppet-discord/database.db";
+          database.filename = "${dataDir}/database.db";
           logging = {
             console = "info";
             lineDateFormat = "MMM-D HH:mm:ss.SSS";
@@ -67,6 +67,9 @@ in {
       serviceDependencies = mkOption {
         type = with types; listOf str;
         default = optional config.services.matrix-synapse.enable "matrix-synapse.service";
+        defaultText = literalExpression ''
+          optional config.services.matrix-synapse.enable "matrix-synapse.service"
+        '';
         description = ''
           List of Systemd services to require and wait for when starting the application service.
         '';
@@ -110,7 +113,9 @@ in {
         UMask = 0027;
 
         ExecStart = ''
-          ${pkgs.mx-puppet-discord}/bin/mx-puppet-discord -c ${settingsFile}
+          ${pkgs.mx-puppet-discord}/bin/mx-puppet-discord \
+            -c ${settingsFile} \
+            -f ${registrationFile}
         '';
       };
     };
diff --git a/nixos/modules/services/misc/nitter.nix b/nixos/modules/services/misc/nitter.nix
index 0c562343d85..6a9eeb02095 100644
--- a/nixos/modules/services/misc/nitter.nix
+++ b/nixos/modules/services/misc/nitter.nix
@@ -299,7 +299,7 @@ in
     systemd.services.nitter = {
         description = "Nitter (An alternative Twitter front-end)";
         wantedBy = [ "multi-user.target" ];
-        after = [ "syslog.target" "network.target" ];
+        after = [ "network.target" ];
         serviceConfig = {
           DynamicUser = true;
           StateDirectory = "nitter";
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index fb643e7a66e..869feb05eb7 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -192,15 +192,28 @@ in
         example = "batch";
         description = ''
           Nix daemon process CPU scheduling policy. This policy propagates to
-          build processes. other is the default scheduling policy for regular
-          tasks. The batch policy is similar to other, but optimised for
-          non-interactive tasks. idle is for extremely low-priority tasks
-          that should only be run when no other task requires CPU time.
-
-          Please note that while using the idle policy may greatly improve
-          responsiveness of a system performing expensive builds, it may also
-          slow down and potentially starve crucial configuration updates
-          during load.
+          build processes. <literal>other</literal> is the default scheduling
+          policy for regular tasks. The <literal>batch</literal> policy is
+          similar to <literal>other</literal>, but optimised for
+          non-interactive tasks. <literal>idle</literal> is for extremely
+          low-priority tasks that should only be run when no other task
+          requires CPU time.
+
+          Please note that while using the <literal>idle</literal> policy may
+          greatly improve responsiveness of a system performing expensive
+          builds, it may also slow down and potentially starve crucial
+          configuration updates during load.
+
+          <literal>idle</literal> may therefore be a sensible policy for
+          systems that experience only intermittent phases of high CPU load,
+          such as desktop or portable computers used interactively. Other
+          systems should use the <literal>other</literal> or
+          <literal>batch</literal> policy instead.
+
+          For more fine-grained resource control, please refer to
+          <citerefentry><refentrytitle>systemd.resource-control
+          </refentrytitle><manvolnum>5</manvolnum></citerefentry> and adjust
+          <option>systemd.services.nix-daemon</option> directly.
       '';
       };
 
@@ -210,13 +223,20 @@ in
         example = "idle";
         description = ''
           Nix daemon process I/O scheduling class. This class propagates to
-          build processes. best-effort is the default class for regular tasks.
-          The idle class is for extremely low-priority tasks that should only
-          perform I/O when no other task does.
-
-          Please note that while using the idle scheduling class can improve
-          responsiveness of a system performing expensive builds, it might also
-          slow down or starve crucial configuration updates during load.
+          build processes. <literal>best-effort</literal> is the default
+          class for regular tasks. The <literal>idle</literal> class is for
+          extremely low-priority tasks that should only perform I/O when no
+          other task does.
+
+          Please note that while using the <literal>idle</literal> scheduling
+          class can improve responsiveness of a system performing expensive
+          builds, it might also slow down or starve crucial configuration
+          updates during load.
+
+          <literal>idle</literal> may therefore be a sensible class for
+          systems that experience only intermittent phases of high I/O load,
+          such as desktop or portable computers used interactively. Other
+          systems should use the <literal>best-effort</literal> class.
       '';
       };
 
diff --git a/nixos/modules/services/misc/sourcehut/default.nix b/nixos/modules/services/misc/sourcehut/default.nix
index 9c812d6b043..c84a75b0ca0 100644
--- a/nixos/modules/services/misc/sourcehut/default.nix
+++ b/nixos/modules/services/misc/sourcehut/default.nix
@@ -71,6 +71,9 @@ in
     originBase = mkOption {
       type = types.str;
       default = with config.networking; hostName + lib.optionalString (domain != null) ".${domain}";
+      defaultText = literalExpression ''
+        with config.networking; hostName + optionalString (domain != null) ".''${domain}"
+      '';
       description = ''
         Host name used by reverse-proxy and for default settings. Will host services at git."''${originBase}". For example: git.sr.ht
       '';
diff --git a/nixos/modules/services/misc/xmrig.nix b/nixos/modules/services/misc/xmrig.nix
index cf01bb119e8..c5c3803920c 100644
--- a/nixos/modules/services/misc/xmrig.nix
+++ b/nixos/modules/services/misc/xmrig.nix
@@ -18,6 +18,7 @@ with lib;
       package = mkOption {
         type = types.package;
         default = pkgs.xmrig;
+        defaultText = literalExpression "pkgs.xmrig";
         example = literalExpression "pkgs.xmrig-mo";
         description = "XMRig package to use.";
       };
diff --git a/nixos/modules/services/misc/zigbee2mqtt.nix b/nixos/modules/services/misc/zigbee2mqtt.nix
index b378d9f362f..ff6d595e5a6 100644
--- a/nixos/modules/services/misc/zigbee2mqtt.nix
+++ b/nixos/modules/services/misc/zigbee2mqtt.nix
@@ -22,13 +22,9 @@ in
 
     package = mkOption {
       description = "Zigbee2mqtt package to use";
-      default = pkgs.zigbee2mqtt.override {
-        dataDir = cfg.dataDir;
-      };
+      default = pkgs.zigbee2mqtt;
       defaultText = literalExpression ''
-        pkgs.zigbee2mqtt {
-          dataDir = services.zigbee2mqtt.dataDir
-        }
+        pkgs.zigbee2mqtt
       '';
       type = types.package;
     };
@@ -41,7 +37,7 @@ in
 
     settings = mkOption {
       type = format.type;
-      default = {};
+      default = { };
       example = literalExpression ''
         {
           homeassistant = config.services.home-assistant.enable;
@@ -83,6 +79,7 @@ in
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/zigbee2mqtt";
         User = "zigbee2mqtt";
+        Group = "zigbee2mqtt";
         WorkingDirectory = cfg.dataDir;
         Restart = "on-failure";
 
diff --git a/nixos/modules/services/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix
index 6af04d22f0f..660d108587d 100644
--- a/nixos/modules/services/monitoring/collectd.nix
+++ b/nixos/modules/services/monitoring/collectd.nix
@@ -132,7 +132,12 @@ in {
     users.users = optionalAttrs (cfg.user == "collectd") {
       collectd = {
         isSystemUser = true;
+        group = "collectd";
       };
     };
+
+    users.groups = optionalAttrs (cfg.user == "collectd") {
+      collectd = {};
+    };
   };
 }
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index 4690a252c92..0dbb33530c9 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -324,6 +324,7 @@ in {
 
       mongoUrl = mkOption {
         default = "mongodb://${config.services.mongodb.bind_ip}:27017/seyren";
+        defaultText = literalExpression ''"mongodb://''${config.services.mongodb.bind_ip}:27017/seyren"'';
         description = "Mongodb connection string.";
         type = types.str;
       };
diff --git a/nixos/modules/services/monitoring/nagios.nix b/nixos/modules/services/monitoring/nagios.nix
index 83020d52fc8..2c7f0ed1966 100644
--- a/nixos/modules/services/monitoring/nagios.nix
+++ b/nixos/modules/services/monitoring/nagios.nix
@@ -131,6 +131,7 @@ in
       validateConfig = mkOption {
         type = types.bool;
         default = pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform;
+        defaultText = literalExpression "pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform";
         description = "if true, the syntax of the nagios configuration file is checked at build time";
       };
 
diff --git a/nixos/modules/services/monitoring/parsedmarc.nix b/nixos/modules/services/monitoring/parsedmarc.nix
index eeee04b4400..8571e1f01ed 100644
--- a/nixos/modules/services/monitoring/parsedmarc.nix
+++ b/nixos/modules/services/monitoring/parsedmarc.nix
@@ -93,6 +93,7 @@ in
         dashboard = lib.mkOption {
           type = lib.types.bool;
           default = config.services.grafana.enable;
+          defaultText = lib.literalExpression "config.services.grafana.enable";
           description = ''
             Whether the official parsedmarc grafana dashboard should
             be provisioned to the local grafana instance.
diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix
index 62e90232e11..d29d50706ef 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -61,6 +61,7 @@ let
     "rtl_433"
     "script"
     "snmp"
+    "smartctl"
     "smokeping"
     "sql"
     "surfboard"
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix b/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix
new file mode 100644
index 00000000000..b6416b93e69
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix
@@ -0,0 +1,64 @@
+{ config, lib, pkgs, options }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.exporters.smartctl;
+  format = pkgs.formats.yaml {};
+  configFile = format.generate "smartctl-exporter.yml" {
+    smartctl_exporter = {
+      bind_to = "${cfg.listenAddress}:${toString cfg.port}";
+      url_path = "/metrics";
+      smartctl_location = "${pkgs.smartmontools}/bin/smartctl";
+      collect_not_more_than_period = cfg.maxInterval;
+      devices = cfg.devices;
+    };
+  };
+in {
+  port = 9633;
+
+  extraOpts = {
+    devices = mkOption {
+      type = types.listOf types.str;
+      default = [];
+      example = literalExpression ''
+        [ "/dev/sda", "/dev/nvme0n1" ];
+      '';
+      description = ''
+        Paths to disks that will be monitored.
+      '';
+    };
+    maxInterval = mkOption {
+      type = types.str;
+      default = "60s";
+      example = "2m";
+      description = ''
+        Interval that limits how often a disk can be queried.
+      '';
+    };
+  };
+
+  serviceOpts = {
+    serviceConfig = {
+      AmbientCapabilities = [
+        "CAP_SYS_ADMIN"
+      ];
+      CapabilityBoundingSet = [
+        "CAP_SYS_ADMIN"
+      ];
+      DevicePolicy = "closed";
+      DeviceAllow = lib.mkForce cfg.devices;
+      ExecStart = ''
+        ${pkgs.prometheus-smartctl-exporter}/bin/smartctl_exporter -config ${configFile}
+      '';
+      PrivateDevices = lib.mkForce false;
+      ProtectProc = "invisible";
+      ProcSubset = "pid";
+      SupplementaryGroups = [ "disk" ];
+      SystemCallFilter = [
+        "@system-service"
+        "~@privileged @resources"
+      ];
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix
index 3ea25437114..73021b1b4d3 100644
--- a/nixos/modules/services/monitoring/smartd.nix
+++ b/nixos/modules/services/monitoring/smartd.nix
@@ -125,6 +125,7 @@ in
         mail = {
           enable = mkOption {
             default = config.services.mail.sendmailSetuidWrapper != null;
+            defaultText = literalExpression "config.services.mail.sendmailSetuidWrapper != null";
             type = types.bool;
             description = "Whenever to send e-mail notifications.";
           };
@@ -169,12 +170,14 @@ in
         x11 = {
           enable = mkOption {
             default = config.services.xserver.enable;
+            defaultText = literalExpression "config.services.xserver.enable";
             type = types.bool;
             description = "Whenever to send X11 xmessage notifications.";
           };
 
           display = mkOption {
             default = ":${toString config.services.xserver.display}";
+            defaultText = literalExpression ''":''${toString config.services.xserver.display}"'';
             type = types.str;
             description = "DISPLAY to send X11 notifications to.";
           };
diff --git a/nixos/modules/services/network-filesystems/drbd.nix b/nixos/modules/services/network-filesystems/drbd.nix
index 916e7eaaaa9..c730e0b34e9 100644
--- a/nixos/modules/services/network-filesystems/drbd.nix
+++ b/nixos/modules/services/network-filesystems/drbd.nix
@@ -47,19 +47,17 @@ let cfg = config.services.drbd; in
         options drbd usermode_helper=/run/current-system/sw/bin/drbdadm
       '';
 
-    environment.etc.drbd.conf =
+    environment.etc."drbd.conf" =
       { source = pkgs.writeText "drbd.conf" cfg.config; };
 
     systemd.services.drbd = {
       after = [ "systemd-udev.settle.service" "network.target" ];
       wants = [ "systemd-udev.settle.service" ];
       wantedBy = [ "multi-user.target" ];
-      script = ''
-        ${pkgs.drbd}/sbin/drbdadm up all
-      '';
-      serviceConfig.ExecStop = ''
-        ${pkgs.drbd}/sbin/drbdadm down all
-      '';
+      serviceConfig = {
+        ExecStart = "${pkgs.drbd}/sbin/drbdadm up all";
+        ExecStop = "${pkgs.drbd}/sbin/drbdadm down all";
+      };
     };
   };
 }
diff --git a/nixos/modules/services/network-filesystems/glusterfs.nix b/nixos/modules/services/network-filesystems/glusterfs.nix
index bc8be05ca8c..38be098de5d 100644
--- a/nixos/modules/services/network-filesystems/glusterfs.nix
+++ b/nixos/modules/services/network-filesystems/glusterfs.nix
@@ -187,7 +187,7 @@ in
 
       wantedBy = [ "multi-user.target" ];
 
-      after = [ "syslog.target" "network.target" ];
+      after = [ "network.target" ];
 
       preStart = ''
         install -m 0755 -d /var/log/glusterfs
diff --git a/nixos/modules/services/network-filesystems/ipfs.nix b/nixos/modules/services/network-filesystems/ipfs.nix
index 36b72ca48b2..5482b2aaf88 100644
--- a/nixos/modules/services/network-filesystems/ipfs.nix
+++ b/nixos/modules/services/network-filesystems/ipfs.nix
@@ -79,6 +79,11 @@ in
           if versionAtLeast config.system.stateVersion "17.09"
           then "/var/lib/ipfs"
           else "/var/lib/ipfs/.ipfs";
+        defaultText = literalExpression ''
+          if versionAtLeast config.system.stateVersion "17.09"
+          then "/var/lib/ipfs"
+          else "/var/lib/ipfs/.ipfs"
+        '';
         description = "The data dir for IPFS";
       };
 
diff --git a/nixos/modules/services/network-filesystems/openafs/server.nix b/nixos/modules/services/network-filesystems/openafs/server.nix
index c1bf83be77b..9c974335def 100644
--- a/nixos/modules/services/network-filesystems/openafs/server.nix
+++ b/nixos/modules/services/network-filesystems/openafs/server.nix
@@ -248,7 +248,7 @@ in {
     systemd.services = {
       openafs-server = {
         description = "OpenAFS server";
-        after = [ "syslog.target" "network.target" ];
+        after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
         restartIfChanged = false;
         unitConfig.ConditionPathExists = [
diff --git a/nixos/modules/services/networking/adguardhome.nix b/nixos/modules/services/networking/adguardhome.nix
index 4388ef2b7e5..03f9b9f9bad 100644
--- a/nixos/modules/services/networking/adguardhome.nix
+++ b/nixos/modules/services/networking/adguardhome.nix
@@ -56,7 +56,7 @@ in
   config = mkIf cfg.enable {
     systemd.services.adguardhome = {
       description = "AdGuard Home: Network-level blocker";
-      after = [ "syslog.target" "network.target" ];
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       unitConfig = {
         StartLimitIntervalSec = 5;
diff --git a/nixos/modules/services/networking/bind.nix b/nixos/modules/services/networking/bind.nix
index f2b2e4c4d5d..e44f8d4cf30 100644
--- a/nixos/modules/services/networking/bind.nix
+++ b/nixos/modules/services/networking/bind.nix
@@ -144,6 +144,7 @@ in
 
       forwarders = mkOption {
         default = config.networking.nameservers;
+        defaultText = literalExpression "config.networking.nameservers";
         type = types.listOf types.str;
         description = "
           List of servers we should forward requests to.
diff --git a/nixos/modules/services/networking/coturn.nix b/nixos/modules/services/networking/coturn.nix
index 610754e9bd3..ce563c31136 100644
--- a/nixos/modules/services/networking/coturn.nix
+++ b/nixos/modules/services/networking/coturn.nix
@@ -193,6 +193,7 @@ in {
       realm = mkOption {
         type = types.str;
         default = config.networking.hostName;
+        defaultText = literalExpression "config.networking.hostName";
         example = "example.com";
         description = ''
           The default realm to be used for the users when no explicit
diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix
index fd9c216b060..8a2c0fc7080 100644
--- a/nixos/modules/services/networking/ddclient.nix
+++ b/nixos/modules/services/networking/ddclient.nix
@@ -31,8 +31,8 @@ let
   preStart = ''
     install ${configFile} /run/${RuntimeDirectory}/ddclient.conf
     ${lib.optionalString (cfg.configFile == null) (if (cfg.passwordFile != null) then ''
-      password=$(head -n 1 ${cfg.passwordFile})
-      sed -i "s/^password=$/password=$password/" /run/${RuntimeDirectory}/ddclient.conf
+      password=$(printf "%q" "$(head -n 1 "${cfg.passwordFile}")")
+      sed -i "s|^password=$|password=$password|" /run/${RuntimeDirectory}/ddclient.conf
     '' else ''
       sed -i '/^password=$/d' /run/${RuntimeDirectory}/ddclient.conf
     '')}
diff --git a/nixos/modules/services/networking/dnscrypt-wrapper.nix b/nixos/modules/services/networking/dnscrypt-wrapper.nix
index 400d6e67044..c2add170e9c 100644
--- a/nixos/modules/services/networking/dnscrypt-wrapper.nix
+++ b/nixos/modules/services/networking/dnscrypt-wrapper.nix
@@ -145,6 +145,7 @@ in {
     providerName = mkOption {
       type = types.str;
       default = "2.dnscrypt-cert.${config.networking.hostName}";
+      defaultText = literalExpression ''"2.dnscrypt-cert.''${config.networking.hostName}"'';
       example = "2.dnscrypt-cert.myresolver";
       description = ''
         The name that will be given to this DNSCrypt resolver.
diff --git a/nixos/modules/services/networking/eternal-terminal.nix b/nixos/modules/services/networking/eternal-terminal.nix
index a2e5b30dc0f..88b4cd90540 100644
--- a/nixos/modules/services/networking/eternal-terminal.nix
+++ b/nixos/modules/services/networking/eternal-terminal.nix
@@ -67,7 +67,7 @@ in
       eternal-terminal = {
         description = "Eternal Terminal server.";
         wantedBy = [ "multi-user.target" ];
-        after = [ "syslog.target" "network.target" ];
+        after = [ "network.target" ];
         serviceConfig = {
           Type = "forking";
           ExecStart = "${pkgs.eternal-terminal}/bin/etserver --daemon --cfgfile=${pkgs.writeText "et.cfg" ''
diff --git a/nixos/modules/services/networking/flannel.nix b/nixos/modules/services/networking/flannel.nix
index b15339870ee..ac84b3d35a3 100644
--- a/nixos/modules/services/networking/flannel.nix
+++ b/nixos/modules/services/networking/flannel.nix
@@ -93,6 +93,9 @@ in {
       '';
       type = types.nullOr types.str;
       default = with config.networking; (hostName + optionalString (domain != null) ".${domain}");
+      defaultText = literalExpression ''
+        with config.networking; (hostName + optionalString (domain != null) ".''${domain}")
+      '';
       example = "node1.example.com";
     };
 
diff --git a/nixos/modules/services/networking/freeradius.nix b/nixos/modules/services/networking/freeradius.nix
index f3fdd576b65..7fa3a8fa17f 100644
--- a/nixos/modules/services/networking/freeradius.nix
+++ b/nixos/modules/services/networking/freeradius.nix
@@ -28,6 +28,7 @@ let
         ProtectHome = "on";
         Restart = "on-failure";
         RestartSec = 2;
+        LogsDirectory = "radius";
     };
   };
 
@@ -73,6 +74,7 @@ in
       users.radius = {
         /*uid = config.ids.uids.radius;*/
         description = "Radius daemon user";
+        isSystemUser = true;
       };
     };
 
diff --git a/nixos/modules/services/networking/jitsi-videobridge.nix b/nixos/modules/services/networking/jitsi-videobridge.nix
index dd06ad98a97..abb0bd0a25e 100644
--- a/nixos/modules/services/networking/jitsi-videobridge.nix
+++ b/nixos/modules/services/networking/jitsi-videobridge.nix
@@ -217,6 +217,8 @@ in
         "-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "videobridge";
         "-Djava.util.logging.config.file" = "/etc/jitsi/videobridge/logging.properties";
         "-Dconfig.file" = pkgs.writeText "jvb.conf" (toHOCON jvbConfig);
+        # Mitigate CVE-2021-44228
+        "-Dlog4j2.formatMsgNoLookups" = true;
       } // (mapAttrs' (k: v: nameValuePair "-D${k}" v) cfg.extraProperties);
     in
     {
diff --git a/nixos/modules/services/networking/knot.nix b/nixos/modules/services/networking/knot.nix
index 67eadbd7670..a58a03997b3 100644
--- a/nixos/modules/services/networking/knot.nix
+++ b/nixos/modules/services/networking/knot.nix
@@ -80,13 +80,13 @@ in {
   };
 
   config = mkIf config.services.knot.enable {
+    users.groups.knot = {};
     users.users.knot = {
       isSystemUser = true;
       group = "knot";
       description = "Knot daemon user";
     };
 
-    users.groups.knot.gid = null;
     systemd.services.knot = {
       unitConfig.Documentation = "man:knotd(8) man:knot.conf(5) man:knotc(8) https://www.knot-dns.cz/docs/${cfg.package.version}/html/";
       description = cfg.package.meta.description;
@@ -98,17 +98,52 @@ in {
         Type = "notify";
         ExecStart = "${cfg.package}/bin/knotd --config=${configFile} --socket=${socketFile} ${concatStringsSep " " cfg.extraArgs}";
         ExecReload = "${knot-cli-wrappers}/bin/knotc reload";
-        CapabilityBoundingSet = "CAP_NET_BIND_SERVICE CAP_SETPCAP";
-        AmbientCapabilities = "CAP_NET_BIND_SERVICE CAP_SETPCAP";
-        NoNewPrivileges = true;
         User = "knot";
+        Group = "knot";
+
+        AmbientCapabilities = [
+          "CAP_NET_BIND_SERVICE"
+        ];
+        CapabilityBoundingSet = [
+          "CAP_NET_BIND_SERVICE"
+        ];
+        DeviceAllow = "";
+        DevicePolicy = "closed";
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateTmp = true;
+        PrivateUsers = false; # breaks capability passing
+        ProcSubset = "pid";
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectProc = "invisible";
+        ProtectSystem = "strict";
+        RemoveIPC = true;
+        Restart = "on-abort";
+        RestrictAddressFamilies = [
+          "AF_INET"
+          "AF_INET6"
+          "AF_UNIX"
+        ];
+        RestrictNamespaces = true;
+        RestrictRealtime =true;
+        RestrictSUIDSGID = true;
         RuntimeDirectory = "knot";
         StateDirectory = "knot";
         StateDirectoryMode = "0700";
-        PrivateDevices = true;
-        RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
         SystemCallArchitectures = "native";
-        Restart = "on-abort";
+        SystemCallFilter = [
+          "@system-service"
+          "~@privileged"
+        ];
+        UMask = "0077";
       };
     };
 
diff --git a/nixos/modules/services/networking/ncdns.nix b/nixos/modules/services/networking/ncdns.nix
index af17fc0814b..82c285d0516 100644
--- a/nixos/modules/services/networking/ncdns.nix
+++ b/nixos/modules/services/networking/ncdns.nix
@@ -76,6 +76,7 @@ in
       identity.hostname = mkOption {
         type = types.str;
         default = config.networking.hostName;
+        defaultText = literalExpression "config.networking.hostName";
         example = "example.com";
         description = ''
           The hostname of this ncdns instance, which defaults to the machine
diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix
index 893995165b9..cf6c9661dc1 100644
--- a/nixos/modules/services/networking/nsd.nix
+++ b/nixos/modules/services/networking/nsd.nix
@@ -603,6 +603,7 @@ in
     reuseport = mkOption {
       type = types.bool;
       default = pkgs.stdenv.isLinux;
+      defaultText = literalExpression "pkgs.stdenv.isLinux";
       description = ''
         Whether to enable SO_REUSEPORT on all used sockets. This lets multiple
         processes bind to the same port. This speeds up operation especially
diff --git a/nixos/modules/services/networking/ntp/chrony.nix b/nixos/modules/services/networking/ntp/chrony.nix
index d414936a2c2..34728455a21 100644
--- a/nixos/modules/services/networking/ntp/chrony.nix
+++ b/nixos/modules/services/networking/ntp/chrony.nix
@@ -52,6 +52,7 @@ in
 
       servers = mkOption {
         default = config.networking.timeServers;
+        defaultText = literalExpression "config.networking.timeServers";
         type = types.listOf types.str;
         description = ''
           The set of NTP servers from which to synchronise.
diff --git a/nixos/modules/services/networking/ntp/ntpd.nix b/nixos/modules/services/networking/ntp/ntpd.nix
index ce4802ce024..12be0d045a8 100644
--- a/nixos/modules/services/networking/ntp/ntpd.nix
+++ b/nixos/modules/services/networking/ntp/ntpd.nix
@@ -77,6 +77,7 @@ in
 
       servers = mkOption {
         default = config.networking.timeServers;
+        defaultText = literalExpression "config.networking.timeServers";
         type = types.listOf types.str;
         description = ''
           The set of NTP servers from which to synchronise.
diff --git a/nixos/modules/services/networking/ntp/openntpd.nix b/nixos/modules/services/networking/ntp/openntpd.nix
index 9f3892e3b53..e86b71291f9 100644
--- a/nixos/modules/services/networking/ntp/openntpd.nix
+++ b/nixos/modules/services/networking/ntp/openntpd.nix
@@ -23,6 +23,7 @@ in
 
     servers = mkOption {
       default = config.services.ntp.servers;
+      defaultText = literalExpression "config.services.ntp.servers";
       type = types.listOf types.str;
       inherit (options.services.ntp.servers) description;
     };
diff --git a/nixos/modules/services/networking/pleroma.nix b/nixos/modules/services/networking/pleroma.nix
index 2f32faf387c..9b8382392c0 100644
--- a/nixos/modules/services/networking/pleroma.nix
+++ b/nixos/modules/services/networking/pleroma.nix
@@ -100,6 +100,7 @@ in {
       after = [ "network-online.target" "postgresql.service" ];
       wantedBy = [ "multi-user.target" ];
       restartTriggers = [ config.environment.etc."/pleroma/config.exs".source ];
+      environment.RELEASE_COOKIE = "/var/lib/pleroma/.cookie";
       serviceConfig = {
         User = cfg.user;
         Group = cfg.group;
@@ -116,8 +117,14 @@ in {
         # has not been updated. But the no-op process is pretty fast.
         # Better be safe than sorry migration-wise.
         ExecStartPre =
-          let preScript = pkgs.writers.writeBashBin "pleromaStartPre"
-            "${cfg.package}/bin/pleroma_ctl migrate";
+          let preScript = pkgs.writers.writeBashBin "pleromaStartPre" ''
+            if [ ! -f /var/lib/pleroma/.cookie ]
+            then
+              echo "Creating cookie file"
+              dd if=/dev/urandom bs=1 count=16 | hexdump -e '16/1 "%02x"' > /var/lib/pleroma/.cookie
+            fi
+            ${cfg.package}/bin/pleroma_ctl migrate
+          '';
           in "${preScript}/bin/pleromaStartPre";
 
         ExecStart = "${cfg.package}/bin/pleroma start";
diff --git a/nixos/modules/services/networking/resilio.nix b/nixos/modules/services/networking/resilio.nix
index 4701b0e8143..89127850641 100644
--- a/nixos/modules/services/networking/resilio.nix
+++ b/nixos/modules/services/networking/resilio.nix
@@ -58,6 +58,7 @@ in
         type = types.str;
         example = "Voltron";
         default = config.networking.hostName;
+        defaultText = literalExpression "config.networking.hostName";
         description = ''
           Name of the Resilio Sync device.
         '';
diff --git a/nixos/modules/services/networking/seafile.nix b/nixos/modules/services/networking/seafile.nix
index 856797b6b02..d7fb22edebe 100644
--- a/nixos/modules/services/networking/seafile.nix
+++ b/nixos/modules/services/networking/seafile.nix
@@ -124,6 +124,7 @@ in {
       type = types.package;
       description = "Which package to use for the seafile server.";
       default = pkgs.seafile-server;
+      defaultText = literalExpression "pkgs.seafile-server";
     };
 
     seahubExtraConf = mkOption {
diff --git a/nixos/modules/services/networking/skydns.nix b/nixos/modules/services/networking/skydns.nix
index c4e959b57bb..dea60a3862a 100644
--- a/nixos/modules/services/networking/skydns.nix
+++ b/nixos/modules/services/networking/skydns.nix
@@ -49,6 +49,7 @@ in {
 
     nameservers = mkOption {
       default = map (n: n + ":53") config.networking.nameservers;
+      defaultText = literalExpression ''map (n: n + ":53") config.networking.nameservers'';
       type = types.listOf types.str;
       description = "Skydns list of nameservers to forward DNS requests to when not authoritative for a domain.";
       example = ["8.8.8.8:53" "8.8.4.4:53"];
diff --git a/nixos/modules/services/networking/smokeping.nix b/nixos/modules/services/networking/smokeping.nix
index c075cbbceac..bd71b158dbe 100644
--- a/nixos/modules/services/networking/smokeping.nix
+++ b/nixos/modules/services/networking/smokeping.nix
@@ -241,6 +241,12 @@ in
           + FPing
           binary = ${config.security.wrapperDir}/fping
         '';
+        defaultText = literalExpression ''
+          '''
+            + FPing
+            binary = ''${config.security.wrapperDir}/fping
+          '''
+        '';
         description = "Probe configuration";
       };
       sendmail = mkOption {
diff --git a/nixos/modules/services/networking/soju.nix b/nixos/modules/services/networking/soju.nix
index 68a33e9dccb..cb0acf4765f 100644
--- a/nixos/modules/services/networking/soju.nix
+++ b/nixos/modules/services/networking/soju.nix
@@ -43,6 +43,7 @@ in
     hostName = mkOption {
       type = types.str;
       default = config.networking.hostName;
+      defaultText = literalExpression "config.networking.hostName";
       description = "Server hostname.";
     };
 
diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix
index 53ad4df477f..174e919f988 100644
--- a/nixos/modules/services/networking/unifi.nix
+++ b/nixos/modules/services/networking/unifi.nix
@@ -7,6 +7,7 @@ let
     @${cfg.jrePackage}/bin/java java \
         ${optionalString (cfg.initialJavaHeapSize != null) "-Xms${(toString cfg.initialJavaHeapSize)}m"} \
         ${optionalString (cfg.maximumJavaHeapSize != null) "-Xmx${(toString cfg.maximumJavaHeapSize)}m"} \
+        ${optionalString (lib.versionOlder cfg.unifiPackage.version "6.5.54") "-Dlog4j2.formatMsgNoLookups=true"} \
         -jar ${stateDir}/lib/ace.jar
   '';
 in
diff --git a/nixos/modules/services/networking/xrdp.nix b/nixos/modules/services/networking/xrdp.nix
index c4f828f3c5a..e9f123a181a 100644
--- a/nixos/modules/services/networking/xrdp.nix
+++ b/nixos/modules/services/networking/xrdp.nix
@@ -97,6 +97,11 @@ in
         '';
       };
 
+      confDir = mkOption {
+        type = types.path;
+        default = confDir;
+        description = "The location of the config files for xrdp.";
+      };
     };
   };
 
@@ -149,7 +154,7 @@ in
           User = "xrdp";
           Group = "xrdp";
           PermissionsStartOnly = true;
-          ExecStart = "${cfg.package}/bin/xrdp --nodaemon --port ${toString cfg.port} --config ${confDir}/xrdp.ini";
+          ExecStart = "${cfg.package}/bin/xrdp --nodaemon --port ${toString cfg.port} --config ${cfg.confDir}/xrdp.ini";
         };
       };
 
@@ -159,7 +164,7 @@ in
         description = "xrdp session manager";
         restartIfChanged = false; # do not restart on "nixos-rebuild switch". like "display-manager", it can have many interactive programs as children
         serviceConfig = {
-          ExecStart = "${cfg.package}/bin/xrdp-sesman --nodaemon --config ${confDir}/sesman.ini";
+          ExecStart = "${cfg.package}/bin/xrdp-sesman --nodaemon --config ${cfg.confDir}/sesman.ini";
           ExecStop  = "${pkgs.coreutils}/bin/kill -INT $MAINPID";
         };
       };
diff --git a/nixos/modules/services/security/oauth2_proxy_nginx.nix b/nixos/modules/services/security/oauth2_proxy_nginx.nix
index d82ddb894ea..5853c5a123c 100644
--- a/nixos/modules/services/security/oauth2_proxy_nginx.nix
+++ b/nixos/modules/services/security/oauth2_proxy_nginx.nix
@@ -8,6 +8,7 @@ in
     proxy = mkOption {
       type = types.str;
       default = config.services.oauth2_proxy.httpAddress;
+      defaultText = literalExpression "config.services.oauth2_proxy.httpAddress";
       description = ''
         The address of the reverse proxy endpoint for oauth2_proxy
       '';
diff --git a/nixos/modules/services/security/torsocks.nix b/nixos/modules/services/security/torsocks.nix
index 47ac95c4626..fdd6ac32cc6 100644
--- a/nixos/modules/services/security/torsocks.nix
+++ b/nixos/modules/services/security/torsocks.nix
@@ -37,6 +37,7 @@ in
       enable = mkOption {
         type        = types.bool;
         default     = config.services.tor.enable && config.services.tor.client.enable;
+        defaultText = literalExpression "config.services.tor.enable && config.services.tor.client.enable";
         description = ''
           Whether to build <literal>/etc/tor/torsocks.conf</literal>
           containing the specified global torsocks configuration.
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index b8b38f6ba93..9e440e49b50 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -167,13 +167,15 @@ in
       };
 
       downloadDirPermissions = mkOption {
-        type = types.str;
-        default = "770";
-        example = "775";
+        type = with types; nullOr str;
+        default = null;
+        example = "770";
         description = ''
-          The permissions set by <literal>systemd.activationScripts.transmission-daemon</literal>
-          on the directories <xref linkend="opt-services.transmission.settings.download-dir"/>
-          and <xref linkend="opt-services.transmission.settings.incomplete-dir"/>.
+          If not <code>null</code>, is used as the permissions
+          set by <literal>systemd.activationScripts.transmission-daemon</literal>
+          on the directories <xref linkend="opt-services.transmission.settings.download-dir"/>,
+          <xref linkend="opt-services.transmission.settings.incomplete-dir"/>.
+          and <xref linkend="opt-services.transmission.settings.watch-dir"/>.
           Note that you may also want to change
           <xref linkend="opt-services.transmission.settings.umask"/>.
         '';
@@ -246,15 +248,17 @@ in
     # when /home/foo is not owned by cfg.user.
     # Note also that using an ExecStartPre= wouldn't work either
     # because BindPaths= needs these directories before.
-    system.activationScripts.transmission-daemon = ''
-      install -d -m 700 '${cfg.home}/${settingsDir}'
-      chown -R '${cfg.user}:${cfg.group}' ${cfg.home}/${settingsDir}
-      install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.download-dir}'
-      '' + optionalString cfg.settings.incomplete-dir-enabled ''
-      install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.incomplete-dir}'
-      '' + optionalString cfg.settings.watch-dir-enabled ''
-      install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.watch-dir}'
-      '';
+    system.activationScripts = mkIf (cfg.downloadDirPermissions != null)
+      { transmission-daemon = ''
+        install -d -m 700 '${cfg.home}/${settingsDir}'
+        chown -R '${cfg.user}:${cfg.group}' ${cfg.home}/${settingsDir}
+        install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.download-dir}'
+        '' + optionalString cfg.settings.incomplete-dir-enabled ''
+        install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.incomplete-dir}'
+        '' + optionalString cfg.settings.watch-dir-enabled ''
+        install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.watch-dir}'
+        '';
+      };
 
     systemd.services.transmission = {
       description = "Transmission BitTorrent Service";
@@ -313,6 +317,14 @@ in
             cfg.settings.script-torrent-done-filename ++
           optional (cfg.settings.watch-dir-enabled && !cfg.settings.trash-original-torrent-files)
             cfg.settings.watch-dir;
+        StateDirectory = [
+          "transmission"
+          "transmission/.config/transmission-daemon"
+          "transmission/.incomplete"
+          "transmission/Downloads"
+          "transmission/watch-dir"
+        ];
+        StateDirectoryMode = mkDefault 750;
         # The following options are only for optimizing:
         # systemd-analyze security transmission
         AmbientCapabilities = "";
diff --git a/nixos/modules/services/video/epgstation/default.nix b/nixos/modules/services/video/epgstation/default.nix
index 36f7b937d5a..56bd9d9eeec 100644
--- a/nixos/modules/services/video/epgstation/default.nix
+++ b/nixos/modules/services/video/epgstation/default.nix
@@ -48,7 +48,7 @@ let
 in
 {
   options.services.epgstation = {
-    enable = mkEnableOption pkgs.epgstation.meta.description;
+    enable = mkEnableOption "EPGStation: DTV Software in Japan";
 
     usePreconfiguredStreaming = mkOption {
       type = types.bool;
diff --git a/nixos/modules/services/video/mirakurun.nix b/nixos/modules/services/video/mirakurun.nix
index 16efb56cfd6..35303b2332c 100644
--- a/nixos/modules/services/video/mirakurun.nix
+++ b/nixos/modules/services/video/mirakurun.nix
@@ -24,7 +24,7 @@ in
   {
     options = {
       services.mirakurun = {
-        enable = mkEnableOption mirakurun.meta.description;
+        enable = mkEnableOption "the Mirakurun DVR Tuner Server";
 
         port = mkOption {
           type = with types; nullOr port;
diff --git a/nixos/modules/services/web-apps/discourse.nix b/nixos/modules/services/web-apps/discourse.nix
index c4fb7e2b316..18b61200aa1 100644
--- a/nixos/modules/services/web-apps/discourse.nix
+++ b/nixos/modules/services/web-apps/discourse.nix
@@ -621,12 +621,13 @@ in
 
       max_user_api_reqs_per_minute = 20;
       max_user_api_reqs_per_day = 2880;
-      max_admin_api_reqs_per_key_per_minute = 60;
+      max_admin_api_reqs_per_minute = 60;
       max_reqs_per_ip_per_minute = 200;
       max_reqs_per_ip_per_10_seconds = 50;
       max_asset_reqs_per_ip_per_10_seconds = 200;
       max_reqs_per_ip_mode = "block";
       max_reqs_rate_limit_on_private = false;
+      skip_per_ip_rate_limit_trust_level = 1;
       force_anonymous_min_queue_seconds = 1;
       force_anonymous_min_per_10_seconds = 3;
       background_requests_max_queue_length = 0.5;
@@ -646,6 +647,9 @@ in
       enable_email_sync_demon = false;
       max_digests_enqueued_per_30_mins_per_site = 10000;
       cluster_name = null;
+      multisite_config_path = "config/multisite.yml";
+      enable_long_polling = null;
+      long_polling_interval = null;
     };
 
     services.redis.enable = lib.mkDefault (cfg.redis.host == "localhost");
@@ -825,7 +829,7 @@ in
 
       appendHttpConfig = ''
         # inactive means we keep stuff around for 1440m minutes regardless of last access (1 week)
-        # levels means it is a 2 deep heirarchy cause we can have lots of files
+        # levels means it is a 2 deep hierarchy cause we can have lots of files
         # max_size limits the size of the cache
         proxy_cache_path /var/cache/nginx inactive=1440m levels=1:2 keys_zone=discourse:10m max_size=600m;
 
@@ -837,7 +841,7 @@ in
         inherit (cfg) sslCertificate sslCertificateKey enableACME;
         forceSSL = lib.mkDefault tlsEnabled;
 
-        root = "/run/discourse/public";
+        root = "${cfg.package}/share/discourse/public";
 
         locations =
           let
@@ -889,7 +893,7 @@ in
               "~ ^/uploads/" = proxy {
                 extraConfig = cache_1y + ''
                   proxy_set_header X-Sendfile-Type X-Accel-Redirect;
-                  proxy_set_header X-Accel-Mapping /run/discourse/public/=/downloads/;
+                  proxy_set_header X-Accel-Mapping ${cfg.package}/share/discourse/public/=/downloads/;
 
                   # custom CSS
                   location ~ /stylesheet-cache/ {
@@ -911,7 +915,7 @@ in
               "~ ^/admin/backups/" = proxy {
                 extraConfig = ''
                   proxy_set_header X-Sendfile-Type X-Accel-Redirect;
-                  proxy_set_header X-Accel-Mapping /run/discourse/public/=/downloads/;
+                  proxy_set_header X-Accel-Mapping ${cfg.package}/share/discourse/public/=/downloads/;
                 '';
               };
               "~ ^/(svg-sprite/|letter_avatar/|letter_avatar_proxy/|user_avatar|highlight-js|stylesheets|theme-javascripts|favicon/proxied|service-worker)" = proxy {
@@ -938,7 +942,7 @@ in
               };
               "/downloads/".extraConfig = ''
                 internal;
-                alias /run/discourse/public/;
+                alias ${cfg.package}/share/discourse/public/;
               '';
             };
       };
diff --git a/nixos/modules/services/web-apps/discourse.xml b/nixos/modules/services/web-apps/discourse.xml
index 184c9c6363e..e91d3eac422 100644
--- a/nixos/modules/services/web-apps/discourse.xml
+++ b/nixos/modules/services/web-apps/discourse.xml
@@ -297,7 +297,7 @@ services.discourse = {
       the script:
       <programlisting language="bash">
 ./update.py update-plugins
-</programlisting>.
+</programlisting>
     </para>
 
     <para>
diff --git a/nixos/modules/services/web-apps/dokuwiki.nix b/nixos/modules/services/web-apps/dokuwiki.nix
index fc0e23729b3..9b9ae931f9a 100644
--- a/nixos/modules/services/web-apps/dokuwiki.nix
+++ b/nixos/modules/services/web-apps/dokuwiki.nix
@@ -308,6 +308,9 @@ in
         inherit user;
         group = webserver.group;
 
+        # Not yet compatible with php 8 https://www.dokuwiki.org/requirements
+        # https://github.com/splitbrain/dokuwiki/issues/3545
+        phpPackage = pkgs.php74;
         phpEnv = {
           DOKUWIKI_LOCAL_CONFIG = "${dokuwikiLocalConfig hostName cfg}";
           DOKUWIKI_PLUGINS_LOCAL_CONFIG = "${dokuwikiPluginsLocalConfig hostName cfg}";
@@ -446,5 +449,6 @@ in
   meta.maintainers = with maintainers; [
     _1000101
     onny
+    dandellion
   ];
 }
diff --git a/nixos/modules/services/web-apps/ihatemoney/default.nix b/nixos/modules/services/web-apps/ihatemoney/default.nix
index 238241854c1..ad314c885ba 100644
--- a/nixos/modules/services/web-apps/ihatemoney/default.nix
+++ b/nixos/modules/services/web-apps/ihatemoney/default.nix
@@ -79,6 +79,7 @@ in
         email = mkOption {
           type = types.str;
           default = "ihatemoney@${config.networking.hostName}";
+          defaultText = literalExpression ''"ihatemoney@''${config.networking.hostName}"'';
           description = "The email of the sender of ihatemoney emails";
         };
       };
diff --git a/nixos/modules/services/web-apps/invidious.nix b/nixos/modules/services/web-apps/invidious.nix
index 7fb826af583..50370629e47 100644
--- a/nixos/modules/services/web-apps/invidious.nix
+++ b/nixos/modules/services/web-apps/invidious.nix
@@ -11,7 +11,7 @@ let
     systemd.services.invidious = {
       description = "Invidious (An alternative YouTube front-end)";
       wants = [ "network-online.target" ];
-      after = [ "syslog.target" "network-online.target" ];
+      after = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
 
       script =
diff --git a/nixos/modules/services/web-apps/openwebrx.nix b/nixos/modules/services/web-apps/openwebrx.nix
index 51005cd1e49..9e90c01e0bb 100644
--- a/nixos/modules/services/web-apps/openwebrx.nix
+++ b/nixos/modules/services/web-apps/openwebrx.nix
@@ -9,6 +9,7 @@ in
     package = mkOption {
       type = types.package;
       default = pkgs.openwebrx;
+      defaultText = literalExpression "pkgs.openwebrx";
       description = "OpenWebRX package to use for the service";
     };
   };
diff --git a/nixos/modules/services/web-apps/peertube.nix b/nixos/modules/services/web-apps/peertube.nix
index 362a3358b79..932ddcfef19 100644
--- a/nixos/modules/services/web-apps/peertube.nix
+++ b/nixos/modules/services/web-apps/peertube.nix
@@ -234,6 +234,7 @@ in {
     package = lib.mkOption {
       type = lib.types.package;
       default = pkgs.peertube;
+      defaultText = lib.literalExpression "pkgs.peertube";
       description = "Peertube package to use.";
     };
   };
diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix
index 08356cee1df..9aa38ab25c9 100644
--- a/nixos/modules/services/web-apps/tt-rss.nix
+++ b/nixos/modules/services/web-apps/tt-rss.nix
@@ -18,11 +18,11 @@ let
   tt-rss-config = let
     password =
       if (cfg.database.password != null) then
-        "${(escape ["'" "\\"] cfg.database.password)}"
+        "'${(escape ["'" "\\"] cfg.database.password)}'"
       else if (cfg.database.passwordFile != null) then
-        "file_get_contents('${cfg.database.passwordFile}'"
+        "file_get_contents('${cfg.database.passwordFile}')"
       else
-        ""
+        null
       ;
   in pkgs.writeText "config.php" ''
     <?php
@@ -40,7 +40,7 @@ let
       putenv('TTRSS_DB_HOST=${optionalString (cfg.database.host != null) cfg.database.host}');
       putenv('TTRSS_DB_USER=${cfg.database.user}');
       putenv('TTRSS_DB_NAME=${cfg.database.name}');
-      putenv('TTRSS_DB_PASS=${password}');
+      putenv('TTRSS_DB_PASS=' ${optionalString (password != null) ". ${password}"});
       putenv('TTRSS_DB_PORT=${toString dbPort}');
 
       putenv('TTRSS_AUTH_AUTO_CREATE=${boolToString cfg.auth.autoCreate}');
diff --git a/nixos/modules/services/web-servers/nginx/location-options.nix b/nixos/modules/services/web-servers/nginx/location-options.nix
index 56a5381e05c..6fd00b38697 100644
--- a/nixos/modules/services/web-servers/nginx/location-options.nix
+++ b/nixos/modules/services/web-servers/nginx/location-options.nix
@@ -102,7 +102,7 @@ with lib;
     };
 
     fastcgiParams = mkOption {
-      type = types.attrsOf types.str;
+      type = types.attrsOf (types.either types.str types.path);
       default = {};
       description = ''
         FastCGI parameters to override.  Unlike in the Nginx
diff --git a/nixos/modules/services/web-servers/uwsgi.nix b/nixos/modules/services/web-servers/uwsgi.nix
index ac435951310..a1cad17336d 100644
--- a/nixos/modules/services/web-servers/uwsgi.nix
+++ b/nixos/modules/services/web-servers/uwsgi.nix
@@ -121,7 +121,7 @@ in {
               moin = {
                 type = "normal";
                 pythonPackages = self: with self; [ moinmoin ];
-                socket = "${config.services.uwsgi.runDir}/uwsgi.sock";
+                socket = "''${config.services.uwsgi.runDir}/uwsgi.sock";
               };
             };
           }
diff --git a/nixos/modules/services/web-servers/varnish/default.nix b/nixos/modules/services/web-servers/varnish/default.nix
index 0ebf58eb9f6..fe817313a99 100644
--- a/nixos/modules/services/web-servers/varnish/default.nix
+++ b/nixos/modules/services/web-servers/varnish/default.nix
@@ -42,6 +42,7 @@ in
       stateDir = mkOption {
         type = types.path;
         default = "/var/spool/varnish/${config.networking.hostName}";
+        defaultText = literalExpression ''"/var/spool/varnish/''${config.networking.hostName}"'';
         description = "
           Directory holding all state for Varnish to run.
         ";
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index 5a41f96497f..3296b722048 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -296,9 +296,10 @@ in
     })
 
     (mkIf serviceCfg.contractor.enable {
-      environment.systemPackages = with  pkgs.pantheon; [
+      environment.systemPackages = with pkgs.pantheon; [
         contractor
-        extra-elementary-contracts
+        file-roller-contract
+        gnome-bluetooth-contract
       ];
 
       environment.pathsToLink = [
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.xml b/nixos/modules/services/x11/desktop-managers/pantheon.xml
index 64933349e79..fe0a1c49622 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.xml
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.xml
@@ -105,8 +105,14 @@ switchboard-with-plugs.override {
     </term>
     <listitem>
      <para>
-      AppCenter has been available since 20.03, but it is of little use. This is because there is no functioning PackageKit backend for Nix 2.0. The Flatpak backend will not work before <link xlink:href="https://github.com/elementary/appcenter/issues/1076">flag for Flatpak-only</link> is provided. See this <link xlink:href="https://github.com/NixOS/nixpkgs/issues/70214">issue</link>.
+      AppCenter has been available since 20.03, but it is of little use. This is because there is no functioning PackageKit backend for Nix 2.0. Starting from 21.11, the Flatpak backend should work so you can install some Flatpak applications using it. See this <link xlink:href="https://github.com/NixOS/nixpkgs/issues/70214">issue</link>.
      </para>
+     <para>
+      To use AppCenter on NixOS, add <literal>pantheon.appcenter</literal> to <xref linkend="opt-environment.systemPackages" />, <link linkend="module-services-flatpak">enable Flatpak support</link> and optionally add the <literal>appcenter</literal> Flatpak remote:
+     </para>
+<screen>
+<prompt>$ </prompt>flatpak remote-add --if-not-exists appcenter https://flatpak.elementary.io/repo.flatpakrepo
+</screen>
     </listitem>
    </varlistentry>
   </variablelist>
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index 8a1793484e2..9bacdaa9be9 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -4,6 +4,28 @@ let
   xcfg = config.services.xserver;
   cfg = xcfg.desktopManager.plasma5;
 
+  # Use only for **internal** options.
+  # This is not exactly user-friendly.
+  kdeConfigurationType = with types;
+    let
+      valueTypes = (oneOf [
+        bool
+        float
+        int
+        str
+      ]) // {
+        description = "KDE Configuration value";
+        emptyValue.value = "";
+      };
+      set = (nullOr (lazyAttrsOf valueTypes)) // {
+        description = "KDE Configuration set";
+        emptyValue.value = {};
+      };
+    in (lazyAttrsOf set) // {
+        description = "KDE Configuration file";
+        emptyValue.value = {};
+      };
+
   libsForQt5 = pkgs.plasma5Packages;
   inherit (libsForQt5) kdeGear kdeFrameworks plasma5;
   inherit (pkgs) writeText;
@@ -169,6 +191,37 @@ in
       type = types.bool;
       default = false;
     };
+
+    # Internally allows configuring kdeglobals globally
+    kdeglobals = mkOption {
+      internal = true;
+      default = {};
+      type = kdeConfigurationType;
+    };
+
+    # Internally allows configuring kwin globally
+    kwinrc = mkOption {
+      internal = true;
+      default = {};
+      type = kdeConfigurationType;
+    };
+
+    mobile.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable support for running the Plasma Mobile shell.
+      '';
+    };
+
+    mobile.installRecommendedSoftware = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Installs software recommended for use with Plasma Mobile, but which
+        is not strictly required for Plasma Mobile to run.
+      '';
+    };
   };
 
   imports = [
@@ -177,22 +230,8 @@ in
   ];
 
   config = mkMerge [
-    (mkIf cfg.enable {
-
-      # Seed our configuration into nixos-generate-config
-      system.nixos-generate-config.desktopConfiguration = [
-        ''
-          # Enable the Plasma 5 Desktop Environment.
-          services.xserver.displayManager.sddm.enable = true;
-          services.xserver.desktopManager.plasma5.enable = true;
-        ''
-      ];
-
-      services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-workspace ];
-      # Default to be `plasma` (X11) instead of `plasmawayland`, since plasma wayland currently has
-      # many tiny bugs.
-      # See: https://github.com/NixOS/nixpkgs/issues/143272
-      services.xserver.displayManager.defaultSession = mkDefault "plasma";
+    # Common Plasma dependencies
+    (mkIf (cfg.enable || cfg.mobile.enable) {
 
       security.wrappers = {
         kcheckpass = {
@@ -278,37 +317,24 @@ in
           kdeplasma-addons
           kgamma5
           khotkeys
-          kinfocenter
-          kmenuedit
           kscreen
           kscreenlocker
-          ksystemstats
           kwayland
           kwin
           kwrited
           libkscreen
           libksysguard
           milou
-          plasma-systemmonitor
           plasma-browser-integration
           plasma-integration
           polkit-kde-agent
-          spectacle
-          systemsettings
 
           plasma-desktop
           plasma-workspace
           plasma-workspace-wallpapers
 
-          dolphin
-          dolphin-plugins
-          ffmpegthumbs
-          kdegraphics-thumbnailers
-          khelpcenter
-          kio-extras
           konsole
           oxygen
-          print-manager
 
           breeze-icons
           pkgs.hicolor-icon-theme
@@ -319,10 +345,6 @@ in
           qtvirtualkeyboard
 
           pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
-
-          elisa
-          gwenview
-          okular
         ]
 
         # Phonon audio backend
@@ -396,7 +418,67 @@ in
           serviceConfig.Type = "oneshot";
           script = activationScript;
         };
+      };
+
+      xdg.portal.enable = true;
+      xdg.portal.extraPortals = [ plasma5.xdg-desktop-portal-kde ];
+
+      # Update the start menu for each user that is currently logged in
+      system.userActivationScripts.plasmaSetup = activationScript;
+      services.xserver.displayManager.setupCommands = startplasma;
+
+      nixpkgs.config.firefox.enablePlasmaBrowserIntegration = true;
+
+      environment.etc = {
+        "xdg/kwinrc".text     = lib.generators.toINI {} cfg.kwinrc;
+        "xdg/kdeglobals".text = lib.generators.toINI {} cfg.kdeglobals;
+      };
+    })
+
+    # Plasma Desktop
+    (mkIf cfg.enable {
+
+      # Seed our configuration into nixos-generate-config
+      system.nixos-generate-config.desktopConfiguration = [
+        ''
+          # Enable the Plasma 5 Desktop Environment.
+          services.xserver.displayManager.sddm.enable = true;
+          services.xserver.desktopManager.plasma5.enable = true;
+        ''
+      ];
 
+      services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-workspace ];
+      # Default to be `plasma` (X11) instead of `plasmawayland`, since plasma wayland currently has
+      # many tiny bugs.
+      # See: https://github.com/NixOS/nixpkgs/issues/143272
+      services.xserver.displayManager.defaultSession = mkDefault "plasma";
+
+      environment.systemPackages =
+        with libsForQt5;
+        with plasma5; with kdeGear; with kdeFrameworks;
+        [
+          ksystemstats
+          kinfocenter
+          kmenuedit
+          plasma-systemmonitor
+          spectacle
+          systemsettings
+
+          dolphin
+          dolphin-plugins
+          ffmpegthumbs
+          kdegraphics-thumbnailers
+          khelpcenter
+          kio-extras
+          print-manager
+
+          elisa
+          gwenview
+          okular
+        ]
+      ;
+
+      systemd.user.services = {
         plasma-run-with-systemd = {
           description = "Run KDE Plasma via systemd";
           wantedBy = [ "basic.target" ];
@@ -409,15 +491,88 @@ in
           '';
         };
       };
+    })
 
-      xdg.portal.enable = true;
-      xdg.portal.extraPortals = [ plasma5.xdg-desktop-portal-kde ];
+    # Plasma Mobile
+    (mkIf cfg.mobile.enable {
+      assertions = [
+        {
+          # The user interface breaks without NetworkManager
+          assertion = config.networking.networkmanager.enable;
+          message = "Plasma Mobile requires NetworkManager.";
+        }
+        {
+          # The user interface breaks without bluetooth
+          assertion = config.hardware.bluetooth.enable;
+          message = "Plasma Mobile requires Bluetooth.";
+        }
+        {
+          # The user interface breaks without pulse
+          assertion = config.hardware.pulseaudio.enable;
+          message = "Plasma Mobile requires pulseaudio.";
+        }
+      ];
 
-      # Update the start menu for each user that is currently logged in
-      system.userActivationScripts.plasmaSetup = activationScript;
-      services.xserver.displayManager.setupCommands = startplasma;
+      environment.systemPackages =
+        with libsForQt5;
+        with plasma5; with kdeApplications; with kdeFrameworks;
+        [
+          # Basic packages without which Plasma Mobile fails to work properly.
+          plasma-phone-components
+          plasma-nano
+          pkgs.maliit-framework
+          pkgs.maliit-keyboard
+        ]
+        ++ lib.optionals (cfg.mobile.installRecommendedSoftware) (with libsForQt5.plasmaMobileGear;[
+          # Additional software made for Plasma Mobile.
+          alligator
+          angelfish
+          audiotube
+          calindori
+          kalk
+          kasts
+          kclock
+          keysmith
+          koko
+          krecorder
+          ktrip
+          kweather
+          plasma-dialer
+          plasma-phonebook
+          plasma-settings
+          spacebar
+        ])
+      ;
+
+      # The following services are needed or the UI is broken.
+      hardware.bluetooth.enable = true;
+      hardware.pulseaudio.enable = true;
+      networking.networkmanager.enable = true;
+
+      # Recommendations can be found here:
+      #  - https://invent.kde.org/plasma-mobile/plasma-phone-settings/-/tree/master/etc/xdg
+      # This configuration is the minimum required for Plasma Mobile to *work*.
+      services.xserver.desktopManager.plasma5 = {
+        kdeglobals = {
+          KDE = {
+            # This forces a numeric PIN for the lockscreen, which is the
+            # recommendation from upstream.
+            LookAndFeelPackage = lib.mkDefault "org.kde.plasma.phone";
+          };
+        };
+        kwinrc = {
+          Windows = {
+            # Forces windows to be maximized
+            Placement = lib.mkDefault "Maximizing";
+          };
+          "org.kde.kdecoration2" = {
+            # No decorations (title bar)
+            NoPlugin = lib.mkDefault "true";
+          };
+        };
+      };
 
-      nixpkgs.config.firefox.enablePlasmaBrowserIntegration = true;
+      services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-phone-components ];
     })
   ];
 }
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index 25276e1d649..3cf92f98c56 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -9,7 +9,7 @@ in
 {
 
   meta = {
-    maintainers = with maintainers; [ ];
+    maintainers = teams.xfce.members;
   };
 
   imports = [
diff --git a/nixos/modules/services/x11/window-managers/xmonad.nix b/nixos/modules/services/x11/window-managers/xmonad.nix
index a8f38046137..ecad411ff68 100644
--- a/nixos/modules/services/x11/window-managers/xmonad.nix
+++ b/nixos/modules/services/x11/window-managers/xmonad.nix
@@ -39,10 +39,12 @@ in {
   options = {
     services.xserver.windowManager.xmonad = {
       enable = mkEnableOption "xmonad";
+
       haskellPackages = mkOption {
         default = pkgs.haskellPackages;
         defaultText = literalExpression "pkgs.haskellPackages";
         example = literalExpression "pkgs.haskell.packages.ghc784";
+        type = types.attrs;
         description = ''
           haskellPackages used to build Xmonad and other packages.
           This can be used to change the GHC version used to build
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index 8dbfe393f10..4a32387db8d 100644
--- a/nixos/modules/system/activation/activation-script.nix
+++ b/nixos/modules/system/activation/activation-script.nix
@@ -150,7 +150,7 @@ in
       example = literalExpression ''
         { plasmaSetup = {
             text = '''
-              ${pkgs.libsForQt5.kservice}/bin/kbuildsycoca5"
+              ''${pkgs.libsForQt5.kservice}/bin/kbuildsycoca5"
             ''';
             deps = [];
           };
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index 053496441d8..d3e9a97c212 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -11,7 +11,6 @@ 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.
@@ -25,7 +24,7 @@ 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 => 0755 });
+make_path("/run/nixos", { mode => oct(755) });
 
 my $action = shift @ARGV;
 
@@ -219,13 +218,17 @@ while (my ($unit, $state) = each %{$activePrev}) {
         }
 
         elsif (fingerprintUnit($prevUnitFile) ne fingerprintUnit($newUnitFile)) {
-            if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target") {
+            if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target" || $unit =~ /\.path$/ || $unit =~ /\.slice$/) {
                 # 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);
-            } elsif ($unit =~ /\.socket$/ || $unit =~ /\.path$/ || $unit =~ /\.slice$/) {
+            } elsif ($unit =~ /\.socket$/) {
                 # FIXME: do something?
             } else {
                 my $unitInfo = parseUnit($newUnitFile);
@@ -348,8 +351,14 @@ foreach my $device (keys %$prevSwaps) {
 
 # Should we have systemd re-exec itself?
 my $prevSystemd = abs_path("/proc/1/exe") // "/unknown";
+my $prevSystemdSystemConfig = abs_path("/etc/systemd/system.conf") // "/unknown";
 my $newSystemd = abs_path("@systemd@/lib/systemd/systemd") or die;
+my $newSystemdSystemConfig = abs_path("$out/etc/systemd/system.conf") // "/unknown";
+
 my $restartSystemd = $prevSystemd ne $newSystemd;
+if ($prevSystemdSystemConfig ne $newSystemdSystemConfig) {
+    $restartSystemd = 1;
+}
 
 
 sub filterUnits {
@@ -382,12 +391,12 @@ if ($action eq "dry-activate") {
         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;
     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;
@@ -400,7 +409,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)); # FIXME: ignore errors?
+    system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToStop));
 }
 
 print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n"
@@ -485,7 +494,7 @@ unlink($startListFile);
 
 
 # Print failed and new units.
-my (@failed, @new, @restarting);
+my (@failed, @new);
 my $activeNew = getActiveUnits;
 while (my ($unit, $state) = each %{$activeNew}) {
     if ($state->{state} eq "failed") {
@@ -501,7 +510,9 @@ while (my ($unit, $state) = each %{$activeNew}) {
             push @failed, $unit;
         }
     }
-    elsif ($state->{state} ne "failed" && !defined $activePrev->{$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$/) {
         push @new, $unit;
     }
 }
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index b04577aeb83..501998fa399 100644
--- a/nixos/modules/system/activation/top-level.nix
+++ b/nixos/modules/system/activation/top-level.nix
@@ -78,6 +78,13 @@ 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
 
@@ -201,6 +208,7 @@ in
     system.boot.loader.kernelFile = mkOption {
       internal = true;
       default = pkgs.stdenv.hostPlatform.linux-kernel.target;
+      defaultText = literalExpression "pkgs.stdenv.hostPlatform.linux-kernel.target";
       type = types.str;
       description = ''
         Name of the kernel file to be passed to the bootloader.
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index fa8500dd42b..8db271f8713 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -99,6 +99,7 @@ in
 
       enable = mkOption {
         default = !config.boot.isContainer;
+        defaultText = literalExpression "!config.boot.isContainer";
         type = types.bool;
         description = ''
           Whether to enable the GNU GRUB boot loader.
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index 2e17bdf6bb6..1145831ee2e 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -1,8 +1,8 @@
-{ config, lib, pkgs, ... }:
+{ config, lib, pkgs, utils, ... }:
 
+with utils.systemdUtils.unitOptions;
+with utils.systemdUtils.lib;
 with lib;
-with import ./systemd-unit-options.nix { inherit config lib; };
-with import ./systemd-lib.nix { inherit config lib pkgs; };
 
 let
 
@@ -572,6 +572,7 @@ let
           "Family"
           "User"
           "SuppressPrefixLength"
+          "Type"
         ])
         (assertInt "TypeOfService")
         (assertRange "TypeOfService" 0 255)
@@ -584,6 +585,7 @@ let
         (assertValueOneOf "Family" ["ipv4" "ipv6" "both"])
         (assertInt "SuppressPrefixLength")
         (assertRange "SuppressPrefixLength" 0 128)
+        (assertValueOneOf "Type" ["blackhole" "unreachable" "prohibit"])
       ];
 
       sectionRoute = checkUnitConfig "Route" [
@@ -821,6 +823,16 @@ let
         (assertValueOneOf "OnLink" boolValues)
       ];
 
+      sectionDHCPServerStaticLease = checkUnitConfig "DHCPServerStaticLease" [
+        (assertOnlyFields [
+          "MACAddress"
+          "Address"
+        ])
+        (assertHasField "MACAddress")
+        (assertHasField "Address")
+        (assertMacAddress "MACAddress")
+      ];
+
     };
   };
 
@@ -1161,6 +1173,25 @@ let
     };
   };
 
+  dhcpServerStaticLeaseOptions = {
+    options = {
+      dhcpServerStaticLeaseConfig = mkOption {
+        default = {};
+        example = { MACAddress = "65:43:4a:5b:d8:5f"; Address = "192.168.1.42"; };
+        type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPServerStaticLease;
+        description = ''
+          Each attribute in this set specifies an option in the
+          <literal>[DHCPServerStaticLease]</literal> section of the unit.  See
+          <citerefentry><refentrytitle>systemd.network</refentrytitle>
+          <manvolnum>5</manvolnum></citerefentry> for details.
+
+          Make sure to configure the corresponding client interface to use
+          <literal>ClientIdentifier=mac</literal>.
+        '';
+      };
+    };
+  };
+
   networkOptions = commonNetworkOptions // {
 
     linkConfig = mkOption {
@@ -1273,6 +1304,17 @@ let
       '';
     };
 
+    dhcpServerStaticLeases = mkOption {
+      default = [];
+      example = [ { MACAddress = "65:43:4a:5b:d8:5f"; Address = "192.168.1.42"; } ];
+      type = with types; listOf (submodule dhcpServerStaticLeaseOptions);
+      description = ''
+        A list of DHCPServerStaticLease sections to be added to the unit.  See
+        <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
     ipv6Prefixes = mkOption {
       default = [];
       example = [ { AddressAutoconfiguration = true; OnLink = true; } ];
@@ -1644,6 +1686,10 @@ let
           [IPv6Prefix]
           ${attrsToSection x.ipv6PrefixConfig}
         '')
+        + flip concatMapStrings def.dhcpServerStaticLeases (x: ''
+          [DHCPServerStaticLease]
+          ${attrsToSection x.dhcpServerStaticLeaseConfig}
+        '')
         + def.extraConfig;
     };
 
diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix
index a6fc07da0ab..21d3fab2f35 100644
--- a/nixos/modules/system/boot/resolved.nix
+++ b/nixos/modules/system/boot/resolved.nix
@@ -32,6 +32,7 @@ in
 
     services.resolved.domains = mkOption {
       default = config.networking.search;
+      defaultText = literalExpression "config.networking.search";
       example = [ "example.com" ];
       type = types.listOf types.str;
       description = ''
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 3dfcc010b64..e8e32bab6e3 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -119,6 +119,18 @@ specialMount() {
 }
 source @earlyMountScript@
 
+# Copy initrd secrets from /.initrd-secrets to their actual destinations
+if [ -d "/.initrd-secrets" ]; then
+    #
+    # Secrets are named by their full destination pathname and stored
+    # under /.initrd-secrets/
+    #
+    for secret in $(cd "/.initrd-secrets"; find . -type f); do
+        mkdir -p $(dirname "/$secret")
+        cp "/.initrd-secrets/$secret" "$secret"
+    done
+fi
+
 # Log the script output to /dev/kmsg or /run/log/stage-1-init.log.
 mkdir -p /tmp
 mkfifo /tmp/stage-1-init.log.fifo
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index adbed9d8d58..409424a5b0f 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -411,8 +411,8 @@ let
         ${lib.concatStringsSep "\n" (mapAttrsToList (dest: source:
             let source' = if source == null then dest else toString source; in
               ''
-                mkdir -p $(dirname "$tmp/${dest}")
-                cp -a ${source'} "$tmp/${dest}"
+                mkdir -p $(dirname "$tmp/.initrd-secrets/${dest}")
+                cp -a ${source'} "$tmp/.initrd-secrets/${dest}"
               ''
           ) config.boot.initrd.secrets)
          }
diff --git a/nixos/modules/system/boot/systemd-lib.nix b/nixos/modules/system/boot/systemd-lib.nix
deleted file mode 100644
index 6c4d27018ee..00000000000
--- a/nixos/modules/system/boot/systemd-lib.nix
+++ /dev/null
@@ -1,237 +0,0 @@
-{ config, lib, pkgs }:
-
-with lib;
-
-let
-  cfg = config.systemd;
-  lndir = "${pkgs.buildPackages.xorg.lndir}/bin/lndir";
-in rec {
-
-  shellEscape = s: (replaceChars [ "\\" ] [ "\\\\" ] s);
-
-  mkPathSafeName = lib.replaceChars ["@" ":" "\\" "[" "]"] ["-" "-" "-" "" ""];
-
-  makeUnit = name: unit:
-    if unit.enable then
-      pkgs.runCommand "unit-${mkPathSafeName name}"
-        { preferLocalBuild = true;
-          allowSubstitutes = false;
-          inherit (unit) text;
-        }
-        ''
-          mkdir -p $out
-          echo -n "$text" > $out/${shellEscape name}
-        ''
-    else
-      pkgs.runCommand "unit-${mkPathSafeName name}-disabled"
-        { preferLocalBuild = true;
-          allowSubstitutes = false;
-        }
-        ''
-          mkdir -p $out
-          ln -s /dev/null $out/${shellEscape name}
-        '';
-
-  boolValues = [true false "yes" "no"];
-
-  digits = map toString (range 0 9);
-
-  isByteFormat = s:
-    let
-      l = reverseList (stringToCharacters s);
-      suffix = head l;
-      nums = tail l;
-    in elem suffix (["K" "M" "G" "T"] ++ digits)
-      && all (num: elem num digits) nums;
-
-  assertByteFormat = name: group: attr:
-    optional (attr ? ${name} && ! isByteFormat attr.${name})
-      "Systemd ${group} field `${name}' must be in byte format [0-9]+[KMGT].";
-
-  hexChars = stringToCharacters "0123456789abcdefABCDEF";
-
-  isMacAddress = s: stringLength s == 17
-    && flip all (splitString ":" s) (bytes:
-      all (byte: elem byte hexChars) (stringToCharacters bytes)
-    );
-
-  assertMacAddress = name: group: attr:
-    optional (attr ? ${name} && ! isMacAddress attr.${name})
-      "Systemd ${group} field `${name}' must be a valid mac address.";
-
-  isPort = i: i >= 0 && i <= 65535;
-
-  assertPort = name: group: attr:
-    optional (attr ? ${name} && ! isPort attr.${name})
-      "Error on the systemd ${group} field `${name}': ${attr.name} is not a valid port number.";
-
-  assertValueOneOf = name: values: group: attr:
-    optional (attr ? ${name} && !elem attr.${name} values)
-      "Systemd ${group} field `${name}' cannot have value `${toString attr.${name}}'.";
-
-  assertHasField = name: group: attr:
-    optional (!(attr ? ${name}))
-      "Systemd ${group} field `${name}' must exist.";
-
-  assertRange = name: min: max: group: attr:
-    optional (attr ? ${name} && !(min <= attr.${name} && max >= attr.${name}))
-      "Systemd ${group} field `${name}' is outside the range [${toString min},${toString max}]";
-
-  assertMinimum = name: min: group: attr:
-    optional (attr ? ${name} && attr.${name} < min)
-      "Systemd ${group} field `${name}' must be greater than or equal to ${toString min}";
-
-  assertOnlyFields = fields: group: attr:
-    let badFields = filter (name: ! elem name fields) (attrNames attr); in
-    optional (badFields != [ ])
-      "Systemd ${group} has extra fields [${concatStringsSep " " badFields}].";
-
-  assertInt = name: group: attr:
-    optional (attr ? ${name} && !isInt attr.${name})
-      "Systemd ${group} field `${name}' is not an integer";
-
-  checkUnitConfig = group: checks: attrs: let
-    # We're applied at the top-level type (attrsOf unitOption), so the actual
-    # unit options might contain attributes from mkOverride and mkIf that we need to
-    # convert into single values before checking them.
-    defs = mapAttrs (const (v:
-      if v._type or "" == "override" then v.content
-      else if v._type or "" == "if" then v.content
-      else v
-    )) attrs;
-    errors = concatMap (c: c group defs) checks;
-  in if errors == [] then true
-     else builtins.trace (concatStringsSep "\n" errors) false;
-
-  toOption = x:
-    if x == true then "true"
-    else if x == false then "false"
-    else toString x;
-
-  attrsToSection = as:
-    concatStrings (concatLists (mapAttrsToList (name: value:
-      map (x: ''
-          ${name}=${toOption x}
-        '')
-        (if isList value then value else [value]))
-        as));
-
-  generateUnits = generateUnits' true;
-
-  generateUnits' = allowCollisions: type: units: upstreamUnits: upstreamWants:
-    pkgs.runCommand "${type}-units"
-      { preferLocalBuild = true;
-        allowSubstitutes = false;
-      } ''
-      mkdir -p $out
-
-      # Copy the upstream systemd units we're interested in.
-      for i in ${toString upstreamUnits}; do
-        fn=${cfg.package}/example/systemd/${type}/$i
-        if ! [ -e $fn ]; then echo "missing $fn"; false; fi
-        if [ -L $fn ]; then
-          target="$(readlink "$fn")"
-          if [ ''${target:0:3} = ../ ]; then
-            ln -s "$(readlink -f "$fn")" $out/
-          else
-            cp -pd $fn $out/
-          fi
-        else
-          ln -s $fn $out/
-        fi
-      done
-
-      # Copy .wants links, but only those that point to units that
-      # we're interested in.
-      for i in ${toString upstreamWants}; do
-        fn=${cfg.package}/example/systemd/${type}/$i
-        if ! [ -e $fn ]; then echo "missing $fn"; false; fi
-        x=$out/$(basename $fn)
-        mkdir $x
-        for i in $fn/*; do
-          y=$x/$(basename $i)
-          cp -pd $i $y
-          if ! [ -e $y ]; then rm $y; fi
-        done
-      done
-
-      # Symlink all units provided listed in systemd.packages.
-      packages="${toString cfg.packages}"
-
-      # Filter duplicate directories
-      declare -A unique_packages
-      for k in $packages ; do unique_packages[$k]=1 ; done
-
-      for i in ''${!unique_packages[@]}; do
-        for fn in $i/etc/systemd/${type}/* $i/lib/systemd/${type}/*; do
-          if ! [[ "$fn" =~ .wants$ ]]; then
-            if [[ -d "$fn" ]]; then
-              targetDir="$out/$(basename "$fn")"
-              mkdir -p "$targetDir"
-              ${lndir} "$fn" "$targetDir"
-            else
-              ln -s $fn $out/
-            fi
-          fi
-        done
-      done
-
-      # Symlink all units defined by systemd.units. If these are also
-      # provided by systemd or systemd.packages, then add them as
-      # <unit-name>.d/overrides.conf, which makes them extend the
-      # upstream unit.
-      for i in ${toString (mapAttrsToList (n: v: v.unit) units)}; do
-        fn=$(basename $i/*)
-        if [ -e $out/$fn ]; then
-          if [ "$(readlink -f $i/$fn)" = /dev/null ]; then
-            ln -sfn /dev/null $out/$fn
-          else
-            ${if allowCollisions then ''
-              mkdir -p $out/$fn.d
-              ln -s $i/$fn $out/$fn.d/overrides.conf
-            '' else ''
-              echo "Found multiple derivations configuring $fn!"
-              exit 1
-            ''}
-          fi
-       else
-          ln -fs $i/$fn $out/
-        fi
-      done
-
-      # Create service aliases from aliases option.
-      ${concatStrings (mapAttrsToList (name: unit:
-          concatMapStrings (name2: ''
-            ln -sfn '${name}' $out/'${name2}'
-          '') unit.aliases) units)}
-
-      # Create .wants and .requires symlinks from the wantedBy and
-      # requiredBy options.
-      ${concatStrings (mapAttrsToList (name: unit:
-          concatMapStrings (name2: ''
-            mkdir -p $out/'${name2}.wants'
-            ln -sfn '../${name}' $out/'${name2}.wants'/
-          '') unit.wantedBy) units)}
-
-      ${concatStrings (mapAttrsToList (name: unit:
-          concatMapStrings (name2: ''
-            mkdir -p $out/'${name2}.requires'
-            ln -sfn '../${name}' $out/'${name2}.requires'/
-          '') unit.requiredBy) units)}
-
-      ${optionalString (type == "system") ''
-        # Stupid misc. symlinks.
-        ln -s ${cfg.defaultUnit} $out/default.target
-        ln -s ${cfg.ctrlAltDelUnit} $out/ctrl-alt-del.target
-        ln -s rescue.target $out/kbrequest.target
-
-        mkdir -p $out/getty.target.wants/
-        ln -s ../autovt@tty1.service $out/getty.target.wants/
-
-        ln -s ../local-fs.target ../remote-fs.target \
-        ../nss-lookup.target ../nss-user-lookup.target ../swap.target \
-        $out/multi-user.target.wants/
-      ''}
-    ''; # */
-
-}
diff --git a/nixos/modules/system/boot/systemd-nspawn.nix b/nixos/modules/system/boot/systemd-nspawn.nix
index b450d77429b..02d2660add8 100644
--- a/nixos/modules/system/boot/systemd-nspawn.nix
+++ b/nixos/modules/system/boot/systemd-nspawn.nix
@@ -1,8 +1,8 @@
-{ config, lib , pkgs, ...}:
+{ config, lib, pkgs, utils, ...}:
 
+with utils.systemdUtils.unitOptions;
+with utils.systemdUtils.lib;
 with lib;
-with import ./systemd-unit-options.nix { inherit config lib; };
-with import ./systemd-lib.nix { inherit config lib pkgs; };
 
 let
   cfg = config.systemd.nspawn;
diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix
deleted file mode 100644
index 4154389b2ce..00000000000
--- a/nixos/modules/system/boot/systemd-unit-options.nix
+++ /dev/null
@@ -1,536 +0,0 @@
-{ config, lib }:
-
-with lib;
-with import ./systemd-lib.nix { inherit config lib pkgs; };
-
-let
-  checkService = checkUnitConfig "Service" [
-    (assertValueOneOf "Type" [
-      "exec" "simple" "forking" "oneshot" "dbus" "notify" "idle"
-    ])
-    (assertValueOneOf "Restart" [
-      "no" "on-success" "on-failure" "on-abnormal" "on-abort" "always"
-    ])
-  ];
-
-in rec {
-
-  unitOption = mkOptionType {
-    name = "systemd option";
-    merge = loc: defs:
-      let
-        defs' = filterOverrides defs;
-        defs'' = getValues defs';
-      in
-        if isList (head defs'')
-        then concatLists defs''
-        else mergeEqualOption loc defs';
-  };
-
-  sharedOptions = {
-
-    enable = mkOption {
-      default = true;
-      type = types.bool;
-      description = ''
-        If set to false, this unit will be a symlink to
-        /dev/null. This is primarily useful to prevent specific
-        template instances
-        (e.g. <literal>serial-getty@ttyS0</literal>) from being
-        started. Note that <literal>enable=true</literal> does not
-        make a unit start by default at boot; if you want that, see
-        <literal>wantedBy</literal>.
-      '';
-    };
-
-    requiredBy = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        Units that require (i.e. depend on and need to go down with)
-        this unit. The discussion under <literal>wantedBy</literal>
-        applies here as well: inverse <literal>.requires</literal>
-        symlinks are established.
-      '';
-    };
-
-    wantedBy = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        Units that want (i.e. depend on) this unit. The standard way
-        to make a unit start by default at boot is to set this option
-        to <literal>[ "multi-user.target" ]</literal>. That's despite
-        the fact that the systemd.unit(5) manpage says this option
-        goes in the <literal>[Install]</literal> section that controls
-        the behaviour of <literal>systemctl enable</literal>. Since
-        such a process is stateful and thus contrary to the design of
-        NixOS, setting this option instead causes the equivalent
-        inverse <literal>.wants</literal> symlink to be present,
-        establishing the same desired relationship in a stateless way.
-      '';
-    };
-
-    aliases = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = "Aliases of that unit.";
-    };
-
-  };
-
-  concreteUnitOptions = sharedOptions // {
-
-    text = mkOption {
-      type = types.nullOr types.str;
-      default = null;
-      description = "Text of this systemd unit.";
-    };
-
-    unit = mkOption {
-      internal = true;
-      description = "The generated unit.";
-    };
-
-  };
-
-  commonUnitOptions = sharedOptions // {
-
-    description = mkOption {
-      default = "";
-      type = types.str;
-      description = "Description of this unit used in systemd messages and progress indicators.";
-    };
-
-    documentation = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = "A list of URIs referencing documentation for this unit or its configuration.";
-    };
-
-    requires = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        Start the specified units when this unit is started, and stop
-        this unit when the specified units are stopped or fail.
-      '';
-    };
-
-    wants = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        Start the specified units when this unit is started.
-      '';
-    };
-
-    after = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        If the specified units are started at the same time as
-        this unit, delay this unit until they have started.
-      '';
-    };
-
-    before = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        If the specified units are started at the same time as
-        this unit, delay them until this unit has started.
-      '';
-    };
-
-    bindsTo = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        Like ‘requires’, but in addition, if the specified units
-        unexpectedly disappear, this unit will be stopped as well.
-      '';
-    };
-
-    partOf = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        If the specified units are stopped or restarted, then this
-        unit is stopped or restarted as well.
-      '';
-    };
-
-    conflicts = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        If the specified units are started, then this unit is stopped
-        and vice versa.
-      '';
-    };
-
-    requisite = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        Similar to requires. However if the units listed are not started,
-        they will not be started and the transaction will fail.
-      '';
-    };
-
-    unitConfig = mkOption {
-      default = {};
-      example = { RequiresMountsFor = "/data"; };
-      type = types.attrsOf unitOption;
-      description = ''
-        Each attribute in this set specifies an option in the
-        <literal>[Unit]</literal> section of the unit.  See
-        <citerefentry><refentrytitle>systemd.unit</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> for details.
-      '';
-    };
-
-    restartTriggers = mkOption {
-      default = [];
-      type = types.listOf types.unspecified;
-      description = ''
-        An arbitrary list of items such as derivations.  If any item
-        in the list changes between reconfigurations, the service will
-        be restarted.
-      '';
-    };
-
-    onFailure = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      description = ''
-        A list of one or more units that are activated when
-        this unit enters the "failed" state.
-      '';
-    };
-
-    startLimitBurst = mkOption {
-       type = types.int;
-       description = ''
-         Configure unit start rate limiting. Units which are started
-         more than startLimitBurst times within an interval time
-         interval are not permitted to start any more.
-       '';
-    };
-
-    startLimitIntervalSec = mkOption {
-       type = types.int;
-       description = ''
-         Configure unit start rate limiting. Units which are started
-         more than startLimitBurst times within an interval time
-         interval are not permitted to start any more.
-       '';
-    };
-
-  };
-
-
-  serviceOptions = commonUnitOptions // {
-
-    environment = mkOption {
-      default = {};
-      type = with types; attrsOf (nullOr (oneOf [ str path package ]));
-      example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
-      description = "Environment variables passed to the service's processes.";
-    };
-
-    path = mkOption {
-      default = [];
-      type = with types; listOf (oneOf [ package str ]);
-      description = ''
-        Packages added to the service's <envar>PATH</envar>
-        environment variable.  Both the <filename>bin</filename>
-        and <filename>sbin</filename> subdirectories of each
-        package are added.
-      '';
-    };
-
-    serviceConfig = mkOption {
-      default = {};
-      example =
-        { RestartSec = 5;
-        };
-      type = types.addCheck (types.attrsOf unitOption) checkService;
-      description = ''
-        Each attribute in this set specifies an option in the
-        <literal>[Service]</literal> section of the unit.  See
-        <citerefentry><refentrytitle>systemd.service</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> for details.
-      '';
-    };
-
-    script = mkOption {
-      type = types.lines;
-      default = "";
-      description = "Shell commands executed as the service's main process.";
-    };
-
-    scriptArgs = mkOption {
-      type = types.str;
-      default = "";
-      description = "Arguments passed to the main process script.";
-    };
-
-    preStart = mkOption {
-      type = types.lines;
-      default = "";
-      description = ''
-        Shell commands executed before the service's main process
-        is started.
-      '';
-    };
-
-    postStart = mkOption {
-      type = types.lines;
-      default = "";
-      description = ''
-        Shell commands executed after the service's main process
-        is started.
-      '';
-    };
-
-    reload = mkOption {
-      type = types.lines;
-      default = "";
-      description = ''
-        Shell commands executed when the service's main process
-        is reloaded.
-      '';
-    };
-
-    preStop = mkOption {
-      type = types.lines;
-      default = "";
-      description = ''
-        Shell commands executed to stop the service.
-      '';
-    };
-
-    postStop = mkOption {
-      type = types.lines;
-      default = "";
-      description = ''
-        Shell commands executed after the service's main process
-        has exited.
-      '';
-    };
-
-    restartIfChanged = mkOption {
-      type = types.bool;
-      default = true;
-      description = ''
-        Whether the service should be restarted during a NixOS
-        configuration switch if its definition has changed.
-      '';
-    };
-
-    reloadIfChanged = mkOption {
-      type = types.bool;
-      default = false;
-      description = ''
-        Whether the service should be reloaded during a NixOS
-        configuration switch if its definition has changed.  If
-        enabled, the value of <option>restartIfChanged</option> is
-        ignored.
-      '';
-    };
-
-    stopIfChanged = mkOption {
-      type = types.bool;
-      default = true;
-      description = ''
-        If set, a changed unit is restarted by calling
-        <command>systemctl stop</command> in the old configuration,
-        then <command>systemctl start</command> in the new one.
-        Otherwise, it is restarted in a single step using
-        <command>systemctl restart</command> in the new configuration.
-        The latter is less correct because it runs the
-        <literal>ExecStop</literal> commands from the new
-        configuration.
-      '';
-    };
-
-    startAt = mkOption {
-      type = with types; either str (listOf str);
-      default = [];
-      example = "Sun 14:00:00";
-      description = ''
-        Automatically start this unit at the given date/time, which
-        must be in the format described in
-        <citerefentry><refentrytitle>systemd.time</refentrytitle>
-        <manvolnum>7</manvolnum></citerefentry>.  This is equivalent
-        to adding a corresponding timer unit with
-        <option>OnCalendar</option> set to the value given here.
-      '';
-      apply = v: if isList v then v else [ v ];
-    };
-
-  };
-
-
-  socketOptions = commonUnitOptions // {
-
-    listenStreams = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      example = [ "0.0.0.0:993" "/run/my-socket" ];
-      description = ''
-        For each item in this list, a <literal>ListenStream</literal>
-        option in the <literal>[Socket]</literal> section will be created.
-      '';
-    };
-
-    listenDatagrams = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      example = [ "0.0.0.0:993" "/run/my-socket" ];
-      description = ''
-        For each item in this list, a <literal>ListenDatagram</literal>
-        option in the <literal>[Socket]</literal> section will be created.
-      '';
-    };
-
-    socketConfig = mkOption {
-      default = {};
-      example = { ListenStream = "/run/my-socket"; };
-      type = types.attrsOf unitOption;
-      description = ''
-        Each attribute in this set specifies an option in the
-        <literal>[Socket]</literal> section of the unit.  See
-        <citerefentry><refentrytitle>systemd.socket</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> for details.
-      '';
-    };
-
-  };
-
-
-  timerOptions = commonUnitOptions // {
-
-    timerConfig = mkOption {
-      default = {};
-      example = { OnCalendar = "Sun 14:00:00"; Unit = "foo.service"; };
-      type = types.attrsOf unitOption;
-      description = ''
-        Each attribute in this set specifies an option in the
-        <literal>[Timer]</literal> section of the unit.  See
-        <citerefentry><refentrytitle>systemd.timer</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> and
-        <citerefentry><refentrytitle>systemd.time</refentrytitle>
-        <manvolnum>7</manvolnum></citerefentry> for details.
-      '';
-    };
-
-  };
-
-
-  pathOptions = commonUnitOptions // {
-
-    pathConfig = mkOption {
-      default = {};
-      example = { PathChanged = "/some/path"; Unit = "changedpath.service"; };
-      type = types.attrsOf unitOption;
-      description = ''
-        Each attribute in this set specifies an option in the
-        <literal>[Path]</literal> section of the unit.  See
-        <citerefentry><refentrytitle>systemd.path</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> for details.
-      '';
-    };
-
-  };
-
-
-  mountOptions = commonUnitOptions // {
-
-    what = mkOption {
-      example = "/dev/sda1";
-      type = types.str;
-      description = "Absolute path of device node, file or other resource. (Mandatory)";
-    };
-
-    where = mkOption {
-      example = "/mnt";
-      type = types.str;
-      description = ''
-        Absolute path of a directory of the mount point.
-        Will be created if it doesn't exist. (Mandatory)
-      '';
-    };
-
-    type = mkOption {
-      default = "";
-      example = "ext4";
-      type = types.str;
-      description = "File system type.";
-    };
-
-    options = mkOption {
-      default = "";
-      example = "noatime";
-      type = types.commas;
-      description = "Options used to mount the file system.";
-    };
-
-    mountConfig = mkOption {
-      default = {};
-      example = { DirectoryMode = "0775"; };
-      type = types.attrsOf unitOption;
-      description = ''
-        Each attribute in this set specifies an option in the
-        <literal>[Mount]</literal> section of the unit.  See
-        <citerefentry><refentrytitle>systemd.mount</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> for details.
-      '';
-    };
-  };
-
-  automountOptions = commonUnitOptions // {
-
-    where = mkOption {
-      example = "/mnt";
-      type = types.str;
-      description = ''
-        Absolute path of a directory of the mount point.
-        Will be created if it doesn't exist. (Mandatory)
-      '';
-    };
-
-    automountConfig = mkOption {
-      default = {};
-      example = { DirectoryMode = "0775"; };
-      type = types.attrsOf unitOption;
-      description = ''
-        Each attribute in this set specifies an option in the
-        <literal>[Automount]</literal> section of the unit.  See
-        <citerefentry><refentrytitle>systemd.automount</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> for details.
-      '';
-    };
-  };
-
-  targetOptions = commonUnitOptions;
-
-  sliceOptions = commonUnitOptions // {
-
-    sliceConfig = mkOption {
-      default = {};
-      example = { MemoryMax = "2G"; };
-      type = types.attrsOf unitOption;
-      description = ''
-        Each attribute in this set specifies an option in the
-        <literal>[Slice]</literal> section of the unit.  See
-        <citerefentry><refentrytitle>systemd.slice</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> for details.
-      '';
-    };
-
-  };
-
-}
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 6e0ee437d91..ec5dea075bb 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -1,9 +1,9 @@
 { config, lib, pkgs, utils, ... }:
 
 with utils;
+with systemdUtils.unitOptions;
+with systemdUtils.lib;
 with lib;
-with import ./systemd-unit-options.nix { inherit config lib; };
-with import ./systemd-lib.nix { inherit config lib pkgs; };
 
 let
 
diff --git a/nixos/modules/system/boot/timesyncd.nix b/nixos/modules/system/boot/timesyncd.nix
index 692315dbe99..5f35a154769 100644
--- a/nixos/modules/system/boot/timesyncd.nix
+++ b/nixos/modules/system/boot/timesyncd.nix
@@ -9,6 +9,7 @@ with lib;
     services.timesyncd = {
       enable = mkOption {
         default = !config.boot.isContainer;
+        defaultText = literalExpression "!config.boot.isContainer";
         type = types.bool;
         description = ''
           Enables the systemd NTP client daemon.
@@ -16,6 +17,7 @@ with lib;
       };
       servers = mkOption {
         default = config.networking.timeServers;
+        defaultText = literalExpression "config.networking.timeServers";
         type = types.listOf types.str;
         description = ''
           The set of NTP servers from which to synchronise.
diff --git a/nixos/modules/tasks/snapraid.nix b/nixos/modules/tasks/snapraid.nix
index ff956f30670..c8dde5b4899 100644
--- a/nixos/modules/tasks/snapraid.nix
+++ b/nixos/modules/tasks/snapraid.nix
@@ -207,7 +207,7 @@ in
             SystemCallArchitectures = "native";
             SystemCallFilter = "@system-service";
             SystemCallErrorNumber = "EPERM";
-            CapabilityBoundingSet = "CAP_DAC_OVERRIDE" ++
+            CapabilityBoundingSet = "CAP_DAC_OVERRIDE" +
               lib.optionalString cfg.touchBeforeSync " CAP_FOWNER";
 
             ProtectSystem = "strict";
diff --git a/nixos/modules/virtualisation/amazon-options.nix b/nixos/modules/virtualisation/amazon-options.nix
index 698edcd835a..0465571ca92 100644
--- a/nixos/modules/virtualisation/amazon-options.nix
+++ b/nixos/modules/virtualisation/amazon-options.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 let
-  inherit (lib) types;
+  inherit (lib) literalExpression types;
 in {
   options = {
     ec2 = {
@@ -50,6 +50,7 @@ in {
       };
       efi = lib.mkOption {
         default = pkgs.stdenv.hostPlatform.isAarch64;
+        defaultText = literalExpression "pkgs.stdenv.hostPlatform.isAarch64";
         internal = true;
         description = ''
           Whether the EC2 instance is using EFI.
diff --git a/nixos/modules/virtualisation/nixos-containers.nix b/nixos/modules/virtualisation/nixos-containers.nix
index 279c9656735..0838a57f0f3 100644
--- a/nixos/modules/virtualisation/nixos-containers.nix
+++ b/nixos/modules/virtualisation/nixos-containers.nix
@@ -716,9 +716,9 @@ in
               { config =
                   { config, pkgs, ... }:
                   { services.postgresql.enable = true;
-                    services.postgresql.package = pkgs.postgresql_9_6;
+                    services.postgresql.package = pkgs.postgresql_10;
 
-                    system.stateVersion = "17.03";
+                    system.stateVersion = "21.05";
                   };
               };
           }
diff --git a/nixos/modules/virtualisation/podman.nix b/nixos/modules/virtualisation/podman/default.nix
index 385475c84a1..94fd727a4b5 100644
--- a/nixos/modules/virtualisation/podman.nix
+++ b/nixos/modules/virtualisation/podman/default.nix
@@ -39,8 +39,8 @@ let
 in
 {
   imports = [
-    ./podman-dnsname.nix
-    ./podman-network-socket.nix
+    ./dnsname.nix
+    ./network-socket.nix
     (lib.mkRenamedOptionModule [ "virtualisation" "podman" "libpod" ] [ "virtualisation" "containers" "containersConf" ])
   ];
 
diff --git a/nixos/modules/virtualisation/podman-dnsname.nix b/nixos/modules/virtualisation/podman/dnsname.nix
index beef1975507..beef1975507 100644
--- a/nixos/modules/virtualisation/podman-dnsname.nix
+++ b/nixos/modules/virtualisation/podman/dnsname.nix
diff --git a/nixos/modules/virtualisation/podman-network-socket-ghostunnel.nix b/nixos/modules/virtualisation/podman/network-socket-ghostunnel.nix
index a0e7e433164..a0e7e433164 100644
--- a/nixos/modules/virtualisation/podman-network-socket-ghostunnel.nix
+++ b/nixos/modules/virtualisation/podman/network-socket-ghostunnel.nix
diff --git a/nixos/modules/virtualisation/podman-network-socket.nix b/nixos/modules/virtualisation/podman/network-socket.nix
index 1429164630b..94d8da9d2b6 100644
--- a/nixos/modules/virtualisation/podman-network-socket.nix
+++ b/nixos/modules/virtualisation/podman/network-socket.nix
@@ -9,6 +9,10 @@ let
 
 in
 {
+  imports = [
+    ./network-socket-ghostunnel.nix
+  ];
+
   options.virtualisation.podman.networkSocket = {
     enable = mkOption {
       type = types.bool;
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 91356ac1d98..fa3e25afb03 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -329,6 +329,7 @@ in
       mkOption {
         type = types.str;
         default = "./${config.system.name}.qcow2";
+        defaultText = literalExpression ''"./''${config.system.name}.qcow2"'';
         description =
           ''
             Path to the disk image containing the root filesystem.
@@ -678,6 +679,7 @@ in
       mkOption {
         type = types.str;
         default = "./${config.system.name}-efi-vars.fd";
+        defaultText = literalExpression ''"./''${config.system.name}-efi-vars.fd"'';
         description =
           ''
             Path to nvram image containing UEFI variables.  The will be created
@@ -833,6 +835,7 @@ in
 
     # FIXME: Consolidate this one day.
     virtualisation.qemu.options = mkMerge [
+      [ "-device virtio-keyboard" ]
       (mkIf pkgs.stdenv.hostPlatform.isx86 [
         "-usb" "-device usb-tablet,bus=usb-bus.0"
       ])