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.nix2
-rw-r--r--nixos/modules/config/users-groups.nix5
-rw-r--r--nixos/modules/hardware/all-firmware.nix1
-rw-r--r--nixos/modules/hardware/video/displaylink.nix1
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix1
-rw-r--r--nixos/modules/installer/cd-dvd/iso-image.nix12
-rw-r--r--nixos/modules/module-list.nix2
-rw-r--r--nixos/modules/profiles/headless.nix4
-rw-r--r--nixos/modules/programs/gnupg.nix9
-rw-r--r--nixos/modules/programs/shadow.nix308
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/job-builder.nix27
-rw-r--r--nixos/modules/services/games/mchprs.nix341
-rw-r--r--nixos/modules/services/games/minetest-server.nix71
-rw-r--r--nixos/modules/services/hardware/pcscd.nix3
-rw-r--r--nixos/modules/services/hardware/udev.nix2
-rw-r--r--nixos/modules/services/misc/ankisyncd.nix22
-rw-r--r--nixos/modules/services/misc/calibre-server.nix94
-rw-r--r--nixos/modules/services/misc/gitea.nix17
-rw-r--r--nixos/modules/services/misc/gitlab.nix2
-rw-r--r--nixos/modules/services/misc/gollum.nix24
-rw-r--r--nixos/modules/services/misc/n8n.nix10
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix2
-rw-r--r--nixos/modules/services/misc/nix-optimise.nix31
-rw-r--r--nixos/modules/services/misc/ntfy-sh.nix20
-rw-r--r--nixos/modules/services/misc/paperless.nix5
-rw-r--r--nixos/modules/services/monitoring/grafana.nix2
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters.nix17
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/php-fpm.nix65
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/scaphandre.nix33
-rw-r--r--nixos/modules/services/networking/pdns-recursor.nix2
-rw-r--r--nixos/modules/services/networking/powerdns.nix2
-rw-r--r--nixos/modules/services/networking/searx.nix59
-rw-r--r--nixos/modules/services/networking/sing-box.nix1
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix10
-rw-r--r--nixos/modules/services/networking/thelounge.nix18
-rw-r--r--nixos/modules/services/security/fail2ban.nix225
-rw-r--r--nixos/modules/services/security/usbguard.nix125
-rw-r--r--nixos/modules/services/security/vaultwarden/default.nix7
-rw-r--r--nixos/modules/services/system/cloud-init.nix9
-rw-r--r--nixos/modules/services/system/dbus.nix2
-rw-r--r--nixos/modules/services/web-apps/anuko-time-tracker.nix78
-rw-r--r--nixos/modules/services/web-apps/lemmy.nix26
-rw-r--r--nixos/modules/services/web-apps/snipe-it.nix9
-rw-r--r--nixos/modules/services/web-servers/caddy/default.nix38
-rw-r--r--nixos/modules/services/web-servers/static-web-server.nix68
-rw-r--r--nixos/modules/services/web-servers/ttyd.nix11
-rw-r--r--nixos/modules/services/x11/desktop-managers/cde.nix4
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.nix1
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix4
-rw-r--r--nixos/modules/services/x11/xserver.nix2
-rw-r--r--nixos/modules/system/boot/networkd.nix345
-rw-r--r--nixos/modules/tasks/bcache.nix8
-rw-r--r--nixos/modules/tasks/filesystems/bcachefs.nix14
-rw-r--r--nixos/modules/tasks/lvm.nix17
-rw-r--r--nixos/modules/tasks/swraid.nix8
-rw-r--r--nixos/modules/virtualisation/proxmox-image.nix10
56 files changed, 1480 insertions, 756 deletions
diff --git a/nixos/modules/config/fonts/fontdir.nix b/nixos/modules/config/fonts/fontdir.nix
index 30e0dfe2566..9d41463c947 100644
--- a/nixos/modules/config/fonts/fontdir.nix
+++ b/nixos/modules/config/fonts/fontdir.nix
@@ -8,7 +8,7 @@ let
 
   x11Fonts = pkgs.runCommand "X11-fonts" { preferLocalBuild = true; } ''
     mkdir -p "$out/share/X11/fonts"
-    font_regexp='.*\.\(ttf\|ttc\|otf\|pcf\|pfa\|pfb\|bdf\)\(\.gz\)?'
+    font_regexp='.*\.\(ttf\|ttc\|otb\|otf\|pcf\|pfa\|pfb\|bdf\)\(\.gz\)?'
     find ${toString config.fonts.fonts} -regex "$font_regexp" \
       -exec ln -sf -t "$out/share/X11/fonts" '{}' \;
     cd "$out/share/X11/fonts"
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 4640a0f3d6b..4c9e286ea5f 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -539,14 +539,12 @@ in {
 
     # systemd initrd
     boot.initrd.systemd.users = mkOption {
-      visible = false;
       description = ''
         Users to include in initrd.
       '';
       default = {};
       type = types.attrsOf (types.submodule ({ name, ... }: {
         options.uid = mkOption {
-          visible = false;
           type = types.int;
           description = ''
             ID of the user in initrd.
@@ -555,7 +553,6 @@ in {
           default = cfg.users.${name}.uid;
         };
         options.group = mkOption {
-          visible = false;
           type = types.singleLineStr;
           description = ''
             Group the user belongs to in initrd.
@@ -567,14 +564,12 @@ in {
     };
 
     boot.initrd.systemd.groups = mkOption {
-      visible = false;
       description = ''
         Groups to include in initrd.
       '';
       default = {};
       type = types.attrsOf (types.submodule ({ name, ... }: {
         options.gid = mkOption {
-          visible = false;
           type = types.int;
           description = ''
             ID of the group in initrd.
diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix
index 75247286368..9e7a01c58af 100644
--- a/nixos/modules/hardware/all-firmware.nix
+++ b/nixos/modules/hardware/all-firmware.nix
@@ -55,7 +55,6 @@ in {
         intel2200BGFirmware
         rtl8192su-firmware
         rt5677-firmware
-        rtl8723bs-firmware
         rtl8761b-firmware
         rtw88-firmware
         zd1211fw
diff --git a/nixos/modules/hardware/video/displaylink.nix b/nixos/modules/hardware/video/displaylink.nix
index 912f53da836..ce5fbeeae53 100644
--- a/nixos/modules/hardware/video/displaylink.nix
+++ b/nixos/modules/hardware/video/displaylink.nix
@@ -26,6 +26,7 @@ in
         Identifier  "DisplayLink"
         MatchDriver "evdi"
         Driver      "modesetting"
+        Option      "TearFree" "true"
         Option      "AccelMethod" "none"
       EndSection
     '';
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
index 573b31b439c..ea8056ff870 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
@@ -6,6 +6,7 @@
   imports = [ ./installation-cd-graphical-base.nix ];
 
   isoImage.edition = "gnome";
+  isoImage.graphicalGrub = true;
 
   services.xserver.desktopManager.gnome = {
     # Add Firefox and other tools useful for installation to the launcher
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index f9cbafc2865..c430048d659 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -283,7 +283,7 @@ let
     cat <<EOF > $out/EFI/boot/grub.cfg
 
     set with_fonts=false
-    set textmode=false
+    set textmode=${boolToString (!config.isoImage.graphicalGrub)}
     # If you want to use serial for "terminal_*" commands, you need to set one up:
     #   Example manual configuration:
     #    → serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
@@ -658,6 +658,16 @@ in
       '';
     };
 
+    isoImage.graphicalGrub = mkOption {
+      default = false;
+      type = types.bool;
+      example = true;
+      description = lib.mdDoc ''
+        Whether to use textmode or graphical grub.
+        false means we use textmode grub.
+      '';
+    };
+
   };
 
   # store them in lib so we can mkImageMediaOverride the
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index e728dcb3f19..bd715535dd6 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -476,6 +476,7 @@
   ./services/games/deliantra-server.nix
   ./services/games/factorio.nix
   ./services/games/freeciv.nix
+  ./services/games/mchprs.nix
   ./services/games/minecraft-server.nix
   ./services/games/minetest-server.nix
   ./services/games/openarena.nix
@@ -1282,6 +1283,7 @@
   ./services/web-servers/pomerium.nix
   ./services/web-servers/rustus.nix
   ./services/web-servers/stargazer.nix
+  ./services/web-servers/static-web-server.nix
   ./services/web-servers/tomcat.nix
   ./services/web-servers/traefik.nix
   ./services/web-servers/trafficserver/default.nix
diff --git a/nixos/modules/profiles/headless.nix b/nixos/modules/profiles/headless.nix
index c17cb287b72..eb29f3d6510 100644
--- a/nixos/modules/profiles/headless.nix
+++ b/nixos/modules/profiles/headless.nix
@@ -6,8 +6,6 @@
 with lib;
 
 {
-  boot.vesa = false;
-
   # Don't start a tty on the serial consoles.
   systemd.services."serial-getty@ttyS0".enable = lib.mkDefault false;
   systemd.services."serial-getty@hvc0".enable = false;
@@ -15,7 +13,7 @@ with lib;
   systemd.services."autovt@".enable = false;
 
   # Since we can't manually respond to a panic, just reboot.
-  boot.kernelParams = [ "panic=1" "boot.panic_on_fail" ];
+  boot.kernelParams = [ "panic=1" "boot.panic_on_fail" "vga=0x317" "nomodeset" ];
 
   # Don't allow emergency mode, because we don't have a console.
   systemd.enableEmergencyMode = false;
diff --git a/nixos/modules/programs/gnupg.nix b/nixos/modules/programs/gnupg.nix
index 3dfc53c5261..697b6e9a0bd 100644
--- a/nixos/modules/programs/gnupg.nix
+++ b/nixos/modules/programs/gnupg.nix
@@ -75,9 +75,7 @@ in
       defaultText = literalMD ''matching the configured desktop environment'';
       description = lib.mdDoc ''
         Which pinentry interface to use. If not null, the path to the
-        pinentry binary will be passed to gpg-agent via commandline and
-        thus overrides the pinentry option in gpg-agent.conf in the user's
-        home directory.
+        pinentry binary will be set in /etc/gnupg/gpg-agent.conf.
         If not set at all, it'll pick an appropriate flavor depending on the
         system configuration (qt flavor for lxqt and plasma5, gtk2 for xfce
         4.12, gnome3 on all other systems with X enabled, ncurses otherwise).
@@ -94,12 +92,13 @@ in
   };
 
   config = mkIf cfg.agent.enable {
-    environment.etc."gnupg/gpg-agent.conf".text = ''
+    environment.etc."gnupg/gpg-agent.conf".text =
+      lib.optionalString (cfg.agent.pinentryFlavor != null) ''
       pinentry-program ${pkgs.pinentry.${cfg.agent.pinentryFlavor}}/bin/pinentry
     '';
 
     # This overrides the systemd user unit shipped with the gnupg package
-    systemd.user.services.gpg-agent = mkIf (cfg.agent.pinentryFlavor != null) {
+    systemd.user.services.gpg-agent = {
       unitConfig = {
         Description = "GnuPG cryptographic agent and passphrase cache";
         Documentation = "man:gpg-agent(1)";
diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix
index 35267acd6bb..00895db03fc 100644
--- a/nixos/modules/programs/shadow.nix
+++ b/nixos/modules/programs/shadow.nix
@@ -1,67 +1,131 @@
 # Configuration for the pwdutils suite of tools: passwd, useradd, etc.
-
 { config, lib, utils, pkgs, ... }:
-
 with lib;
-
 let
-
-  /*
-  There are three different sources for user/group id ranges, each of which gets
-  used by different programs:
-  - The login.defs file, used by the useradd, groupadd and newusers commands
-  - The update-users-groups.pl file, used by NixOS in the activation phase to
-    decide on which ids to use for declaratively defined users without a static
-    id
-  - Systemd compile time options -Dsystem-uid-max= and -Dsystem-gid-max=, used
-    by systemd for features like ConditionUser=@system and systemd-sysusers
-  */
-  loginDefs =
-    ''
-      DEFAULT_HOME yes
-
-      SYS_UID_MIN  400
-      SYS_UID_MAX  999
-      UID_MIN      1000
-      UID_MAX      29999
-
-      SYS_GID_MIN  400
-      SYS_GID_MAX  999
-      GID_MIN      1000
-      GID_MAX      29999
-
-      TTYGROUP     tty
-      TTYPERM      0620
-
-      # Ensure privacy for newly created home directories.
-      UMASK        077
-
-      # Uncomment this and install chfn SUID to allow non-root
-      # users to change their account GECOS information.
-      # This should be made configurable.
-      #CHFN_RESTRICT frwh
-
-      # The default crypt() method, keep in sync with the PAM default
-      ENCRYPT_METHOD YESCRYPT
-    '';
-
-  mkSetuidRoot = source:
-    { setuid = true;
-      owner = "root";
-      group = "root";
-      inherit source;
-    };
-
+  cfg = config.security.loginDefs;
 in
-
 {
+  options = with types; {
+    security.loginDefs = {
+      package = mkPackageOptionMD pkgs "shadow" { };
+
+      chfnRestrict = mkOption {
+        description = mdDoc ''
+          Use chfn SUID to allow non-root users to change their account GECOS information.
+        '';
+        type = nullOr str;
+        default = null;
+      };
 
-  ###### interface
-
-  options = {
+      settings = mkOption {
+        description = mdDoc ''
+          Config options for the /etc/login.defs file, that defines
+          the site-specific configuration for the shadow password suite.
+          See login.defs(5) man page for available options.
+        '';
+        type = submodule {
+          freeformType = (pkgs.formats.keyValue { }).type;
+          /* There are three different sources for user/group id ranges, each of which gets
+             used by different programs:
+             - The login.defs file, used by the useradd, groupadd and newusers commands
+             - The update-users-groups.pl file, used by NixOS in the activation phase to
+               decide on which ids to use for declaratively defined users without a static
+               id
+             - Systemd compile time options -Dsystem-uid-max= and -Dsystem-gid-max=, used
+               by systemd for features like ConditionUser=@system and systemd-sysusers
+              */
+          options = {
+            DEFAULT_HOME = mkOption {
+              description = mdDoc "Indicate if login is allowed if we can't cd to the home directory.";
+              default = "yes";
+              type = enum [ "yes" "no" ];
+            };
+
+            ENCRYPT_METHOD = mkOption {
+              description = mdDoc "This defines the system default encryption algorithm for encrypting passwords.";
+              # The default crypt() method, keep in sync with the PAM default
+              default = "YESCRYPT";
+              type = enum [ "YESCRYPT" "SHA512" "SHA256" "MD5" "DES"];
+            };
+
+            SYS_UID_MIN = mkOption {
+              description = mdDoc "Range of user IDs used for the creation of system users by useradd or newusers.";
+              default = 400;
+              type = int;
+            };
+
+            SYS_UID_MAX = mkOption {
+              description = mdDoc "Range of user IDs used for the creation of system users by useradd or newusers.";
+              default = 999;
+              type = int;
+            };
+
+            UID_MIN = mkOption {
+              description = mdDoc "Range of user IDs used for the creation of regular users by useradd or newusers.";
+              default = 1000;
+              type = int;
+            };
+
+            UID_MAX = mkOption {
+              description = mdDoc "Range of user IDs used for the creation of regular users by useradd or newusers.";
+              default = 29999;
+              type = int;
+            };
+
+            SYS_GID_MIN = mkOption {
+              description = mdDoc "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers";
+              default = 400;
+              type = int;
+            };
+
+            SYS_GID_MAX = mkOption {
+              description = mdDoc "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers";
+              default = 999;
+              type = int;
+            };
+
+            GID_MIN = mkOption {
+              description = mdDoc "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers.";
+              default = 1000;
+              type = int;
+            };
+
+            GID_MAX = mkOption {
+              description = mdDoc "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers.";
+              default = 29999;
+              type = int;
+            };
+
+            TTYGROUP = mkOption {
+              description = mdDoc ''
+                The terminal permissions: the login tty will be owned by the TTYGROUP group,
+                and the permissions will be set to TTYPERM'';
+              default = "tty";
+              type = str;
+            };
+
+            TTYPERM = mkOption {
+              description = mdDoc ''
+                The terminal permissions: the login tty will be owned by the TTYGROUP group,
+                and the permissions will be set to TTYPERM'';
+              default = "0620";
+              type = str;
+            };
+
+            # Ensure privacy for newly created home directories.
+            UMASK = mkOption {
+              description = mdDoc "The file mode creation mask is initialized to this value.";
+              default = "077";
+              type = str;
+            };
+          };
+        };
+        default = { };
+      };
+    };
 
-    users.defaultUserShell = lib.mkOption {
-      description = lib.mdDoc ''
+    users.defaultUserShell = mkOption {
+      description = mdDoc ''
         This option defines the default shell assigned to user
         accounts. This can be either a full system path or a shell package.
 
@@ -69,63 +133,107 @@ in
         used outside the store (in particular in /etc/passwd).
       '';
       example = literalExpression "pkgs.zsh";
-      type = types.either types.path types.shellPackage;
+      type = either path shellPackage;
     };
-
   };
 
-
   ###### implementation
 
   config = {
-
-    environment.systemPackages =
-      lib.optional config.users.mutableUsers pkgs.shadow ++
-      lib.optional (types.shellPackage.check config.users.defaultUserShell)
-        config.users.defaultUserShell;
+    assertions = [
+      {
+        assertion = cfg.settings.SYS_UID_MIN <= cfg.settings.SYS_UID_MAX;
+        message = "SYS_UID_MIN must be less than or equal to SYS_UID_MAX";
+      }
+      {
+        assertion = cfg.settings.UID_MIN <= cfg.settings.UID_MAX;
+        message = "UID_MIN must be less than or equal to UID_MAX";
+      }
+      {
+        assertion = cfg.settings.SYS_GID_MIN <= cfg.settings.SYS_GID_MAX;
+        message = "SYS_GID_MIN must be less than or equal to SYS_GID_MAX";
+      }
+      {
+        assertion = cfg.settings.GID_MIN <= cfg.settings.GID_MAX;
+        message = "GID_MIN must be less than or equal to GID_MAX";
+      }
+    ];
+
+    security.loginDefs.settings.CHFN_RESTRICT =
+      mkIf (cfg.chfnRestrict != null) cfg.chfnRestrict;
+
+    environment.systemPackages = optional config.users.mutableUsers cfg.package
+      ++ optional (types.shellPackage.check config.users.defaultUserShell) config.users.defaultUserShell
+      ++ optional (cfg.chfnRestrict != null) pkgs.util-linux;
 
     environment.etc =
-      { # /etc/login.defs: global configuration for pwdutils.  You
-        # cannot login without it!
-        "login.defs".source = pkgs.writeText "login.defs" loginDefs;
+      # Create custom toKeyValue generator
+      # see https://man7.org/linux/man-pages/man5/login.defs.5.html for config specification
+      let
+        toKeyValue = generators.toKeyValue {
+          mkKeyValue = generators.mkKeyValueDefault { } " ";
+        };
+      in
+      {
+        # /etc/login.defs: global configuration for pwdutils.
+        # You cannot login without it!
+        "login.defs".source = pkgs.writeText "login.defs" (toKeyValue cfg.settings);
 
         # /etc/default/useradd: configuration for useradd.
-        "default/useradd".source = pkgs.writeText "useradd"
-          ''
-            GROUP=100
-            HOME=/home
-            SHELL=${utils.toShellPath config.users.defaultUserShell}
-          '';
+        "default/useradd".source = pkgs.writeText "useradd" ''
+          GROUP=100
+          HOME=/home
+          SHELL=${utils.toShellPath config.users.defaultUserShell}
+        '';
       };
 
-    security.pam.services =
-      { chsh = { rootOK = true; };
-        chfn = { rootOK = true; };
-        su = { rootOK = true; forwardXAuth = true; logFailures = true; };
-        passwd = {};
-        # Note: useradd, groupadd etc. aren't setuid root, so it
-        # doesn't really matter what the PAM config says as long as it
-        # lets root in.
-        useradd = { rootOK = true; };
-        usermod = { rootOK = true; };
-        userdel = { rootOK = true; };
-        groupadd = { rootOK = true; };
-        groupmod = { rootOK = true; };
-        groupmems = { rootOK = true; };
-        groupdel = { rootOK = true; };
-        login = { startSession = true; allowNullPassword = true; showMotd = true; updateWtmp = true; };
-        chpasswd = { rootOK = true; };
+    security.pam.services = {
+      chsh = { rootOK = true; };
+      chfn = { rootOK = true; };
+      su = {
+        rootOK = true;
+        forwardXAuth = true;
+        logFailures = true;
       };
-
-    security.wrappers = {
-      su        = mkSetuidRoot "${pkgs.shadow.su}/bin/su";
-      sg        = mkSetuidRoot "${pkgs.shadow.out}/bin/sg";
-      newgrp    = mkSetuidRoot "${pkgs.shadow.out}/bin/newgrp";
-      newuidmap = mkSetuidRoot "${pkgs.shadow.out}/bin/newuidmap";
-      newgidmap = mkSetuidRoot "${pkgs.shadow.out}/bin/newgidmap";
-    } // lib.optionalAttrs config.users.mutableUsers {
-      chsh   = mkSetuidRoot "${pkgs.shadow.out}/bin/chsh";
-      passwd = mkSetuidRoot "${pkgs.shadow.out}/bin/passwd";
+      passwd = { };
+      # Note: useradd, groupadd etc. aren't setuid root, so it
+      # doesn't really matter what the PAM config says as long as it
+      # lets root in.
+      useradd.rootOK = true;
+      usermod.rootOK = true;
+      userdel.rootOK = true;
+      groupadd.rootOK = true;
+      groupmod.rootOK = true;
+      groupmems.rootOK = true;
+      groupdel.rootOK = true;
+      login = {
+        startSession = true;
+        allowNullPassword = true;
+        showMotd = true;
+        updateWtmp = true;
+      };
+      chpasswd = { rootOK = true; };
     };
+
+    security.wrappers =
+      let
+        mkSetuidRoot = source: {
+          setuid = true;
+          owner = "root";
+          group = "root";
+          inherit source;
+        };
+      in
+      {
+        su = mkSetuidRoot "${cfg.package.su}/bin/su";
+        sg = mkSetuidRoot "${cfg.package.out}/bin/sg";
+        newgrp = mkSetuidRoot "${cfg.package.out}/bin/newgrp";
+        newuidmap = mkSetuidRoot "${cfg.package.out}/bin/newuidmap";
+        newgidmap = mkSetuidRoot "${cfg.package.out}/bin/newgidmap";
+      }
+      // optionalAttrs config.users.mutableUsers {
+        chsh = mkSetuidRoot "${cfg.package.out}/bin/chsh";
+        passwd = mkSetuidRoot "${cfg.package.out}/bin/passwd";
+      };
   };
 }
diff --git a/nixos/modules/services/continuous-integration/jenkins/job-builder.nix b/nixos/modules/services/continuous-integration/jenkins/job-builder.nix
index d6a8c2a3f7c..a8e3effd1f7 100644
--- a/nixos/modules/services/continuous-integration/jenkins/job-builder.nix
+++ b/nixos/modules/services/continuous-integration/jenkins/job-builder.nix
@@ -9,25 +9,20 @@ let
 in {
   options = {
     services.jenkins.jobBuilder = {
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc ''
-          Whether or not to enable the Jenkins Job Builder (JJB) service. It
-          allows defining jobs for Jenkins in a declarative manner.
+      enable = mkEnableOption (mdDoc ''
+        the Jenkins Job Builder (JJB) service. It
+        allows defining jobs for Jenkins in a declarative manner.
 
-          Jobs managed through the Jenkins WebUI (or by other means) are left
-          unchanged.
+        Jobs managed through the Jenkins WebUI (or by other means) are left
+        unchanged.
 
-          Note that it really is declarative configuration; if you remove a
-          previously defined job, the corresponding job directory will be
-          deleted.
+        Note that it really is declarative configuration; if you remove a
+        previously defined job, the corresponding job directory will be
+        deleted.
 
-          Please see the Jenkins Job Builder documentation for more info:
-          [
-          http://docs.openstack.org/infra/jenkins-job-builder/](http://docs.openstack.org/infra/jenkins-job-builder/)
-        '';
-      };
+        Please see the Jenkins Job Builder documentation for more info:
+        <https://jenkins-job-builder.readthedocs.io/>
+      '');
 
       accessUser = mkOption {
         default = "admin";
diff --git a/nixos/modules/services/games/mchprs.nix b/nixos/modules/services/games/mchprs.nix
new file mode 100644
index 00000000000..a65001b0b3e
--- /dev/null
+++ b/nixos/modules/services/games/mchprs.nix
@@ -0,0 +1,341 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.mchprs;
+  settingsFormat = pkgs.formats.toml { };
+
+  whitelistFile = pkgs.writeText "whitelist.json"
+    (builtins.toJSON
+      (mapAttrsToList (n: v: { name = n; uuid = v; }) cfg.whitelist.list));
+
+  configToml =
+    (removeAttrs cfg.settings [ "address" "port" ]) //
+    {
+      bind_address = cfg.settings.address + ":" + toString cfg.settings.port;
+      whitelist = cfg.whitelist.enable;
+    };
+
+  configTomlFile = settingsFormat.generate "Config.toml" configToml;
+in
+{
+  options = {
+    services.mchprs = {
+      enable = mkEnableOption "MCHPRS";
+
+      declarativeSettings = mkOption {
+        type = types.bool;
+        default = false;
+        description = mdDoc ''
+          Whether to use a declarative configuration for MCHPRS.
+        '';
+      };
+
+      declarativeWhitelist = mkOption {
+        type = types.bool;
+        default = false;
+        description = mdDoc ''
+          Whether to use a declarative whitelist.
+          The options {option}`services.mchprs.whitelist.list`
+          will be applied if and only if set to `true`.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/lib/mchprs";
+        description = mdDoc ''
+          Directory to store MCHPRS database and other state/data files.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = mdDoc ''
+          Whether to open ports in the firewall for the server.
+          Only has effect when
+          {option}`services.mchprs.declarativeSettings` is `true`.
+        '';
+      };
+
+      maxRuntime = mkOption {
+        type = types.str;
+        default = "infinity";
+        example = "7d";
+        description = mdDoc ''
+          Automatically restart the server after
+          {option}`services.mchprs.maxRuntime`.
+          The time span format is described here:
+          https://www.freedesktop.org/software/systemd/man/systemd.time.html#Parsing%20Time%20Spans.
+          If `null`, then the server is not restarted automatically.
+        '';
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.mchprs;
+        defaultText = literalExpression "pkgs.mchprs";
+        description = mdDoc "Version of MCHPRS to run.";
+      };
+
+      settings = mkOption {
+        type = types.submodule {
+          freeformType = settingsFormat.type;
+
+          options = {
+            port = mkOption {
+              type = types.port;
+              default = 25565;
+              description = mdDoc ''
+                Port for the server.
+                Only has effect when
+                {option}`services.mchprs.declarativeSettings` is `true`.
+              '';
+            };
+
+            address = mkOption {
+              type = types.str;
+              default = "0.0.0.0";
+              description = mdDoc ''
+                Address for the server.
+                Please use enclosing square brackets when using ipv6.
+                Only has effect when
+                {option}`services.mchprs.declarativeSettings` is `true`.
+              '';
+            };
+
+            motd = mkOption {
+              type = types.str;
+              default = "Minecraft High Performance Redstone Server";
+              description = mdDoc ''
+                Message of the day.
+                Only has effect when
+                {option}`services.mchprs.declarativeSettings` is `true`.
+              '';
+            };
+
+            chat_format = mkOption {
+              type = types.str;
+              default = "<{username}> {message}";
+              description = mdDoc ''
+                How to format chat message interpolating `username`
+                and `message` with curly braces.
+                Only has effect when
+                {option}`services.mchprs.declarativeSettings` is `true`.
+              '';
+            };
+
+            max_players = mkOption {
+              type = types.ints.positive;
+              default = 99999;
+              description = mdDoc ''
+                Maximum number of simultaneous players.
+                Only has effect when
+                {option}`services.mchprs.declarativeSettings` is `true`.
+              '';
+            };
+
+            view_distance = mkOption {
+              type = types.ints.positive;
+              default = 8;
+              description = mdDoc ''
+                Maximal distance (in chunks) between players and loaded chunks.
+                Only has effect when
+                {option}`services.mchprs.declarativeSettings` is `true`.
+              '';
+            };
+
+            bungeecord = mkOption {
+              type = types.bool;
+              default = false;
+              description = mdDoc ''
+                Enable compatibility with
+                [BungeeCord](https://github.com/SpigotMC/BungeeCord).
+                Only has effect when
+                {option}`services.mchprs.declarativeSettings` is `true`.
+              '';
+            };
+
+            schemati = mkOption {
+              type = types.bool;
+              default = false;
+              description = mdDoc ''
+                Mimic the verification and directory layout used by the
+                Open Redstone Engineers
+                [Schemati plugin](https://github.com/OpenRedstoneEngineers/Schemati).
+                Only has effect when
+                {option}`services.mchprs.declarativeSettings` is `true`.
+              '';
+            };
+
+            block_in_hitbox = mkOption {
+              type = types.bool;
+              default = true;
+              description = mdDoc ''
+                Allow placing blocks inside of players
+                (hitbox logic is simplified).
+                Only has effect when
+                {option}`services.mchprs.declarativeSettings` is `true`.
+              '';
+            };
+
+            auto_redpiler = mkOption {
+              type = types.bool;
+              default = true;
+              description = mdDoc ''
+                Use redpiler automatically.
+                Only has effect when
+                {option}`services.mchprs.declarativeSettings` is `true`.
+              '';
+            };
+          };
+        };
+        default = { };
+
+        description = mdDoc ''
+          Configuration for MCHPRS via `Config.toml`.
+          See https://github.com/MCHPR/MCHPRS/blob/master/README.md for documentation.
+        '';
+      };
+
+      whitelist = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = mdDoc ''
+            Whether or not the whitelist (in `whitelist.json`) shoud be enabled.
+            Only has effect when {option}`services.mchprs.declarativeSettings` is `true`.
+          '';
+        };
+
+        list = mkOption {
+          type =
+            let
+              minecraftUUID = types.strMatching
+                "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" // {
+                description = "Minecraft UUID";
+              };
+            in
+            types.attrsOf minecraftUUID;
+          default = { };
+          example = literalExpression ''
+            {
+              username1 = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
+              username2 = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy";
+            };
+          '';
+          description = mdDoc ''
+            Whitelisted players, only has an effect when
+            {option}`services.mchprs.declarativeWhitelist` is
+            `true` and the whitelist is enabled
+            via {option}`services.mchprs.whitelist.enable`.
+            This is a mapping from Minecraft usernames to UUIDs.
+            You can use <https://mcuuid.net/> to get a
+            Minecraft UUID for a username.
+          '';
+        };
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.users.mchprs = {
+      description = "MCHPRS service user";
+      home = cfg.dataDir;
+      createHome = true;
+      isSystemUser = true;
+      group = "mchprs";
+    };
+    users.groups.mchprs = { };
+
+    systemd.services.mchprs = {
+      description = "MCHPRS Service";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      serviceConfig = {
+        ExecStart = "${lib.getExe cfg.package}";
+        Restart = "always";
+        RuntimeMaxSec = cfg.maxRuntime;
+        User = "mchprs";
+        WorkingDirectory = cfg.dataDir;
+
+        StandardOutput = "journal";
+        StandardError = "journal";
+
+        # Hardening
+        CapabilityBoundingSet = [ "" ];
+        DeviceAllow = [ "" ];
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        PrivateDevices = true;
+        PrivateTmp = true;
+        PrivateUsers = true;
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectProc = "invisible";
+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        SystemCallArchitectures = "native";
+        UMask = "0077";
+      };
+
+      preStart =
+        (if cfg.declarativeSettings then ''
+          if [ -e .declarativeSettings ]; then
+
+            # Settings were declarative before, no need to back up anything
+            cp -f ${configTomlFile} Config.toml
+
+          else
+
+            # Declarative settings for the first time, backup stateful files
+            cp -b --suffix=.stateful ${configTomlFile} Config.toml
+
+            echo "Autogenerated file that implies that this server configuration is managed declaratively by NixOS" \
+              > .declarativeSettings
+
+          fi
+        '' else ''
+          if [ -e .declarativeSettings ]; then
+            rm .declarativeSettings
+          fi
+        '') + (if cfg.declarativeWhitelist then ''
+          if [ -e .declarativeWhitelist ]; then
+
+            # Whitelist was declarative before, no need to back up anything
+            ln -sf ${whitelistFile} whitelist.json
+
+          else
+
+            # Declarative whitelist for the first time, backup stateful files
+            ln -sb --suffix=.stateful ${whitelistFile} whitelist.json
+
+            echo "Autogenerated file that implies that this server's whitelist is managed declaratively by NixOS" \
+              > .declarativeWhitelist
+
+          fi
+        '' else ''
+          if [ -e .declarativeWhitelist ]; then
+            rm .declarativeWhitelist
+          fi
+        '');
+    };
+
+    networking.firewall = mkIf (cfg.declarativeSettings && cfg.openFirewall) {
+      allowedUDPPorts = [ cfg.settings.port ];
+      allowedTCPPorts = [ cfg.settings.port ];
+    };
+  };
+
+  meta.maintainers = with maintainers; [ gdd ];
+}
diff --git a/nixos/modules/services/games/minetest-server.nix b/nixos/modules/services/games/minetest-server.nix
index 578364ec542..8dc36015349 100644
--- a/nixos/modules/services/games/minetest-server.nix
+++ b/nixos/modules/services/games/minetest-server.nix
@@ -3,15 +3,52 @@
 with lib;
 
 let
+  CONTAINS_NEWLINE_RE = ".*\n.*";
+  # The following values are reserved as complete option values:
+  # { - start of a group.
+  # """ - start of a multi-line string.
+  RESERVED_VALUE_RE = "[[:space:]]*(\"\"\"|\\{)[[:space:]]*";
+  NEEDS_MULTILINE_RE = "${CONTAINS_NEWLINE_RE}|${RESERVED_VALUE_RE}";
+
+  # There is no way to encode """ on its own line in a Minetest config.
+  UNESCAPABLE_RE = ".*\n\"\"\"\n.*";
+
+  toConfMultiline = name: value:
+    assert lib.assertMsg
+      ((builtins.match UNESCAPABLE_RE value) == null)
+      ''""" can't be on its own line in a minetest config.'';
+    "${name} = \"\"\"\n${value}\n\"\"\"\n";
+
+  toConf = values:
+    lib.concatStrings
+      (lib.mapAttrsToList
+        (name: value: {
+          bool = "${name} = ${toString value}\n";
+          int = "${name} = ${toString value}\n";
+          null = "";
+          set = "${name} = {\n${toConf value}}\n";
+          string =
+            if (builtins.match NEEDS_MULTILINE_RE value) != null
+            then toConfMultiline name value
+            else "${name} = ${value}\n";
+        }.${builtins.typeOf value})
+        values);
+
   cfg   = config.services.minetest-server;
-  flag  = val: name: optionalString (val != null) "--${name} ${toString val} ";
+  flag  = val: name: lib.optionals (val != null) ["--${name}" "${toString val}"];
+
   flags = [
-    (flag cfg.gameId "gameid")
-    (flag cfg.world "world")
-    (flag cfg.configPath "config")
-    (flag cfg.logPath "logfile")
-    (flag cfg.port "port")
-  ];
+    "--server"
+  ]
+    ++ (
+      if cfg.configPath != null
+      then ["--config" cfg.configPath]
+      else ["--config" (builtins.toFile "minetest.conf" (toConf cfg.config))])
+    ++ (flag cfg.gameId "gameid")
+    ++ (flag cfg.world "world")
+    ++ (flag cfg.logPath "logfile")
+    ++ (flag cfg.port "port")
+    ++ cfg.extraArgs;
 in
 {
   options = {
@@ -55,6 +92,16 @@ in
         '';
       };
 
+      config = mkOption {
+        type = types.attrsOf types.anything;
+        default = {};
+        description = lib.mdDoc ''
+          Settings to add to the minetest config file.
+
+          This option is ignored if `configPath` is set.
+        '';
+      };
+
       logPath = mkOption {
         type        = types.nullOr types.path;
         default     = null;
@@ -75,6 +122,14 @@ in
           If set to null, the default 30000 will be used.
         '';
       };
+
+      extraArgs = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = lib.mdDoc ''
+          Additional command line flags to pass to the minetest executable.
+        '';
+      };
     };
   };
 
@@ -100,7 +155,7 @@ in
       script = ''
         cd /var/lib/minetest
 
-        exec ${pkgs.minetest}/bin/minetest --server ${concatStrings flags}
+        exec ${pkgs.minetest}/bin/minetest ${lib.escapeShellArgs flags}
       '';
     };
   };
diff --git a/nixos/modules/services/hardware/pcscd.nix b/nixos/modules/services/hardware/pcscd.nix
index a09c64645c4..a9e4998efe3 100644
--- a/nixos/modules/services/hardware/pcscd.nix
+++ b/nixos/modules/services/hardware/pcscd.nix
@@ -24,7 +24,6 @@ in
 
     plugins = mkOption {
       type = types.listOf types.package;
-      default = [ pkgs.ccid ];
       defaultText = literalExpression "[ pkgs.ccid ]";
       example = literalExpression "[ pkgs.pcsc-cyberjack ]";
       description = lib.mdDoc "Plugin packages to be used for PCSC-Lite.";
@@ -56,6 +55,8 @@ in
     environment.systemPackages = [ package ];
     systemd.packages = [ (getBin package) ];
 
+    services.pcscd.plugins = [ pkgs.ccid ];
+
     systemd.sockets.pcscd.wantedBy = [ "sockets.target" ];
 
     systemd.services.pcscd = {
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index e3451e1f6c7..56120094871 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -296,7 +296,6 @@ in
       packages = mkOption {
         type = types.listOf types.path;
         default = [];
-        visible = false;
         description = lib.mdDoc ''
           *This will only be used when systemd is used in stage 1.*
 
@@ -311,7 +310,6 @@ in
       binPackages = mkOption {
         type = types.listOf types.path;
         default = [];
-        visible = false;
         description = lib.mdDoc ''
           *This will only be used when systemd is used in stage 1.*
 
diff --git a/nixos/modules/services/misc/ankisyncd.nix b/nixos/modules/services/misc/ankisyncd.nix
index 5198b824202..7be8dc7dab8 100644
--- a/nixos/modules/services/misc/ankisyncd.nix
+++ b/nixos/modules/services/misc/ankisyncd.nix
@@ -9,22 +9,16 @@ let
 
   stateDir = "/var/lib/${name}";
 
-  authDbPath = "${stateDir}/auth.db";
+  toml = pkgs.formats.toml {};
 
-  sessionDbPath = "${stateDir}/session.db";
-
-  configFile = pkgs.writeText "ankisyncd.conf" (lib.generators.toINI {} {
-    sync_app = {
+  configFile = toml.generate "ankisyncd.conf" {
+    listen = {
       host = cfg.host;
       port = cfg.port;
-      data_root = stateDir;
-      auth_db_path = authDbPath;
-      session_db_path = sessionDbPath;
-
-      base_url = "/sync/";
-      base_media_url = "/msync/";
     };
-  });
+    paths.root_dir = stateDir;
+    # encryption.ssl_enable / cert_file / key_file
+  };
 in
   {
     options.services.ankisyncd = {
@@ -59,8 +53,6 @@ in
     config = mkIf cfg.enable {
       networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
 
-      environment.etc."ankisyncd/ankisyncd.conf".source = configFile;
-
       systemd.services.ankisyncd = {
         description = "ankisyncd - Anki sync server";
         after = [ "network.target" ];
@@ -71,7 +63,7 @@ in
           Type = "simple";
           DynamicUser = true;
           StateDirectory = name;
-          ExecStart = "${cfg.package}/bin/ankisyncd";
+          ExecStart = "${cfg.package}/bin/ankisyncd --config ${configFile}";
           Restart = "always";
         };
       };
diff --git a/nixos/modules/services/misc/calibre-server.nix b/nixos/modules/services/misc/calibre-server.nix
index 77c60381a31..e1ddae1de1f 100644
--- a/nixos/modules/services/misc/calibre-server.nix
+++ b/nixos/modules/services/misc/calibre-server.nix
@@ -6,6 +6,17 @@ let
 
   cfg = config.services.calibre-server;
 
+  documentationLink = "https://manual.calibre-ebook.com";
+  generatedDocumentationLink = documentationLink + "/generated/en/calibre-server.html";
+
+  execFlags = (concatStringsSep " "
+    (mapAttrsToList (k: v: "${k} ${toString v}") (filterAttrs (name: value: value != null) {
+      "--listen-on" = cfg.host;
+      "--port" = cfg.port;
+      "--auth-mode" = cfg.auth.mode;
+      "--userdb" = cfg.auth.userDb;
+    }) ++ [(optionalString (cfg.auth.enable == true) "--enable-auth")])
+  );
 in
 
 {
@@ -18,52 +29,100 @@ in
     )
   ];
 
-  ###### interface
-
   options = {
     services.calibre-server = {
 
       enable = mkEnableOption (lib.mdDoc "calibre-server");
+      package = lib.mkPackageOptionMD pkgs "calibre" { };
 
       libraries = mkOption {
+        type = types.listOf types.path;
+        default = [ "/var/lib/calibre-server" ];
         description = lib.mdDoc ''
+          Make sure each library path is initialized before service startup.
           The directories of the libraries to serve. They must be readable for the user under which the server runs.
+          See the [calibredb documentation](${documentationLink}/generated/en/calibredb.html#add) for details.
         '';
-        type = types.listOf types.path;
       };
 
       user = mkOption {
-        description = lib.mdDoc "The user under which calibre-server runs.";
         type = types.str;
         default = "calibre-server";
+        description = lib.mdDoc "The user under which calibre-server runs.";
       };
 
       group = mkOption {
-        description = lib.mdDoc "The group under which calibre-server runs.";
         type = types.str;
         default = "calibre-server";
+        description = lib.mdDoc "The group under which calibre-server runs.";
       };
 
-    };
-  };
+      host = mkOption {
+        type = types.str;
+        default = "0.0.0.0";
+        example = "::1";
+        description = lib.mdDoc ''
+          The interface on which to listen for connections.
+          See the [calibre-server documentation](${generatedDocumentationLink}#cmdoption-calibre-server-listen-on) for details.
+        '';
+      };
+
+      port = mkOption {
+        default = 8080;
+        type = types.port;
+        description = lib.mdDoc ''
+          The port on which to listen for connections.
+          See the [calibre-server documentation](${generatedDocumentationLink}#cmdoption-calibre-server-port) for details.
+        '';
+      };
 
+      auth = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = lib.mdDoc ''
+            Password based authentication to access the server.
+            See the [calibre-server documentation](${generatedDocumentationLink}#cmdoption-calibre-server-enable-auth) for details.
+          '';
+        };
 
-  ###### implementation
+        mode = mkOption {
+          type = types.enum [ "auto" "basic" "digest" ];
+          default = "auto";
+          description = lib.mdDoc ''
+            Choose the type of authentication used.
+            Set the HTTP authentication mode used by the server.
+            See the [calibre-server documentation](${generatedDocumentationLink}#cmdoption-calibre-server-auth-mode) for details.
+          '';
+        };
+
+        userDb = mkOption {
+          default = null;
+          type = types.nullOr types.path;
+          description = lib.mdDoc ''
+            Choose users database file to use for authentication.
+            Make sure users database file is initialized before service startup.
+            See the [calibre-server documentation](${documentationLink}/server.html#managing-user-accounts-from-the-command-line-only) for details.
+          '';
+        };
+      };
+    };
+  };
 
   config = mkIf cfg.enable {
 
     systemd.services.calibre-server = {
-        description = "Calibre Server";
-        after = [ "network.target" ];
-        wantedBy = [ "multi-user.target" ];
-        serviceConfig = {
-          User = cfg.user;
-          Restart = "always";
-          ExecStart = "${pkgs.calibre}/bin/calibre-server ${lib.concatStringsSep " " cfg.libraries}";
-        };
-
+      description = "Calibre Server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = cfg.user;
+        Restart = "always";
+        ExecStart = "${cfg.package}/bin/calibre-server ${lib.concatStringsSep " " cfg.libraries} ${execFlags}";
       };
 
+    };
+
     environment.systemPackages = [ pkgs.calibre ];
 
     users.users = optionalAttrs (cfg.user == "calibre-server") {
@@ -83,4 +142,5 @@ in
 
   };
 
+  meta.maintainers = with lib.maintainers; [ gaelreyrol ];
 }
diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix
index 5c35cfa177a..945009f0058 100644
--- a/nixos/modules/services/misc/gitea.nix
+++ b/nixos/modules/services/misc/gitea.nix
@@ -467,10 +467,8 @@ in
     systemd.tmpfiles.rules = [
       "d '${cfg.dump.backupDir}' 0750 ${cfg.user} ${cfg.group} - -"
       "z '${cfg.dump.backupDir}' 0750 ${cfg.user} ${cfg.group} - -"
-      "Z '${cfg.dump.backupDir}' - ${cfg.user} ${cfg.group} - -"
       "d '${cfg.repositoryRoot}' 0750 ${cfg.user} ${cfg.group} - -"
       "z '${cfg.repositoryRoot}' 0750 ${cfg.user} ${cfg.group} - -"
-      "Z '${cfg.repositoryRoot}' - ${cfg.user} ${cfg.group} - -"
       "d '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -"
       "d '${cfg.stateDir}/conf' 0750 ${cfg.user} ${cfg.group} - -"
       "d '${cfg.customDir}' 0750 ${cfg.user} ${cfg.group} - -"
@@ -484,7 +482,6 @@ in
       "z '${cfg.customDir}/conf' 0750 ${cfg.user} ${cfg.group} - -"
       "z '${cfg.stateDir}/data' 0750 ${cfg.user} ${cfg.group} - -"
       "z '${cfg.stateDir}/log' 0750 ${cfg.user} ${cfg.group} - -"
-      "Z '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -"
 
       # If we have a folder or symlink with gitea locales, remove it
       # And symlink the current gitea locales in place
@@ -493,13 +490,12 @@ in
     ] ++ lib.optionals cfg.lfs.enable [
       "d '${cfg.lfs.contentDir}' 0750 ${cfg.user} ${cfg.group} - -"
       "z '${cfg.lfs.contentDir}' 0750 ${cfg.user} ${cfg.group} - -"
-      "Z '${cfg.lfs.contentDir}' - ${cfg.user} ${cfg.group} - -"
     ];
 
     systemd.services.gitea = {
       description = "gitea";
       after = [ "network.target" ] ++ optional usePostgresql "postgresql.service" ++ optional useMysql "mysql.service";
-      requires = optional usePostgresql "postgresql.service" ++ optional useMysql "mysql.service";
+      requires = optional (cfg.database.createDatabase && usePostgresql) "postgresql.service" ++ optional (cfg.database.createDatabase && useMysql) "mysql.service";
       wantedBy = [ "multi-user.target" ];
       path = [ cfg.package pkgs.git pkgs.gnupg ];
 
@@ -587,7 +583,10 @@ in
         Restart = "always";
         # Runtime directory and mode
         RuntimeDirectory = "gitea";
-        RuntimeDirectoryMode = "0755";
+        RuntimeDirectoryMode = "0750";
+        # Proc filesystem
+        ProcSubset = "pid";
+        ProtectProc = "invisible";
         # Access write directories
         ReadWritePaths = [ cfg.customDir cfg.dump.backupDir cfg.repositoryRoot cfg.stateDir cfg.lfs.contentDir ];
         UMask = "0027";
@@ -607,15 +606,17 @@ in
         ProtectKernelModules = true;
         ProtectKernelLogs = true;
         ProtectControlGroups = true;
-        RestrictAddressFamilies = [ "AF_UNIX AF_INET AF_INET6" ];
+        RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
+        RestrictNamespaces = true;
         LockPersonality = true;
         MemoryDenyWriteExecute = true;
         RestrictRealtime = true;
         RestrictSUIDSGID = true;
+        RemoveIPC = true;
         PrivateMounts = true;
         # System Call Filtering
         SystemCallArchitectures = "native";
-        SystemCallFilter = "~@clock @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @reboot @setuid @swap";
+        SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid" "setrlimit" ];
       };
 
       environment = {
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 8958d375b2b..a442cb237ed 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -152,6 +152,7 @@ let
         api_url = "http://${config.services.dockerRegistry.listenAddress}:${toString config.services.dockerRegistry.port}/";
         issuer = cfg.registry.issuer;
       };
+      elasticsearch.indexer_path = "${pkgs.gitlab-elasticsearch-indexer}/bin/gitlab-elasticsearch-indexer";
       extra = {};
       uploads.storage_path = cfg.statePath;
       pages = optionalAttrs cfg.pages.enable {
@@ -1644,6 +1645,7 @@ in {
         nodejs
         procps
         gnupg
+        gzip
       ];
       serviceConfig = {
         Type = "notify";
diff --git a/nixos/modules/services/misc/gollum.nix b/nixos/modules/services/misc/gollum.nix
index 4eec9610b5e..d607e92e5ec 100644
--- a/nixos/modules/services/misc/gollum.nix
+++ b/nixos/modules/services/misc/gollum.nix
@@ -91,18 +91,30 @@ in
         The package used in the service
       '';
     };
+
+    user = mkOption {
+      type = types.str;
+      default = "gollum";
+      description = lib.mdDoc "Specifies the owner of the wiki directory";
+    };
+
+    group = mkOption {
+      type = types.str;
+      default = "gollum";
+      description = lib.mdDoc "Specifies the owner group of the wiki directory";
+    };
   };
 
   config = mkIf cfg.enable {
 
-    users.users.gollum = {
-      group = config.users.users.gollum.name;
+    users.users.gollum = mkIf (cfg.user == "gollum") {
+      group = cfg.group;
       description = "Gollum user";
       createHome = false;
       isSystemUser = true;
     };
 
-    users.groups.gollum = { };
+    users.groups."${cfg.group}" = { };
 
     systemd.tmpfiles.rules = [
       "d '${cfg.stateDir}' - ${config.users.users.gollum.name} ${config.users.groups.gollum.name} - -"
@@ -120,8 +132,8 @@ in
       '';
 
       serviceConfig = {
-        User = config.users.users.gollum.name;
-        Group = config.users.groups.gollum.name;
+        User = cfg.user;
+        Group = cfg.group;
         WorkingDirectory = cfg.stateDir;
         ExecStart = ''
           ${cfg.package}/bin/gollum \
@@ -142,5 +154,5 @@ in
     };
   };
 
-  meta.maintainers = with lib.maintainers; [ erictapen bbenno ];
+  meta.maintainers = with lib.maintainers; [ erictapen bbenno joscha ];
 }
diff --git a/nixos/modules/services/misc/n8n.nix b/nixos/modules/services/misc/n8n.nix
index cdfe9dc8482..c72ed106f2d 100644
--- a/nixos/modules/services/misc/n8n.nix
+++ b/nixos/modules/services/misc/n8n.nix
@@ -26,6 +26,15 @@ in
       '';
     };
 
+    webhookUrl = mkOption {
+      type = types.string;
+      default = "";
+      description = lib.mdDoc ''
+        WEBHOOK_URL for n8n, in case we're running behind a reverse proxy.
+        This cannot be set through configuration and must reside in an environment variable.
+      '';
+    };
+
   };
 
   config = mkIf cfg.enable {
@@ -44,6 +53,7 @@ in
         N8N_USER_FOLDER = "/var/lib/n8n";
         HOME = "/var/lib/n8n";
         N8N_CONFIG_FILES = "${configFile}";
+        WEBHOOK_URL = "${webhookUrl}";
 
         # Don't phone home
         N8N_DIAGNOSTICS_ENABLED = "false";
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 7b1282b15b3..44cf71ad401 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -656,7 +656,7 @@ in
           to view the current value. By default it is empty.
 
           Nix configurations defined under {option}`nix.*` will be translated and applied to this
-          option. In addition, configuration specified in {option}`nix.extraOptions` which will be appended
+          option. In addition, configuration specified in {option}`nix.extraOptions` will be appended
           verbatim to the resulting config file.
         '';
       };
diff --git a/nixos/modules/services/misc/nix-optimise.nix b/nixos/modules/services/misc/nix-optimise.nix
index db8148c060e..0398229a13d 100644
--- a/nixos/modules/services/misc/nix-optimise.nix
+++ b/nixos/modules/services/misc/nix-optimise.nix
@@ -1,28 +1,21 @@
 { config, lib, ... }:
 
-with lib;
-
 let
   cfg = config.nix.optimise;
 in
 
 {
-
-  ###### interface
-
   options = {
-
     nix.optimise = {
-
-      automatic = mkOption {
+      automatic = lib.mkOption {
         default = false;
-        type = types.bool;
+        type = lib.types.bool;
         description = lib.mdDoc "Automatically run the nix store optimiser at a specific time.";
       };
 
-      dates = mkOption {
+      dates = lib.mkOption {
         default = ["03:45"];
-        type = types.listOf types.str;
+        type = with lib.types; listOf str;
         description = lib.mdDoc ''
           Specification (in the format described by
           {manpage}`systemd.time(7)`) of the time at
@@ -32,9 +25,6 @@ in
     };
   };
 
-
-  ###### implementation
-
   config = {
     assertions = [
       {
@@ -43,14 +33,19 @@ in
       }
     ];
 
-    systemd.services.nix-optimise = lib.mkIf config.nix.enable
-      { description = "Nix Store Optimiser";
+    systemd = lib.mkIf config.nix.enable {
+      services.nix-optimise = {
+        description = "Nix Store Optimiser";
         # No point this if the nix daemon (and thus the nix store) is outside
         unitConfig.ConditionPathIsReadWrite = "/nix/var/nix/daemon-socket";
         serviceConfig.ExecStart = "${config.nix.package}/bin/nix-store --optimise";
-        startAt = optionals cfg.automatic cfg.dates;
+        startAt = lib.optionals cfg.automatic cfg.dates;
       };
 
+      timers.nix-optimise.timerConfig = {
+        Persistent = true;
+        RandomizedDelaySec = 1800;
+      };
+    };
   };
-
 }
diff --git a/nixos/modules/services/misc/ntfy-sh.nix b/nixos/modules/services/misc/ntfy-sh.nix
index 3258f91f704..8fc1df93afb 100644
--- a/nixos/modules/services/misc/ntfy-sh.nix
+++ b/nixos/modules/services/misc/ntfy-sh.nix
@@ -32,7 +32,25 @@ in
     };
 
     settings = mkOption {
-      type = types.submodule { freeformType = settingsFormat.type; };
+      type = types.submodule {
+        freeformType = settingsFormat.type;
+        options = {
+          base-url = mkOption {
+            type = types.str;
+            example = "https://ntfy.example";
+            description = lib.mdDoc ''
+              Public facing base URL of the service
+
+              This setting is required for any of the following features:
+              - attachments (to return a download URL)
+              - e-mail sending (for the topic URL in the email footer)
+              - iOS push notifications for self-hosted servers
+                (to calculate the Firebase poll_request topic)
+              - Matrix Push Gateway (to validate that the pushkey is correct)
+            '';
+          };
+        };
+      };
 
       default = { };
 
diff --git a/nixos/modules/services/misc/paperless.nix b/nixos/modules/services/misc/paperless.nix
index 4199e771330..8fe628a4088 100644
--- a/nixos/modules/services/misc/paperless.nix
+++ b/nixos/modules/services/misc/paperless.nix
@@ -86,12 +86,11 @@ let
     SupplementaryGroups = optional enableRedis redisServer.user;
     SystemCallArchitectures = "native";
     SystemCallFilter = [ "@system-service" "~@privileged @setuid @keyring" ];
-    # Does not work well with the temporary root
-    #UMask = "0066";
+    UMask = "0066";
   };
 in
 {
-  meta.maintainers = with maintainers; [ erikarvstedt Flakebi ];
+  meta.maintainers = with maintainers; [ erikarvstedt Flakebi leona ];
 
   imports = [
     (mkRenamedOptionModule [ "services" "paperless-ng" ] [ "services" "paperless" ])
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
index 12f89196808..571b9a3aeeb 100644
--- a/nixos/modules/services/monitoring/grafana.nix
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -1126,7 +1126,7 @@ in
                 It will notify, via the UI, when a new version is available.
                 The check itself will not prompt any auto-updates of the Grafana software, nor will it send any sensitive information.
               '';
-              default = true;
+              default = false;
               type = types.bool;
             };
 
diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix
index 501f126e1a3..397125b5123 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -56,6 +56,7 @@ let
     "nut"
     "openldap"
     "openvpn"
+    "php-fpm"
     "pihole"
     "postfix"
     "postgres"
@@ -65,6 +66,7 @@ let
     "redis"
     "rspamd"
     "rtl_433"
+    "scaphandre"
     "script"
     "shelly"
     "snmp"
@@ -301,6 +303,21 @@ in
         Please specify either 'services.prometheus.exporters.sql.configuration' or
           'services.prometheus.exporters.sql.configFile'
       '';
+    } {
+      assertion = cfg.scaphandre.enable -> (pkgs.stdenv.targetPlatform.isx86_64 == true);
+      message = ''
+        Scaphandre only support x86_64 architectures.
+      '';
+    } {
+      assertion = cfg.scaphandre.enable -> ((lib.kernel.whenHelpers pkgs.linux.version).whenOlder "5.11" true).condition == false;
+      message = ''
+        Scaphandre requires a kernel version newer than '5.11', '${pkgs.linux.version}' given.
+      '';
+    } {
+      assertion = cfg.scaphandre.enable -> (builtins.elem "intel_rapl_common" config.boot.kernelModules);
+      message = ''
+        Scaphandre needs 'intel_rapl_common' kernel module to be enabled. Please add it in 'boot.kernelModules'.
+      '';
     } ] ++ (flip map (attrNames exporterOpts) (exporter: {
       assertion = cfg.${exporter}.firewallFilter != null -> cfg.${exporter}.openFirewall;
       message = ''
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/php-fpm.nix b/nixos/modules/services/monitoring/prometheus/exporters/php-fpm.nix
new file mode 100644
index 00000000000..8f6942002f7
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/exporters/php-fpm.nix
@@ -0,0 +1,65 @@
+{ config
+, lib
+, pkgs
+, options
+}:
+
+let
+  logPrefix = "services.prometheus.exporter.php-fpm";
+  cfg = config.services.prometheus.exporters.php-fpm;
+in {
+  port = 9253;
+  extraOpts = {
+    package = lib.mkPackageOptionMD pkgs "prometheus-php-fpm-exporter" {};
+
+    telemetryPath = lib.mkOption {
+      type = lib.types.str;
+      default = "/metrics";
+      description = lib.mdDoc ''
+        Path under which to expose metrics.
+      '';
+    };
+
+    environmentFile = lib.mkOption {
+      type = lib.types.nullOr lib.types.path;
+      default = null;
+      example = "/root/prometheus-php-fpm-exporter.env";
+      description = lib.mdDoc ''
+        Environment file as defined in {manpage}`systemd.exec(5)`.
+
+        Secrets may be passed to the service without adding them to the
+        world-readable Nix store, by specifying placeholder variables as
+        the option value in Nix and setting these variables accordingly in the
+        environment file.
+
+        Environment variables from this file will be interpolated into the
+        config file using envsubst with this syntax:
+        `$ENVIRONMENT ''${VARIABLE}`
+
+        For variables to use see [options and defaults](https://github.com/hipages/php-fpm_exporter#options-and-defaults).
+
+        The main use is to set the PHP_FPM_SCRAPE_URI that indicate how to connect to PHP-FPM process.
+
+        ```
+          # Content of the environment file
+          PHP_FPM_SCRAPE_URI="unix:///tmp/php.sock;/status"
+        ```
+
+        Note that this file needs to be available on the host on which
+        this exporter is running.
+      '';
+    };
+  };
+
+  serviceOpts = {
+    serviceConfig = {
+      EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [ cfg.environmentFile ];
+      ExecStart = ''
+        ${lib.getExe cfg.package} server \
+          --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+          --web.telemetry-path ${cfg.telemetryPath} \
+          ${lib.concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/scaphandre.nix b/nixos/modules/services/monitoring/prometheus/exporters/scaphandre.nix
new file mode 100644
index 00000000000..3b6ebf65b09
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/exporters/scaphandre.nix
@@ -0,0 +1,33 @@
+{ config
+, lib
+, pkgs
+, options
+}:
+
+let
+  logPrefix = "services.prometheus.exporter.scaphandre";
+  cfg = config.services.prometheus.exporters.scaphandre;
+in {
+  port = 8080;
+  extraOpts = {
+    telemetryPath = lib.mkOption {
+      type = lib.types.str;
+      default = "/metrics";
+      description = lib.mdDoc ''
+        Path under which to expose metrics.
+      '';
+    };
+  };
+
+  serviceOpts = {
+    serviceConfig = {
+      ExecStart = ''
+        ${pkgs.scaphandre}/bin/scaphandre prometheus \
+          --address ${cfg.listenAddress} \
+          --port ${toString cfg.port} \
+          --suffix ${cfg.telemetryPath} \
+          ${lib.concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/pdns-recursor.nix b/nixos/modules/services/networking/pdns-recursor.nix
index 2f07cefc736..f929532ba09 100644
--- a/nixos/modules/services/networking/pdns-recursor.nix
+++ b/nixos/modules/services/networking/pdns-recursor.nix
@@ -159,6 +159,8 @@ in {
 
   config = mkIf cfg.enable {
 
+    environment.etc."pdns-recursor".source = configDir;
+
     services.pdns-recursor.settings = mkDefaultAttrs {
       local-address = cfg.dns.address;
       local-port    = cfg.dns.port;
diff --git a/nixos/modules/services/networking/powerdns.nix b/nixos/modules/services/networking/powerdns.nix
index 850a128cf1a..03bf93301d8 100644
--- a/nixos/modules/services/networking/powerdns.nix
+++ b/nixos/modules/services/networking/powerdns.nix
@@ -38,6 +38,8 @@ in {
 
   config = mkIf cfg.enable {
 
+    environment.etc.pdns.source = finalConfigDir;
+
     systemd.packages = [ pkgs.pdns ];
 
     systemd.services.pdns = {
diff --git a/nixos/modules/services/networking/searx.nix b/nixos/modules/services/networking/searx.nix
index 6c57ddbde2d..40648c72481 100644
--- a/nixos/modules/services/networking/searx.nix
+++ b/nixos/modules/services/networking/searx.nix
@@ -10,6 +10,8 @@ let
   settingsFile = pkgs.writeText "settings.yml"
     (builtins.toJSON cfg.settings);
 
+  limiterSettingsFile = (pkgs.formats.toml { }).generate "limiter.toml" cfg.limiterSettings;
+
   generateConfig = ''
     cd ${runDir}
 
@@ -65,6 +67,15 @@ in
         '';
       };
 
+      redisCreateLocally = mkOption {
+        type = types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Configure a local Redis server for SearXNG. This is required if you
+          want to enable the rate limiter and bot protection of SearXNG.
+        '';
+      };
+
       settings = mkOption {
         type = types.attrsOf settingType;
         default = { };
@@ -111,6 +122,31 @@ in
         '';
       };
 
+      limiterSettings = mkOption {
+        type = types.attrsOf settingType;
+        default = { };
+        example = literalExpression ''
+          {
+            real_ip = {
+              x_for = 1;
+              ipv4_prefix = 32;
+              ipv6_prefix = 56;
+            }
+            botdetection.ip_lists.block_ip = [
+              # "93.184.216.34" # example.org
+            ];
+          }
+        '';
+        description = lib.mdDoc ''
+          Limiter settings for SearXNG.
+
+          ::: {.note}
+          For available settings, see the SearXNG
+          [schema file](https://github.com/searxng/searxng/blob/master/searx/botdetection/limiter.toml).
+          :::
+        '';
+      };
+
       package = mkOption {
         type = types.package;
         default = pkgs.searx;
@@ -158,6 +194,17 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
+    assertions = [
+      {
+        assertion = (cfg.limiterSettings != { }) -> cfg.package.pname == "searxng";
+        message = "services.searx.limiterSettings requires services.searx.package to be searxng.";
+      }
+      {
+        assertion = cfg.redisCreateLocally -> cfg.package.pname == "searxng";
+        message = "services.searx.redisCreateLocally requires services.searx.package to be searxng.";
+      }
+    ];
+
     environment.systemPackages = [ cfg.package ];
 
     users.users.searx =
@@ -206,6 +253,7 @@ in
     services.searx.settings = {
       # merge NixOS settings with defaults settings.yml
       use_default_settings = mkDefault true;
+      redis.url = lib.mkIf cfg.redisCreateLocally "unix://${config.services.redis.servers.searx.unixSocket}";
     };
 
     services.uwsgi = mkIf (cfg.runInUwsgi) {
@@ -231,7 +279,16 @@ in
       } // cfg.uwsgiConfig;
     };
 
+    services.redis.servers.searx = lib.mkIf cfg.redisCreateLocally {
+      enable = true;
+      user = "searx";
+      port = 0;
+    };
+
+    environment.etc."searxng/limiter.toml" = lib.mkIf (cfg.limiterSettings != { }) {
+      source = limiterSettingsFile;
+    };
   };
 
-  meta.maintainers = with maintainers; [ rnhmjoj ];
+  meta.maintainers = with maintainers; [ rnhmjoj _999eagle ];
 }
diff --git a/nixos/modules/services/networking/sing-box.nix b/nixos/modules/services/networking/sing-box.nix
index d32725f7714..a884bcd271e 100644
--- a/nixos/modules/services/networking/sing-box.nix
+++ b/nixos/modules/services/networking/sing-box.nix
@@ -56,6 +56,7 @@ in
 
     systemd.services.sing-box = {
       preStart = ''
+        umask 0077
         mkdir -p /etc/sing-box
         ${utils.genJqSecretsReplacementSnippet cfg.settings "/etc/sing-box/config.json"}
       '';
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index fb9774bafde..e75239e059d 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -279,10 +279,12 @@ in
       settings = mkOption {
         description = lib.mdDoc "Configuration for `sshd_config(5)`.";
         default = { };
-        example = literalExpression ''{
-          UseDns = true;
-          PasswordAuthentication = false;
-        }'';
+        example = literalExpression ''
+          {
+            UseDns = true;
+            PasswordAuthentication = false;
+          }
+        '';
         type = types.submodule ({name, ...}: {
           freeformType = settingsFormat.type;
           options = {
diff --git a/nixos/modules/services/networking/thelounge.nix b/nixos/modules/services/networking/thelounge.nix
index 2c4c32bc7cf..321e46fb5d4 100644
--- a/nixos/modules/services/networking/thelounge.nix
+++ b/nixos/modules/services/networking/thelounge.nix
@@ -48,14 +48,16 @@ in
     extraConfig = mkOption {
       default = { };
       type = types.attrs;
-      example = literalExpression ''{
-        reverseProxy = true;
-        defaults = {
-          name = "Your Network";
-          host = "localhost";
-          port = 6697;
-        };
-      }'';
+      example = literalExpression ''
+        {
+          reverseProxy = true;
+          defaults = {
+            name = "Your Network";
+            host = "localhost";
+            port = 6697;
+          };
+        }
+      '';
       description = lib.mdDoc ''
         The Lounge's {file}`config.js` contents as attribute set (will be
         converted to JSON to generate the configuration file).
diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix
index eebf2a2f7b5..9393fa75128 100644
--- a/nixos/modules/services/security/fail2ban.nix
+++ b/nixos/modules/services/security/fail2ban.nix
@@ -3,23 +3,44 @@
 with lib;
 
 let
-
   cfg = config.services.fail2ban;
 
-  fail2banConf = pkgs.writeText "fail2ban.local" cfg.daemonConfig;
+  settingsFormat = pkgs.formats.keyValue { };
 
-  jailConf = pkgs.writeText "jail.local" ''
-    [INCLUDES]
+  configFormat = pkgs.formats.ini {
+    mkKeyValue = generators.mkKeyValueDefault { } " = ";
+  };
 
-    before = paths-nixos.conf
+  mkJailConfig = name: attrs:
+    optionalAttrs (name != "DEFAULT") { inherit (attrs) enabled; } //
+    optionalAttrs (attrs.filter != null) { filter = if (builtins.isString filter) then filter else name; } //
+    attrs.settings;
 
-    ${concatStringsSep "\n" (attrValues (flip mapAttrs cfg.jails (name: def:
-      optionalString (def != "")
-        ''
-          [${name}]
-          ${def}
-        '')))}
-  '';
+  mkFilter = name: attrs: nameValuePair "fail2ban/filter.d/${name}.conf" {
+    source = configFormat.generate "filter.d/${name}.conf" attrs.filter;
+  };
+
+  fail2banConf = configFormat.generate "fail2ban.local" cfg.daemonSettings;
+
+  strJails = filterAttrs (_: builtins.isString) cfg.jails;
+  attrsJails = filterAttrs (_: builtins.isAttrs) cfg.jails;
+
+  jailConf =
+    let
+      configFile = configFormat.generate "jail.local" (
+        { INCLUDES.before = "paths-nixos.conf"; } // (mapAttrs mkJailConfig attrsJails)
+      );
+      extraConfig = concatStringsSep "\n" (attrValues (mapAttrs
+        (name: def:
+          optionalString (def != "")
+            ''
+              [${name}]
+              ${def}
+            '')
+        strJails));
+
+    in
+    pkgs.concatText "jail.local" [ configFile (pkgs.writeText "extra-jail.local" extraConfig) ];
 
   pathsConf = pkgs.writeText "paths-nixos.conf" ''
     # NixOS
@@ -32,15 +53,18 @@ let
 
     [DEFAULT]
   '';
-
 in
 
 {
 
+  imports = [
+    (mkRemovedOptionModule [ "services" "fail2ban" "daemonConfig" ] "The daemon is now configured through the attribute set `services.fail2ban.daemonSettings`.")
+    (mkRemovedOptionModule [ "services" "fail2ban" "extraSettings" ] "The extra default configuration can now be set using `services.fail2ban.jails.DEFAULT.settings`.")
+  ];
+
   ###### interface
 
   options = {
-
     services.fail2ban = {
       enable = mkOption {
         default = false;
@@ -69,7 +93,7 @@ in
       };
 
       extraPackages = mkOption {
-        default = [];
+        default = [ ];
         type = types.listOf types.package;
         example = lib.literalExpression "[ pkgs.ipset ]";
         description = lib.mdDoc ''
@@ -180,7 +204,7 @@ in
         example = true;
         description = lib.mdDoc ''
           "bantime.overalljails" (if true) specifies the search of IP in the database will be executed
-          cross over all jails, if false (default), only current jail of the ban IP will be searched
+          cross over all jails, if false (default), only current jail of the ban IP will be searched.
         '';
       };
 
@@ -194,60 +218,75 @@ in
         '';
       };
 
-      daemonConfig = mkOption {
-        default = ''
-          [Definition]
-          logtarget = SYSLOG
-          socket    = /run/fail2ban/fail2ban.sock
-          pidfile   = /run/fail2ban/fail2ban.pid
-          dbfile    = /var/lib/fail2ban/fail2ban.sqlite3
-        '';
-        type = types.lines;
-        description = lib.mdDoc ''
-          The contents of Fail2ban's main configuration file.  It's
-          generally not necessary to change it.
-       '';
-      };
+      daemonSettings = mkOption {
+        inherit (configFormat) type;
 
-      extraSettings = mkOption {
-        type = with types; attrsOf (oneOf [ bool ints.positive str ]);
-        default = {};
-        description = lib.mdDoc ''
-          Extra default configuration for all jails (i.e. `[DEFAULT]`). See
-          <https://github.com/fail2ban/fail2ban/blob/master/config/jail.conf> for an overview.
-        '';
-        example = literalExpression ''
+        defaultText = literalExpression ''
           {
-            findtime = "15m";
+            Definition = {
+              logtarget = "SYSLOG";
+              socket = "/run/fail2ban/fail2ban.sock";
+              pidfile = "/run/fail2ban/fail2ban.pid";
+              dbfile = "/var/lib/fail2ban/fail2ban.sqlite3";
+            };
           }
         '';
+        description = lib.mdDoc ''
+          The contents of Fail2ban's main configuration file.
+          It's generally not necessary to change it.
+        '';
       };
 
       jails = mkOption {
         default = { };
         example = literalExpression ''
-          { apache-nohome-iptables = '''
-              # Block an IP address if it accesses a non-existent
-              # home directory more than 5 times in 10 minutes,
-              # since that indicates that it's scanning.
-              filter   = apache-nohome
-              action   = iptables-multiport[name=HTTP, port="http,https"]
-              logpath  = /var/log/httpd/error_log*
-              backend = auto
-              findtime = 600
-              bantime  = 600
-              maxretry = 5
-            ''';
-           dovecot = '''
-             # block IPs which failed to log-in
-             # aggressive mode add blocking for aborted connections
-             enabled = true
-             filter = dovecot[mode=aggressive]
-             maxretry = 3
-           ''';
-          }
+          {
+            apache-nohome-iptables = {
+              settings = {
+                # Block an IP address if it accesses a non-existent
+                # home directory more than 5 times in 10 minutes,
+                # since that indicates that it's scanning.
+                filter = "apache-nohome";
+                action = '''iptables-multiport[name=HTTP, port="http,https"]''';
+                logpath = "/var/log/httpd/error_log*";
+                backend = "auto";
+                findtime = 600;
+                bantime = 600;
+                maxretry = 5;
+              };
+            };
+            dovecot = {
+              settings = {
+                # block IPs which failed to log-in
+                # aggressive mode add blocking for aborted connections
+                filter = "dovecot[mode=aggressive]";
+                maxretry = 3;
+              };
+            };
+          };
         '';
-        type = types.attrsOf types.lines;
+        type = with types; attrsOf (either lines (submodule ({ name, ... }: {
+          options = {
+            enabled = mkEnableOption "this jail." // {
+              default = true;
+              readOnly = name == "DEFAULT";
+            };
+
+            filter = mkOption {
+              type = nullOr (either str configFormat.type);
+
+              default = null;
+              description = lib.mdDoc "Content of the filter used for this jail.";
+            };
+
+            settings = mkOption {
+              inherit (settingsFormat) type;
+
+              default = { };
+              description = lib.mdDoc "Additional settings for this jail.";
+            };
+          };
+        })));
         description = lib.mdDoc ''
           The configuration of each Fail2ban “jail”.  A jail
           consists of an action (such as blocking a port using
@@ -278,7 +317,7 @@ in
   config = mkIf cfg.enable {
     assertions = [
       {
-        assertion = (cfg.bantime-increment.formula == null || cfg.bantime-increment.multipliers == null);
+        assertion = cfg.bantime-increment.formula == null || cfg.bantime-increment.multipliers == null;
         message = ''
           Options `services.fail2ban.bantime-increment.formula` and `services.fail2ban.bantime-increment.multipliers` cannot be both specified.
         '';
@@ -300,7 +339,7 @@ in
       "fail2ban/paths-nixos.conf".source = pathsConf;
       "fail2ban/action.d".source = "${cfg.package}/etc/fail2ban/action.d/*.conf";
       "fail2ban/filter.d".source = "${cfg.package}/etc/fail2ban/filter.d/*.conf";
-    };
+    } // (mapAttrs' mkFilter (filterAttrs (_: v: v.filter != null && !builtins.isString v.filter) attrsJails));
 
     systemd.packages = [ cfg.package ];
     systemd.services.fail2ban = {
@@ -335,39 +374,41 @@ in
       };
     };
 
+    # Defaults for the daemon settings
+    services.fail2ban.daemonSettings.Definition = {
+      logtarget = mkDefault "SYSLOG";
+      socket = mkDefault "/run/fail2ban/fail2ban.sock";
+      pidfile = mkDefault "/run/fail2ban/fail2ban.pid";
+      dbfile = mkDefault "/var/lib/fail2ban/fail2ban.sqlite3";
+    };
+
     # Add some reasonable default jails.  The special "DEFAULT" jail
     # sets default values for all other jails.
-    services.fail2ban.jails.DEFAULT = ''
-      # Bantime increment options
-      bantime.increment = ${boolToString cfg.bantime-increment.enable}
-      ${optionalString (cfg.bantime-increment.rndtime != null) "bantime.rndtime = ${cfg.bantime-increment.rndtime}"}
-      ${optionalString (cfg.bantime-increment.maxtime != null) "bantime.maxtime = ${cfg.bantime-increment.maxtime}"}
-      ${optionalString (cfg.bantime-increment.factor != null) "bantime.factor = ${cfg.bantime-increment.factor}"}
-      ${optionalString (cfg.bantime-increment.formula != null) "bantime.formula = ${cfg.bantime-increment.formula}"}
-      ${optionalString (cfg.bantime-increment.multipliers != null) "bantime.multipliers = ${cfg.bantime-increment.multipliers}"}
-      ${optionalString (cfg.bantime-increment.overalljails != null) "bantime.overalljails = ${boolToString cfg.bantime-increment.overalljails}"}
-      # Miscellaneous options
-      ignoreip    = 127.0.0.1/8 ${optionalString config.networking.enableIPv6 "::1"} ${concatStringsSep " " cfg.ignoreIP}
-      ${optionalString (cfg.bantime != null) ''
-        bantime     = ${cfg.bantime}
-      ''}
-      maxretry    = ${toString cfg.maxretry}
-      backend     = systemd
-      # Actions
-      banaction   = ${cfg.banaction}
-      banaction_allports = ${cfg.banaction-allports}
-      ${optionalString (cfg.extraSettings != {}) ''
-        # Extra settings
-        ${generators.toKeyValue {} cfg.extraSettings}
-      ''}
-    '';
-    # Block SSH if there are too many failing connection attempts.
+    services.fail2ban.jails = mkMerge [
+      {
+        DEFAULT.settings = (optionalAttrs cfg.bantime-increment.enable
+          ({ "bantime.increment" = cfg.bantime-increment.enable; } // (mapAttrs'
+            (name: nameValuePair "bantime.${name}")
+            (filterAttrs (n: v: v != null && n != "enable") cfg.bantime-increment))
+          )
+        ) // {
+          # Miscellaneous options
+          inherit (cfg) banaction maxretry;
+          ignoreip = ''127.0.0.1/8 ${optionalString config.networking.enableIPv6 "::1"} ${concatStringsSep " " cfg.ignoreIP}'';
+          backend = "systemd";
+          # Actions
+          banaction_allports = cfg.banaction-allports;
+        };
+      }
+
+      # Block SSH if there are too many failing connection attempts.
+      (mkIf config.services.openssh.enable {
+        sshd.settings.port = mkDefault (concatMapStringsSep "," builtins.toString config.services.openssh.ports);
+      })
+    ];
+
     # Benefits from verbose sshd logging to observe failed login attempts,
     # so we set that here unless the user overrode it.
-    services.openssh.settings.LogLevel = lib.mkDefault "VERBOSE";
-    services.fail2ban.jails.sshd = mkDefault ''
-      enabled = true
-      port    = ${concatMapStringsSep "," (p: toString p) config.services.openssh.ports}
-    '';
+    services.openssh.settings.LogLevel = mkDefault "VERBOSE";
   };
 }
diff --git a/nixos/modules/services/security/usbguard.nix b/nixos/modules/services/security/usbguard.nix
index 1d846b19407..651f5255ac8 100644
--- a/nixos/modules/services/security/usbguard.nix
+++ b/nixos/modules/services/security/usbguard.nix
@@ -150,6 +150,8 @@ in
           Generate device specific rules including the "via-port" attribute.
         '';
       };
+
+      dbus.enable = mkEnableOption (lib.mdDoc "USBGuard dbus daemon");
     };
   };
 
@@ -160,49 +162,90 @@ in
 
     environment.systemPackages = [ cfg.package ];
 
-    systemd.services.usbguard = {
-      description = "USBGuard daemon";
-
-      wantedBy = [ "basic.target" ];
-      wants = [ "systemd-udevd.service" ];
-
-      # make sure an empty rule file exists
-      preStart = ''[ -f "${ruleFile}" ] || touch ${ruleFile}'';
-
-      serviceConfig = {
-        Type = "simple";
-        ExecStart = "${cfg.package}/bin/usbguard-daemon -P -k -c ${daemonConfFile}";
-        Restart = "on-failure";
-
-        StateDirectory = [
-          "usbguard"
-          "usbguard/IPCAccessControl.d"
-        ];
-
-        AmbientCapabilities = "";
-        CapabilityBoundingSet = "CAP_CHOWN CAP_FOWNER";
-        DeviceAllow = "/dev/null rw";
-        DevicePolicy = "strict";
-        IPAddressDeny = "any";
-        LockPersonality = true;
-        MemoryDenyWriteExecute = true;
-        NoNewPrivileges = true;
-        PrivateDevices = true;
-        PrivateTmp = true;
-        ProtectControlGroups = true;
-        ProtectHome = true;
-        ProtectKernelModules = true;
-        ProtectSystem = true;
-        ReadOnlyPaths = "-/";
-        ReadWritePaths = "-/dev/shm -/tmp";
-        RestrictAddressFamilies = [ "AF_UNIX" "AF_NETLINK" ];
-        RestrictNamespaces = true;
-        RestrictRealtime = true;
-        SystemCallArchitectures = "native";
-        SystemCallFilter = "@system-service";
-        UMask = "0077";
+    systemd.services = {
+      usbguard = {
+        description = "USBGuard daemon";
+
+        wantedBy = [ "basic.target" ];
+        wants = [ "systemd-udevd.service" ];
+
+        # make sure an empty rule file exists
+        preStart = ''[ -f "${ruleFile}" ] || touch ${ruleFile}'';
+
+        serviceConfig = {
+          Type = "simple";
+          ExecStart = "${cfg.package}/bin/usbguard-daemon -P -k -c ${daemonConfFile}";
+          Restart = "on-failure";
+
+          StateDirectory = [
+            "usbguard"
+            "usbguard/IPCAccessControl.d"
+          ];
+
+          AmbientCapabilities = "";
+          CapabilityBoundingSet = "CAP_CHOWN CAP_FOWNER";
+          DeviceAllow = "/dev/null rw";
+          DevicePolicy = "strict";
+          IPAddressDeny = "any";
+          LockPersonality = true;
+          MemoryDenyWriteExecute = true;
+          NoNewPrivileges = true;
+          PrivateDevices = true;
+          PrivateTmp = true;
+          ProtectControlGroups = true;
+          ProtectHome = true;
+          ProtectKernelModules = true;
+          ProtectSystem = true;
+          ReadOnlyPaths = "-/";
+          ReadWritePaths = "-/dev/shm -/tmp";
+          RestrictAddressFamilies = [ "AF_UNIX" "AF_NETLINK" ];
+          RestrictNamespaces = true;
+          RestrictRealtime = true;
+          SystemCallArchitectures = "native";
+          SystemCallFilter = "@system-service";
+          UMask = "0077";
+        };
+      };
+
+      usbguard-dbus = mkIf cfg.dbus.enable {
+        description = "USBGuard D-Bus Service";
+
+        wantedBy = [ "multi-user.target" ];
+        requires = [ "usbguard.service" ];
+
+        serviceConfig = {
+          Type = "dbus";
+          BusName = "org.usbguard1";
+          ExecStart = "${cfg.package}/bin/usbguard-dbus --system";
+          Restart = "on-failure";
+        };
+
+        aliases = [ "dbus-org.usbguard.service" ];
       };
     };
+
+    security.polkit.extraConfig =
+      let
+        groupCheck = (lib.concatStrings (map
+          (g: "subject.isInGroup(\"${g}\") || ")
+          cfg.IPCAllowedGroups))
+        + "false";
+      in
+      optionalString cfg.dbus.enable ''
+        polkit.addRule(function(action, subject) {
+            if ((action.id == "org.usbguard.Policy1.listRules" ||
+                 action.id == "org.usbguard.Policy1.appendRule" ||
+                 action.id == "org.usbguard.Policy1.removeRule" ||
+                 action.id == "org.usbguard.Devices1.applyDevicePolicy" ||
+                 action.id == "org.usbguard.Devices1.listDevices" ||
+                 action.id == "org.usbguard1.getParameter" ||
+                 action.id == "org.usbguard1.setParameter") &&
+                subject.active == true && subject.local == true &&
+                (${groupCheck})) {
+                    return polkit.Result.YES;
+            }
+        });
+      '';
   };
   imports = [
     (mkRemovedOptionModule [ "services" "usbguard" "ruleFile" ] "The usbguard module now uses ${defaultRuleFile} as ruleFile. Alternatively, use services.usbguard.rules to configure rules.")
diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix
index aaa3f5507f7..98ab8595bdd 100644
--- a/nixos/modules/services/security/vaultwarden/default.nix
+++ b/nixos/modules/services/security/vaultwarden/default.nix
@@ -59,7 +59,12 @@ in {
 
     config = mkOption {
       type = attrsOf (nullOr (oneOf [ bool int str ]));
-      default = {};
+      default = {
+        config = {
+          ROCKET_ADDRESS = "::1"; # default to localhost
+          ROCKET_PORT = 8222;
+        };
+      };
       example = literalExpression ''
         {
           DOMAIN = "https://bitwarden.example.com";
diff --git a/nixos/modules/services/system/cloud-init.nix b/nixos/modules/services/system/cloud-init.nix
index 4cda06ed424..d782bb1a366 100644
--- a/nixos/modules/services/system/cloud-init.nix
+++ b/nixos/modules/services/system/cloud-init.nix
@@ -15,6 +15,7 @@ let
   ]
   ++ optional cfg.btrfs.enable btrfs-progs
   ++ optional cfg.ext4.enable e2fsprogs
+  ++ optional cfg.xfs.enable xfsprogs
   ;
   settingsFormat = pkgs.formats.yaml { };
   cfgfile = settingsFormat.generate "cloud.cfg" cfg.settings;
@@ -57,6 +58,14 @@ in
         '';
       };
 
+      xfs.enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = mdDoc ''
+          Allow the cloud-init service to operate `xfs` filesystem.
+        '';
+      };
+
       network.enable = mkOption {
         type = types.bool;
         default = false;
diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix
index 9d8a62ec78c..8d5b25e6176 100644
--- a/nixos/modules/services/system/dbus.nix
+++ b/nixos/modules/services/system/dbus.nix
@@ -22,7 +22,7 @@ in
   options = {
 
     boot.initrd.systemd.dbus = {
-      enable = mkEnableOption (lib.mdDoc "dbus in stage 1") // { visible = false; };
+      enable = mkEnableOption (lib.mdDoc "dbus in stage 1");
     };
 
     services.dbus = {
diff --git a/nixos/modules/services/web-apps/anuko-time-tracker.nix b/nixos/modules/services/web-apps/anuko-time-tracker.nix
index c50a0328e34..f43cbc40ec7 100644
--- a/nixos/modules/services/web-apps/anuko-time-tracker.nix
+++ b/nixos/modules/services/web-apps/anuko-time-tracker.nix
@@ -42,13 +42,15 @@ let
       mkdir -p $out
       cp -r * $out/
 
+      # Link config file
       ln -s ${configFile} $out/WEB-INF/config.php
 
       # Link writable templates_c directory
       rm -rf $out/WEB-INF/templates_c
       ln -s ${cfg.dataDir}/templates_c $out/WEB-INF/templates_c
 
-      # ln -fs ${cfg.dataDir}/templates_c $out/WEB-INF/templates_c
+      # Remove unsafe dbinstall.php
+      rm -f $out/dbinstall.php
     '';
   };
 in
@@ -105,6 +107,41 @@ in
       '';
     };
 
+    hostname = lib.mkOption {
+      type = lib.types.str;
+      default =
+        if config.networking.domain != null
+        then config.networking.fqdn
+        else config.networking.hostName;
+      defaultText = lib.literalExpression "config.networking.fqdn";
+      example = "anuko.example.com";
+      description = lib.mdDoc ''
+        The hostname to serve Anuko Time Tracker on.
+      '';
+    };
+
+    nginx = lib.mkOption {
+      type = lib.types.submodule (
+        lib.recursiveUpdate
+          (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) {}
+      );
+      default = {};
+      example = lib.literalExpression ''
+        {
+          serverAliases = [
+            "anuko.''${config.networking.domain}"
+          ];
+
+          # To enable encryption and let let's encrypt take care of certificate
+          forceSSL = true;
+          enableACME = true;
+        }
+      '';
+      description = lib.mdDoc ''
+        With this option, you can customize the Nginx virtualHost settings.
+      '';
+    };
+
     dataDir = lib.mkOption {
       type = lib.types.str;
       default = "/var/lib/anuko-time-tracker";
@@ -118,15 +155,6 @@ in
       description = lib.mdDoc "User under which Anuko Time Tracker runs.";
     };
 
-    virtualHost = lib.mkOption {
-      type = lib.types.nullOr lib.types.str;
-      default = "localhost";
-      description = lib.mdDoc ''
-        Name of the nginx virtualhost to use and setup. If null, do not setup
-        any virtualhost.
-      '';
-    };
-
     settings = {
       multiorgMode = lib.mkOption {
         type = lib.types.bool;
@@ -286,20 +314,26 @@ in
       };
     };
 
-    services.nginx = lib.mkIf (cfg.virtualHost != null) {
-      enable = true;
-      virtualHosts = {
-        "${cfg.virtualHost}" = {
+    services.nginx = {
+      enable = lib.mkDefault true;
+      recommendedTlsSettings = true;
+      recommendedOptimisation = true;
+      recommendedGzipSettings = true;
+      virtualHosts."${cfg.hostname}" = lib.mkMerge [
+        cfg.nginx
+        {
           root = lib.mkForce "${package}";
-          locations."/".index = "index.php";
-          locations."~ [^/]\\.php(/|$)" = {
-            extraConfig = ''
-              fastcgi_split_path_info ^(.+?\.php)(/.*)$;
-              fastcgi_pass unix:${config.services.phpfpm.pools.anuko-time-tracker.socket};
-            '';
+          locations = {
+            "/".index = "index.php";
+            "~ [^/]\\.php(/|$)" = {
+              extraConfig = ''
+                fastcgi_split_path_info ^(.+?\.php)(/.*)$;
+                fastcgi_pass unix:${config.services.phpfpm.pools.anuko-time-tracker.socket};
+              '';
+            };
           };
-        };
-      };
+        }
+      ];
     };
 
     services.mysql = lib.mkIf cfg.database.createLocally {
diff --git a/nixos/modules/services/web-apps/lemmy.nix b/nixos/modules/services/web-apps/lemmy.nix
index dd335302fa4..afbd7497610 100644
--- a/nixos/modules/services/web-apps/lemmy.nix
+++ b/nixos/modules/services/web-apps/lemmy.nix
@@ -77,6 +77,11 @@ in
       };
     };
 
+    secretFile = mkOption {
+      type = with types; nullOr path;
+      default = null;
+      description = lib.mdDoc "Path to a secret JSON configuration file which is merged at runtime with the one generated from {option}`services.lemmy.settings`.";
+    };
   };
 
   config =
@@ -197,11 +202,14 @@ in
         }
       ];
 
-      systemd.services.lemmy = {
+      systemd.services.lemmy = let
+        configFile = settingsFormat.generate "config.hjson" cfg.settings;
+        mergedConfig = "/run/lemmy/config.hjson";
+      in {
         description = "Lemmy server";
 
         environment = {
-          LEMMY_CONFIG_LOCATION = "${settingsFormat.generate "config.hjson" cfg.settings}";
+          LEMMY_CONFIG_LOCATION = if cfg.secretFile == null then configFile else mergedConfig;
           LEMMY_DATABASE_URL = if cfg.database.uri != null then cfg.database.uri else (mkIf (cfg.database.createLocally) "postgres:///lemmy?host=/run/postgresql&user=lemmy");
         };
 
@@ -216,10 +224,24 @@ in
 
         requires = lib.optionals cfg.database.createLocally [ "postgresql.service" ];
 
+        path = mkIf (cfg.secretFile != null) [ pkgs.jq ];
+
+        # merge the two configs and prevent others from reading the result
+        # if somehow $CREDENTIALS_DIRECTORY is not set we fail
+        preStart = mkIf (cfg.secretFile != null) ''
+          set -u
+          umask 177
+          jq --slurp '.[0] * .[1]' ${lib.escapeShellArg configFile} "$CREDENTIALS_DIRECTORY/secretFile" > ${lib.escapeShellArg mergedConfig}
+        '';
+
         serviceConfig = {
           DynamicUser = true;
           RuntimeDirectory = "lemmy";
           ExecStart = "${cfg.server.package}/bin/lemmy_server";
+          LoadCredential = mkIf (cfg.secretFile != null) "secretFile:${toString cfg.secretFile}";
+          PrivateTmp = true;
+          MemoryDenyWriteExecute = true;
+          NoNewPrivileges = true;
         };
       };
 
diff --git a/nixos/modules/services/web-apps/snipe-it.nix b/nixos/modules/services/web-apps/snipe-it.nix
index 93b0aafab64..e861a418519 100644
--- a/nixos/modules/services/web-apps/snipe-it.nix
+++ b/nixos/modules/services/web-apps/snipe-it.nix
@@ -15,6 +15,8 @@ let
 
   tlsEnabled = cfg.nginx.addSSL || cfg.nginx.forceSSL || cfg.nginx.onlySSL || cfg.nginx.enableACME;
 
+  inherit (snipe-it.passthru) phpPackage;
+
   # shell script for local administration
   artisan = pkgs.writeScriptBin "snipe-it" ''
     #! ${pkgs.runtimeShell}
@@ -23,7 +25,7 @@ let
     if [[ "$USER" != ${user} ]]; then
       sudo='exec /run/wrappers/bin/sudo -u ${user}'
     fi
-    $sudo ${pkgs.php}/bin/php artisan $*
+    $sudo ${phpPackage}/bin/php artisan $*
   '';
 in {
   options.services.snipe-it = {
@@ -340,8 +342,7 @@ in {
     };
 
     services.phpfpm.pools.snipe-it = {
-      inherit user group;
-      phpPackage = pkgs.php81;
+      inherit user group phpPackage;
       phpOptions = ''
         post_max_size = ${cfg.maxUploadSize}
         upload_max_filesize = ${cfg.maxUploadSize}
@@ -450,7 +451,7 @@ in {
           rm "${cfg.dataDir}"/bootstrap/cache/*.php || true
 
           # migrate db
-          ${pkgs.php}/bin/php artisan migrate --force
+          ${phpPackage}/bin/php artisan migrate --force
 
           # A placeholder file for invalid barcodes
           invalid_barcode_location="${cfg.dataDir}/public/uploads/barcodes/invalid_barcode.gif"
diff --git a/nixos/modules/services/web-servers/caddy/default.nix b/nixos/modules/services/web-servers/caddy/default.nix
index 70715a23725..5cc9ef6dd6d 100644
--- a/nixos/modules/services/web-servers/caddy/default.nix
+++ b/nixos/modules/services/web-servers/caddy/default.nix
@@ -41,6 +41,10 @@ let
     in
       "${if pkgs.stdenv.buildPlatform == pkgs.stdenv.hostPlatform then Caddyfile-formatted else Caddyfile}/Caddyfile";
 
+  etcConfigFile = "caddy/caddy_config";
+
+  configPath = "/etc/${etcConfigFile}";
+
   acmeHosts = unique (catAttrs "useACMEHost" acmeVHosts);
 
   mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix;
@@ -155,11 +159,16 @@ in
       description = lib.mdDoc ''
         Override the configuration file used by Caddy. By default,
         NixOS generates one automatically.
+
+        The configuration file is exposed at {file}`${configPath}`.
       '';
     };
 
     adapter = mkOption {
-      default = null;
+      default = if (builtins.baseNameOf cfg.configFile) == "Caddyfile" then "caddyfile" else null;
+      defaultText = literalExpression ''
+        if (builtins.baseNameOf cfg.configFile) == "Caddyfile" then "caddyfile" else null
+      '';
       example = literalExpression "nginx";
       type = with types; nullOr str;
       description = lib.mdDoc ''
@@ -275,6 +284,21 @@ in
       '';
     };
 
+    enableReload = mkOption {
+      default = true;
+      type = types.bool;
+      description = lib.mdDoc ''
+        Reload Caddy instead of restarting it when configuration file changes.
+
+        Note that enabling this option requires the [admin API](https://caddyserver.com/docs/caddyfile/options#admin)
+        to not be turned off.
+
+        If you enable this option, consider setting [`grace_period`](https://caddyserver.com/docs/caddyfile/options#grace-period)
+        to a non-infinite value in {option}`services.caddy.globalConfig`
+        to prevent Caddy waiting for active connections to finish,
+        which could delay the reload essentially indefinitely.
+      '';
+    };
   };
 
   # implementation
@@ -311,13 +335,16 @@ in
       wantedBy = [ "multi-user.target" ];
       startLimitIntervalSec = 14400;
       startLimitBurst = 10;
+      reloadTriggers = optional cfg.enableReload cfg.configFile;
 
-      serviceConfig = {
+      serviceConfig = let
+        runOptions = ''--config ${configPath} ${optionalString (cfg.adapter != null) "--adapter ${cfg.adapter}"}'';
+      in {
         # https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
         # If the empty string is assigned to this option, the list of commands to start is reset, prior assignments of this option will have no effect.
-        ExecStart = [ "" ''${cfg.package}/bin/caddy run --config ${cfg.configFile} ${optionalString (cfg.adapter != null) "--adapter ${cfg.adapter}"} ${optionalString cfg.resume "--resume"}'' ];
-        ExecReload = [ "" ''${cfg.package}/bin/caddy reload --config ${cfg.configFile} ${optionalString (cfg.adapter != null) "--adapter ${cfg.adapter}"} --force'' ];
-        ExecStartPre = ''${cfg.package}/bin/caddy validate --config ${cfg.configFile} ${optionalString (cfg.adapter != null) "--adapter ${cfg.adapter}"}'';
+        ExecStart = [ "" ''${cfg.package}/bin/caddy run ${runOptions} ${optionalString cfg.resume "--resume"}'' ];
+        # Validating the configuration before applying it ensures we’ll get a proper error that will be reported when switching to the configuration
+        ExecReload = [ "" ''${cfg.package}/bin/caddy reload ${runOptions} --force'' ];
         User = cfg.user;
         Group = cfg.group;
         ReadWriteDirectories = cfg.dataDir;
@@ -353,5 +380,6 @@ in
       in
         listToAttrs certCfg;
 
+    environment.etc.${etcConfigFile}.source = cfg.configFile;
   };
 }
diff --git a/nixos/modules/services/web-servers/static-web-server.nix b/nixos/modules/services/web-servers/static-web-server.nix
new file mode 100644
index 00000000000..07187f00fec
--- /dev/null
+++ b/nixos/modules/services/web-servers/static-web-server.nix
@@ -0,0 +1,68 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.static-web-server;
+  toml = pkgs.formats.toml {};
+  configFilePath = toml.generate "config.toml" cfg.configuration;
+in {
+  options = {
+    services.static-web-server = {
+      enable = lib.mkEnableOption (lib.mdDoc ''Static Web Server'');
+      listen = lib.mkOption {
+        default = "[::]:8787";
+        type = lib.types.str;
+        description = lib.mdDoc ''
+          The "ListenStream" used in static-web-server.socket.
+          This is equivalent to SWS's "host" and "port" options.
+          See here for specific syntax: <https://www.freedesktop.org/software/systemd/man/systemd.socket.html#ListenStream=>
+        '';
+      };
+      root = lib.mkOption {
+        type = lib.types.path;
+        description = lib.mdDoc ''
+          The location of files for SWS to serve. Equivalent to SWS's "root" config value.
+          NOTE: This folder must exist before starting SWS.
+        '';
+      };
+      configuration = lib.mkOption {
+        default = { };
+        type = toml.type;
+        example = {
+          general = { log-level = "error"; directory-listing = true; };
+        };
+        description = lib.mdDoc ''
+          Configuration for Static Web Server. See
+          <https://static-web-server.net/configuration/config-file/>.
+          NOTE: Don't set "host", "port", or "root" here. They will be ignored.
+          Use the top-level "listen" and "root" options instead.
+        '';
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.static-web-server ];
+    systemd.packages = [ pkgs.static-web-server ];
+    # Have to set wantedBy since systemd.packages ignores the "Install" section
+    systemd.sockets.static-web-server = {
+      wantedBy = [ "sockets.target" ];
+      # Start with empty string to reset upstream option
+      listenStreams = [ "" cfg.listen ];
+    };
+    systemd.services.static-web-server = {
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        # Remove upstream sample environment file; use config.toml exclusively
+        EnvironmentFile = [ "" ];
+        ExecStart = [ "" "${pkgs.static-web-server}/bin/static-web-server --fd 0 --config-file ${configFilePath} --root ${cfg.root}" ];
+        # Supplementary groups doesn't work unless we create the group ourselves
+        SupplementaryGroups = [ "" ];
+        # If the user is serving files from their home dir, override ProtectHome to allow that
+        ProtectHome = if lib.hasPrefix "/home" cfg.root then "tmpfs" else "true";
+        BindReadOnlyPaths = cfg.root;
+      };
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ mac-chaffee ];
+}
diff --git a/nixos/modules/services/web-servers/ttyd.nix b/nixos/modules/services/web-servers/ttyd.nix
index e0a8b5179e0..3b1d87ccb48 100644
--- a/nixos/modules/services/web-servers/ttyd.nix
+++ b/nixos/modules/services/web-servers/ttyd.nix
@@ -78,11 +78,12 @@ in
       clientOptions = mkOption {
         type = types.attrsOf types.str;
         default = {};
-        example = literalExpression ''{
-          fontSize = "16";
-          fontFamily = "Fira Code";
-
-        }'';
+        example = literalExpression ''
+          {
+            fontSize = "16";
+            fontFamily = "Fira Code";
+          }
+        '';
         description = lib.mdDoc ''
           Attribute set of client options for xtermjs.
           <https://xtermjs.org/docs/api/terminal/interfaces/iterminaloptions/>
diff --git a/nixos/modules/services/x11/desktop-managers/cde.nix b/nixos/modules/services/x11/desktop-managers/cde.nix
index e0b4fb0e7bf..ad4b5d27f9d 100644
--- a/nixos/modules/services/x11/desktop-managers/cde.nix
+++ b/nixos/modules/services/x11/desktop-managers/cde.nix
@@ -36,7 +36,7 @@ in {
         name = "cmsd";
         protocol = "udp";
         user = "root";
-        server = "${pkgs.cdesktopenv}/opt/dt/bin/rpc.cmsd";
+        server = "${pkgs.cdesktopenv}/bin/rpc.cmsd";
         extraConfig = ''
           type  = RPC UNLISTED
           rpc_number  = 100068
@@ -64,7 +64,7 @@ in {
     services.xserver.desktopManager.session = [
     { name = "CDE";
       start = ''
-        exec ${pkgs.cdesktopenv}/opt/dt/bin/Xsession
+        exec ${pkgs.cdesktopenv}/bin/Xsession
       '';
     }];
   };
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index 0db4cca520f..e87ae5ae812 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -315,7 +315,6 @@ in
       environment.systemPackages = with pkgs.pantheon; [
         contractor
         file-roller-contract
-        gnome-bluetooth-contract
       ];
 
       environment.pathsToLink = [
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index f8f82bda3fa..676d08b93e2 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -207,7 +207,9 @@ in
     # conflicts display-manager.service, then when nixos-rebuild
     # switch starts multi-user.target, display-manager.service is
     # stopped so plymouth-quit.service can be started.)
-    systemd.services.plymouth-quit.wantedBy = lib.mkForce [];
+    systemd.services.plymouth-quit = mkIf config.boot.plymouth.enable {
+      wantedBy = lib.mkForce [];
+    };
 
     systemd.services.display-manager.serviceConfig = {
       # Restart = "always"; - already defined in xserver.nix
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index 6d2321be8ef..53d9c99b47d 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -725,7 +725,7 @@ in
     systemd.defaultUnit = mkIf cfg.autorun "graphical.target";
 
     systemd.services.display-manager =
-      { description = "X11 Server";
+      { description = "Display Manager";
 
         after = [ "acpid.service" "systemd-logind.service" "systemd-user-sessions.service" ];
 
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index d88f88f9fda..ad8c609e150 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -2,6 +2,7 @@
 
 with utils.systemdUtils.unitOptions;
 with utils.systemdUtils.lib;
+with utils.systemdUtils.network.units;
 with lib;
 
 let
@@ -1897,7 +1898,7 @@ let
 
   bridgeVLANOptions = {
     options = {
-      bridgeMDBConfig = mkOption {
+      bridgeVLANConfig = mkOption {
         default = {};
         example = { VLAN = 20; };
         type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridgeVLAN;
@@ -2388,17 +2389,6 @@ let
       '';
     };
 
-    bridgeVLANConfig = mkOption {
-      default = {};
-      example = { VLAN = "10-20"; };
-      type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridgeVLAN;
-      description = lib.mdDoc ''
-        Each attribute in this set specifies an option in the
-        `[BridgeVLAN]` section of the unit.  See
-        {manpage}`systemd.network(5)` for details.
-      '';
-    };
-
     bridgeVLANs = mkOption {
       default = [];
       example = [ { bridgeVLANConfig = { VLAN = "10-20"; }; } ];
@@ -2615,95 +2605,6 @@ let
     };
   };
 
-  commonMatchText = def: optionalString (def.matchConfig != { }) ''
-    [Match]
-    ${attrsToSection def.matchConfig}
-  '';
-
-  linkToUnit = name: def:
-    { inherit (def) enable;
-      text = commonMatchText def
-        + ''
-          [Link]
-          ${attrsToSection def.linkConfig}
-        ''
-        + def.extraConfig;
-    };
-
-  netdevToUnit = name: def:
-    { inherit (def) enable;
-      text = commonMatchText def
-        + ''
-          [NetDev]
-          ${attrsToSection def.netdevConfig}
-        ''
-        + optionalString (def.vlanConfig != { }) ''
-          [VLAN]
-          ${attrsToSection def.vlanConfig}
-        ''
-        + optionalString (def.macvlanConfig != { }) ''
-          [MACVLAN]
-          ${attrsToSection def.macvlanConfig}
-        ''
-        + optionalString (def.vxlanConfig != { }) ''
-          [VXLAN]
-          ${attrsToSection def.vxlanConfig}
-        ''
-        + optionalString (def.tunnelConfig != { }) ''
-          [Tunnel]
-          ${attrsToSection def.tunnelConfig}
-        ''
-        + optionalString (def.fooOverUDPConfig != { }) ''
-          [FooOverUDP]
-          ${attrsToSection def.fooOverUDPConfig}
-        ''
-        + optionalString (def.peerConfig != { }) ''
-          [Peer]
-          ${attrsToSection def.peerConfig}
-        ''
-        + optionalString (def.tunConfig != { }) ''
-          [Tun]
-          ${attrsToSection def.tunConfig}
-        ''
-        + optionalString (def.tapConfig != { }) ''
-          [Tap]
-          ${attrsToSection def.tapConfig}
-        ''
-        + optionalString (def.l2tpConfig != { }) ''
-          [L2TP]
-          ${attrsToSection def.l2tpConfig}
-        ''
-        + flip concatMapStrings def.l2tpSessions (x: ''
-          [L2TPSession]
-          ${attrsToSection x.l2tpSessionConfig}
-        '')
-        + optionalString (def.wireguardConfig != { }) ''
-          [WireGuard]
-          ${attrsToSection def.wireguardConfig}
-        ''
-        + flip concatMapStrings def.wireguardPeers (x: ''
-          [WireGuardPeer]
-          ${attrsToSection x.wireguardPeerConfig}
-        '')
-        + optionalString (def.bondConfig != { }) ''
-          [Bond]
-          ${attrsToSection def.bondConfig}
-        ''
-        + optionalString (def.xfrmConfig != { }) ''
-          [Xfrm]
-          ${attrsToSection def.xfrmConfig}
-        ''
-        + optionalString (def.vrfConfig != { }) ''
-          [VRF]
-          ${attrsToSection def.vrfConfig}
-        ''
-        + optionalString (def.batmanAdvancedConfig != { }) ''
-          [BatmanAdvanced]
-          ${attrsToSection def.batmanAdvancedConfig}
-        ''
-        + def.extraConfig;
-    };
-
   renderConfig = def:
     { text = ''
         [Network]
@@ -2718,235 +2619,6 @@ let
         ${attrsToSection def.dhcpV6Config}
       ''; };
 
-  networkToUnit = name: def:
-    { inherit (def) enable;
-      text = commonMatchText def
-        + optionalString (def.linkConfig != { }) ''
-          [Link]
-          ${attrsToSection def.linkConfig}
-        ''
-        + ''
-          [Network]
-        ''
-        + attrsToSection def.networkConfig
-        + optionalString (def.address != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "Address=${s}") def.address)}
-        ''
-        + optionalString (def.gateway != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "Gateway=${s}") def.gateway)}
-        ''
-        + optionalString (def.dns != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "DNS=${s}") def.dns)}
-        ''
-        + optionalString (def.ntp != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "NTP=${s}") def.ntp)}
-        ''
-        + optionalString (def.bridge != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "Bridge=${s}") def.bridge)}
-        ''
-        + optionalString (def.bond != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "Bond=${s}") def.bond)}
-        ''
-        + optionalString (def.vrf != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "VRF=${s}") def.vrf)}
-        ''
-        + optionalString (def.vlan != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "VLAN=${s}") def.vlan)}
-        ''
-        + optionalString (def.macvlan != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "MACVLAN=${s}") def.macvlan)}
-        ''
-        + optionalString (def.vxlan != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "VXLAN=${s}") def.vxlan)}
-        ''
-        + optionalString (def.tunnel != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "Tunnel=${s}") def.tunnel)}
-        ''
-        + optionalString (def.xfrm != [ ]) ''
-          ${concatStringsSep "\n" (map (s: "Xfrm=${s}") def.xfrm)}
-        ''
-        + ''
-
-        ''
-        + flip concatMapStrings def.addresses (x: ''
-          [Address]
-          ${attrsToSection x.addressConfig}
-        '')
-        + flip concatMapStrings def.routingPolicyRules (x: ''
-          [RoutingPolicyRule]
-          ${attrsToSection x.routingPolicyRuleConfig}
-        '')
-        + flip concatMapStrings def.routes (x: ''
-          [Route]
-          ${attrsToSection x.routeConfig}
-        '')
-        + optionalString (def.dhcpV4Config != { }) ''
-          [DHCPv4]
-          ${attrsToSection def.dhcpV4Config}
-        ''
-        + optionalString (def.dhcpV6Config != { }) ''
-          [DHCPv6]
-          ${attrsToSection def.dhcpV6Config}
-        ''
-        + optionalString (def.dhcpPrefixDelegationConfig != { }) ''
-          [DHCPPrefixDelegation]
-          ${attrsToSection def.dhcpPrefixDelegationConfig}
-        ''
-        + optionalString (def.ipv6AcceptRAConfig != { }) ''
-          [IPv6AcceptRA]
-          ${attrsToSection def.ipv6AcceptRAConfig}
-        ''
-        + optionalString (def.dhcpServerConfig != { }) ''
-          [DHCPServer]
-          ${attrsToSection def.dhcpServerConfig}
-        ''
-        + optionalString (def.ipv6SendRAConfig != { }) ''
-          [IPv6SendRA]
-          ${attrsToSection def.ipv6SendRAConfig}
-        ''
-        + flip concatMapStrings def.ipv6Prefixes (x: ''
-          [IPv6Prefix]
-          ${attrsToSection x.ipv6PrefixConfig}
-        '')
-        + flip concatMapStrings def.ipv6RoutePrefixes (x: ''
-          [IPv6RoutePrefix]
-          ${attrsToSection x.ipv6RoutePrefixConfig}
-        '')
-        + flip concatMapStrings def.dhcpServerStaticLeases (x: ''
-          [DHCPServerStaticLease]
-          ${attrsToSection x.dhcpServerStaticLeaseConfig}
-        '')
-        + optionalString (def.bridgeConfig != { }) ''
-          [Bridge]
-          ${attrsToSection def.bridgeConfig}
-        ''
-        + flip concatMapStrings def.bridgeFDBs (x: ''
-          [BridgeFDB]
-          ${attrsToSection x.bridgeFDBConfig}
-        '')
-        + flip concatMapStrings def.bridgeMDBs (x: ''
-          [BridgeMDB]
-          ${attrsToSection x.bridgeMDBConfig}
-        '')
-        + optionalString (def.lldpConfig != { }) ''
-          [LLDP]
-          ${attrsToSection def.lldpConfig}
-        ''
-        + optionalString (def.canConfig != { }) ''
-          [CAN]
-          ${attrsToSection def.canConfig}
-        ''
-        + optionalString (def.ipoIBConfig != { }) ''
-          [IPoIB]
-          ${attrsToSection def.ipoIBConfig}
-        ''
-        + optionalString (def.qdiscConfig != { }) ''
-          [QDisc]
-          ${attrsToSection def.qdiscConfig}
-        ''
-        + optionalString (def.networkEmulatorConfig != { }) ''
-          [NetworkEmulator]
-          ${attrsToSection def.networkEmulatorConfig}
-        ''
-        + optionalString (def.tokenBucketFilterConfig != { }) ''
-          [TokenBucketFilter]
-          ${attrsToSection def.tokenBucketFilterConfig}
-        ''
-        + optionalString (def.pieConfig != { }) ''
-          [PIE]
-          ${attrsToSection def.pieConfig}
-        ''
-        + optionalString (def.flowQueuePIEConfig != { }) ''
-          [FlowQueuePIE]
-          ${attrsToSection def.flowQueuePIEConfig}
-        ''
-        + optionalString (def.stochasticFairBlueConfig != { }) ''
-          [StochasticFairBlue]
-          ${attrsToSection def.stochasticFairBlueConfig}
-        ''
-        + optionalString (def.stochasticFairnessQueueingConfig != { }) ''
-          [StochasticFairnessQueueing]
-          ${attrsToSection def.stochasticFairnessQueueingConfig}
-        ''
-        + optionalString (def.bfifoConfig != { }) ''
-          [BFIFO]
-          ${attrsToSection def.bfifoConfig}
-        ''
-        + optionalString (def.pfifoConfig != { }) ''
-          [PFIFO]
-          ${attrsToSection def.pfifoConfig}
-        ''
-        + optionalString (def.pfifoHeadDropConfig != { }) ''
-          [PFIFOHeadDrop]
-          ${attrsToSection def.pfifoHeadDropConfig}
-        ''
-        + optionalString (def.pfifoFastConfig != { }) ''
-          [PFIFOFast]
-          ${attrsToSection def.pfifoFastConfig}
-        ''
-        + optionalString (def.cakeConfig != { }) ''
-          [CAKE]
-          ${attrsToSection def.cakeConfig}
-        ''
-        + optionalString (def.controlledDelayConfig != { }) ''
-          [ControlledDelay]
-          ${attrsToSection def.controlledDelayConfig}
-        ''
-        + optionalString (def.deficitRoundRobinSchedulerConfig != { }) ''
-          [DeficitRoundRobinScheduler]
-          ${attrsToSection def.deficitRoundRobinSchedulerConfig}
-        ''
-        + optionalString (def.deficitRoundRobinSchedulerClassConfig != { }) ''
-          [DeficitRoundRobinSchedulerClass]
-          ${attrsToSection def.deficitRoundRobinSchedulerClassConfig}
-        ''
-        + optionalString (def.enhancedTransmissionSelectionConfig != { }) ''
-          [EnhancedTransmissionSelection]
-          ${attrsToSection def.enhancedTransmissionSelectionConfig}
-        ''
-        + optionalString (def.genericRandomEarlyDetectionConfig != { }) ''
-          [GenericRandomEarlyDetection]
-          ${attrsToSection def.genericRandomEarlyDetectionConfig}
-        ''
-        + optionalString (def.fairQueueingControlledDelayConfig != { }) ''
-          [FairQueueingControlledDelay]
-          ${attrsToSection def.fairQueueingControlledDelayConfig}
-        ''
-        + optionalString (def.fairQueueingConfig != { }) ''
-          [FairQueueing]
-          ${attrsToSection def.fairQueueingConfig}
-        ''
-        + optionalString (def.trivialLinkEqualizerConfig != { }) ''
-          [TrivialLinkEqualizer]
-          ${attrsToSection def.trivialLinkEqualizerConfig}
-        ''
-        + optionalString (def.hierarchyTokenBucketConfig != { }) ''
-          [HierarchyTokenBucket]
-          ${attrsToSection def.hierarchyTokenBucketConfig}
-        ''
-        + optionalString (def.hierarchyTokenBucketClassConfig != { }) ''
-          [HierarchyTokenBucketClass]
-          ${attrsToSection def.hierarchyTokenBucketClassConfig}
-        ''
-        + optionalString (def.heavyHitterFilterConfig != { }) ''
-          [HeavyHitterFilter]
-          ${attrsToSection def.heavyHitterFilterConfig}
-        ''
-        + optionalString (def.quickFairQueueingConfig != { }) ''
-          [QuickFairQueueing]
-          ${attrsToSection def.quickFairQueueingConfig}
-        ''
-        + optionalString (def.quickFairQueueingConfigClass != { }) ''
-          [QuickFairQueueingClass]
-          ${attrsToSection def.quickFairQueueingConfigClass}
-        ''
-        + flip concatMapStrings def.bridgeVLANs (x: ''
-          [BridgeVLAN]
-          ${attrsToSection x.bridgeVLANConfig}
-        '')
-        + def.extraConfig;
-    };
-
   mkUnitFiles = prefix: cfg: listToAttrs (map (name: {
     name = "${prefix}systemd/network/${name}";
     value.source = "${cfg.units.${name}.unit}/${name}";
@@ -3059,11 +2731,14 @@ let
 
   };
 
-  commonConfig = config: let cfg = config.systemd.network; in mkMerge [
+  commonConfig = config: let
+    cfg = config.systemd.network;
+    mkUnit = f: def: { inherit (def) enable; text = f def; };
+  in mkMerge [
 
     # .link units are honored by udev, no matter if systemd-networkd is enabled or not.
     {
-      systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links;
+      systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (mkUnit linkToUnit v)) cfg.links;
 
       systemd.network.wait-online.extraArgs =
         [ "--timeout=${toString cfg.wait-online.timeout}" ]
@@ -3073,8 +2748,8 @@ let
 
     (mkIf config.systemd.network.enable {
 
-      systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs
-        // mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.networks;
+      systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.netdev" (mkUnit netdevToUnit v)) cfg.netdevs
+        // mapAttrs' (n: v: nameValuePair "${n}.network" (mkUnit networkToUnit v)) cfg.networks;
 
       # systemd-networkd is socket-activated by kernel netlink route change
       # messages. It is important to have systemd buffer those on behalf of
@@ -3165,7 +2840,7 @@ let
 
     (mkIf cfg.enable {
 
-      systemd.package = pkgs.systemdStage1Network;
+      systemd.package = mkDefault pkgs.systemdStage1Network;
 
       # For networkctl
       systemd.dbus.enable = mkDefault true;
diff --git a/nixos/modules/tasks/bcache.nix b/nixos/modules/tasks/bcache.nix
index 408ddc02373..35b922dc8a1 100644
--- a/nixos/modules/tasks/bcache.nix
+++ b/nixos/modules/tasks/bcache.nix
@@ -1,8 +1,12 @@
 { config, lib, pkgs, ... }:
 
 {
-  options.boot.initrd.services.bcache.enable = (lib.mkEnableOption (lib.mdDoc "bcache support in the initrd")) // {
-    visible = false; # only works with systemd stage 1
+  options.boot.initrd.services.bcache.enable = lib.mkEnableOption (lib.mdDoc "bcache support in the initrd") // {
+    description = lib.mdDoc ''
+      *This will only be used when systemd is used in stage 1.*
+
+      Whether to enable bcache support in the initrd.
+    '';
   };
 
   config = {
diff --git a/nixos/modules/tasks/filesystems/bcachefs.nix b/nixos/modules/tasks/filesystems/bcachefs.nix
index 851c0978133..19ef188ce78 100644
--- a/nixos/modules/tasks/filesystems/bcachefs.nix
+++ b/nixos/modules/tasks/filesystems/bcachefs.nix
@@ -6,6 +6,15 @@ let
 
   bootFs = filterAttrs (n: fs: (fs.fsType == "bcachefs") && (utils.fsNeededForBoot fs)) config.fileSystems;
 
+  mountCommand = pkgs.runCommand "mount.bcachefs" {} ''
+    mkdir -p $out/bin
+    cat > $out/bin/mount.bcachefs <<EOF
+    #!/bin/sh
+    exec "/bin/bcachefs" mount "\$@"
+    EOF
+    chmod +x $out/bin/mount.bcachefs
+  '';
+
   commonFunctions = ''
     prompt() {
         local name="$1"
@@ -58,13 +67,12 @@ in
 
       boot.initrd.systemd.extraBin = {
         "bcachefs" = "${pkgs.bcachefs-tools}/bin/bcachefs";
-        "mount.bcachefs" = pkgs.runCommand "mount.bcachefs" {} ''
-          cp -pdv ${pkgs.bcachefs-tools}/bin/.mount.bcachefs.sh-wrapped $out
-        '';
+        "mount.bcachefs" = "${mountCommand}/bin/mount.bcachefs";
       };
 
       boot.initrd.extraUtilsCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
         copy_bin_and_libs ${pkgs.bcachefs-tools}/bin/bcachefs
+        copy_bin_and_libs ${mountCommand}/bin/mount.bcachefs
       '';
       boot.initrd.extraUtilsCommandsTest = ''
         $out/bin/bcachefs version
diff --git a/nixos/modules/tasks/lvm.nix b/nixos/modules/tasks/lvm.nix
index a14f26c02e4..325a5aa45b1 100644
--- a/nixos/modules/tasks/lvm.nix
+++ b/nixos/modules/tasks/lvm.nix
@@ -25,8 +25,12 @@ in {
     boot.vdo.enable = mkEnableOption (lib.mdDoc "support for booting from VDOLVs");
   };
 
-  options.boot.initrd.services.lvm.enable = (mkEnableOption (lib.mdDoc "enable booting from LVM2 in the initrd")) // {
-    visible = false;
+  options.boot.initrd.services.lvm.enable = mkEnableOption (lib.mdDoc "booting from LVM2 in the initrd") // {
+    description = lib.mdDoc ''
+      *This will only be used when systemd is used in stage 1.*
+
+      Whether to enable booting from LVM2 in the initrd.
+    '';
   };
 
   config = mkMerge [
@@ -40,12 +44,13 @@ in {
       systemd.packages = [ cfg.package ];
 
       services.udev.packages = [ cfg.package.out ];
-
+    })
+    (mkIf config.boot.initrd.services.lvm.enable {
       # We need lvm2 for the device-mapper rules
-      boot.initrd.services.udev.packages = lib.mkIf config.boot.initrd.services.lvm.enable [ cfg.package ];
+      boot.initrd.services.udev.packages = [ cfg.package ];
       # The device-mapper rules want to call tools from lvm2
-      boot.initrd.systemd.initrdBin = lib.mkIf config.boot.initrd.services.lvm.enable [ cfg.package ];
-      boot.initrd.services.udev.binPackages = lib.mkIf config.boot.initrd.services.lvm.enable [ cfg.package ];
+      boot.initrd.systemd.initrdBin = [ cfg.package ];
+      boot.initrd.services.udev.binPackages = [ cfg.package ];
     })
     (mkIf cfg.dmeventd.enable {
       systemd.sockets."dm-event".wantedBy = [ "sockets.target" ];
diff --git a/nixos/modules/tasks/swraid.nix b/nixos/modules/tasks/swraid.nix
index 7832bbf9201..1c3f1db1509 100644
--- a/nixos/modules/tasks/swraid.nix
+++ b/nixos/modules/tasks/swraid.nix
@@ -5,8 +5,12 @@
 in {
 
   options.boot.initrd.services.swraid = {
-    enable = (lib.mkEnableOption (lib.mdDoc "swraid support using mdadm")) // {
-      visible = false; # only has effect when the new stage 1 is in place
+    enable = lib.mkEnableOption (lib.mdDoc "swraid support using mdadm") // {
+      description = ''
+        *This will only be used when systemd is used in stage 1.*
+
+        Whether to enable swraid support using mdadm.
+      '';
     };
 
     mdadmConf = lib.mkOption {
diff --git a/nixos/modules/virtualisation/proxmox-image.nix b/nixos/modules/virtualisation/proxmox-image.nix
index b5d4ecd0268..1074b02d0eb 100644
--- a/nixos/modules/virtualisation/proxmox-image.nix
+++ b/nixos/modules/virtualisation/proxmox-image.nix
@@ -98,10 +98,12 @@ with lib;
     qemuExtraConf = mkOption {
       type = with types; attrsOf (oneOf [ str int ]);
       default = {};
-      example = literalExpression ''{
-        cpu = "host";
-        onboot = 1;
-      }'';
+      example = literalExpression ''
+        {
+          cpu = "host";
+          onboot = 1;
+        }
+      '';
       description = lib.mdDoc ''
         Additional options appended to qemu-server.conf
       '';