about summary refs log tree commit diff
path: root/nixos/modules/services
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services')
-rw-r--r--nixos/modules/services/admin/salt/master.nix2
-rw-r--r--nixos/modules/services/admin/salt/minion.nix2
-rw-r--r--nixos/modules/services/audio/mpdscribble.nix2
-rw-r--r--nixos/modules/services/backup/borgbackup.nix4
-rw-r--r--nixos/modules/services/backup/restic-rest-server.nix37
-rw-r--r--nixos/modules/services/backup/znapzend.nix2
-rw-r--r--nixos/modules/services/databases/hbase-standalone.nix2
-rw-r--r--nixos/modules/services/databases/lldap.nix2
-rw-r--r--nixos/modules/services/databases/victoriametrics.nix2
-rw-r--r--nixos/modules/services/desktop-managers/plasma6.nix16
-rw-r--r--nixos/modules/services/desktops/blueman.nix2
-rw-r--r--nixos/modules/services/desktops/deepin/dde-api.nix2
-rw-r--r--nixos/modules/services/desktops/neard.nix2
-rw-r--r--nixos/modules/services/desktops/zeitgeist.nix2
-rw-r--r--nixos/modules/services/development/distccd.nix2
-rw-r--r--nixos/modules/services/development/gemstash.nix2
-rw-r--r--nixos/modules/services/display-managers/default.nix257
-rw-r--r--nixos/modules/services/display-managers/greetd.nix2
-rw-r--r--nixos/modules/services/display-managers/sddm.nix (renamed from nixos/modules/services/x11/display-managers/sddm.nix)57
-rw-r--r--nixos/modules/services/finance/odoo.nix2
-rw-r--r--nixos/modules/services/games/mchprs.nix2
-rw-r--r--nixos/modules/services/games/openarena.nix2
-rw-r--r--nixos/modules/services/hardware/kanata.nix2
-rw-r--r--nixos/modules/services/hardware/lirc.nix2
-rw-r--r--nixos/modules/services/hardware/openrgb.nix2
-rw-r--r--nixos/modules/services/hardware/pcscd.nix2
-rw-r--r--nixos/modules/services/hardware/udev.nix2
-rw-r--r--nixos/modules/services/hardware/undervolt.nix2
-rw-r--r--nixos/modules/services/hardware/vdr.nix2
-rw-r--r--nixos/modules/services/home-automation/ebusd.nix2
-rw-r--r--nixos/modules/services/home-automation/esphome.nix2
-rw-r--r--nixos/modules/services/logging/awstats.nix2
-rw-r--r--nixos/modules/services/logging/fluentd.nix2
-rw-r--r--nixos/modules/services/logging/graylog.nix2
-rw-r--r--nixos/modules/services/logging/heartbeat.nix2
-rw-r--r--nixos/modules/services/logging/logcheck.nix2
-rw-r--r--nixos/modules/services/logging/logrotate.nix15
-rw-r--r--nixos/modules/services/logging/ulogd.nix2
-rw-r--r--nixos/modules/services/logging/vector.nix2
-rw-r--r--nixos/modules/services/mail/goeland.nix2
-rw-r--r--nixos/modules/services/mail/mailcatcher.nix2
-rw-r--r--nixos/modules/services/mail/mailhog.nix2
-rw-r--r--nixos/modules/services/matrix/mautrix-meta.nix562
-rw-r--r--nixos/modules/services/matrix/synapse.nix2
-rw-r--r--nixos/modules/services/misc/ankisyncd.nix2
-rw-r--r--nixos/modules/services/misc/autorandr.nix9
-rw-r--r--nixos/modules/services/misc/bepasty.nix2
-rw-r--r--nixos/modules/services/misc/calibre-server.nix2
-rw-r--r--nixos/modules/services/misc/confd.nix2
-rw-r--r--nixos/modules/services/misc/etesync-dav.nix2
-rw-r--r--nixos/modules/services/misc/evdevremapkeys.nix2
-rw-r--r--nixos/modules/services/misc/forgejo.nix2
-rw-r--r--nixos/modules/services/misc/geoipupdate.nix2
-rw-r--r--nixos/modules/services/misc/gollum.nix2
-rw-r--r--nixos/modules/services/misc/graphical-desktop.nix54
-rw-r--r--nixos/modules/services/misc/greenclip.nix2
-rw-r--r--nixos/modules/services/misc/homepage-dashboard.nix2
-rw-r--r--nixos/modules/services/misc/jackett.nix2
-rw-r--r--nixos/modules/services/misc/languagetool.nix2
-rw-r--r--nixos/modules/services/misc/leaps.nix2
-rw-r--r--nixos/modules/services/misc/lidarr.nix2
-rw-r--r--nixos/modules/services/misc/lifecycled.nix2
-rw-r--r--nixos/modules/services/misc/logkeys.nix2
-rw-r--r--nixos/modules/services/misc/mbpfan.nix13
-rw-r--r--nixos/modules/services/misc/nitter.nix2
-rw-r--r--nixos/modules/services/misc/nix-optimise.nix8
-rw-r--r--nixos/modules/services/misc/nzbget.nix2
-rw-r--r--nixos/modules/services/misc/nzbhydra2.nix2
-rw-r--r--nixos/modules/services/misc/ollama.nix20
-rw-r--r--nixos/modules/services/misc/ombi.nix4
-rw-r--r--nixos/modules/services/misc/owncast.nix2
-rw-r--r--nixos/modules/services/misc/paperless.nix35
-rw-r--r--nixos/modules/services/misc/pinnwand.nix2
-rw-r--r--nixos/modules/services/misc/plikd.nix2
-rw-r--r--nixos/modules/services/misc/prowlarr.nix2
-rw-r--r--nixos/modules/services/misc/radarr.nix2
-rw-r--r--nixos/modules/services/misc/readarr.nix2
-rw-r--r--nixos/modules/services/misc/redmine.nix2
-rw-r--r--nixos/modules/services/misc/rippled.nix2
-rw-r--r--nixos/modules/services/misc/signald.nix2
-rw-r--r--nixos/modules/services/monitoring/nezha-agent.nix103
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters.nix1
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/nats.nix34
-rw-r--r--nixos/modules/services/monitoring/thanos.nix8
-rw-r--r--nixos/modules/services/networking/bind.nix2
-rw-r--r--nixos/modules/services/networking/cloudflared.nix2
-rw-r--r--nixos/modules/services/networking/i2p.nix5
-rw-r--r--nixos/modules/services/networking/kea.nix1
-rw-r--r--nixos/modules/services/networking/mihomo.nix8
-rw-r--r--nixos/modules/services/networking/radicale.nix2
-rw-r--r--nixos/modules/services/networking/soju.nix24
-rw-r--r--nixos/modules/services/networking/technitium-dns-server.nix109
-rw-r--r--nixos/modules/services/networking/tinc.nix14
-rw-r--r--nixos/modules/services/security/yubikey-agent.nix2
-rw-r--r--nixos/modules/services/system/cloud-init.nix14
-rw-r--r--nixos/modules/services/system/nix-daemon.nix2
-rw-r--r--nixos/modules/services/web-apps/castopod.nix2
-rw-r--r--nixos/modules/services/web-apps/healthchecks.nix3
-rw-r--r--nixos/modules/services/web-apps/hledger-web.nix45
-rw-r--r--nixos/modules/services/web-apps/kavita.nix4
-rw-r--r--nixos/modules/services/web-apps/movim.nix711
-rw-r--r--nixos/modules/services/web-apps/outline.nix2
-rw-r--r--nixos/modules/services/web-apps/silverbullet.nix123
-rw-r--r--nixos/modules/services/x11/desktop-managers/budgie.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/cinnamon.nix12
-rw-r--r--nixos/modules/services/x11/desktop-managers/deepin.nix4
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/enlightenment.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome.nix4
-rw-r--r--nixos/modules/services/x11/desktop-managers/lumina.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/mate.nix4
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.nix25
-rw-r--r--nixos/modules/services/x11/desktop-managers/phosh.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix12
-rw-r--r--nixos/modules/services/x11/desktop-managers/surf-display.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix219
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix20
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix4
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix20
-rw-r--r--nixos/modules/services/x11/display-managers/xpra.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/ragnarwm.nix2
-rw-r--r--nixos/modules/services/x11/xserver.nix53
124 files changed, 2321 insertions, 524 deletions
diff --git a/nixos/modules/services/admin/salt/master.nix b/nixos/modules/services/admin/salt/master.nix
index 4346022970e12..e10a10efae652 100644
--- a/nixos/modules/services/admin/salt/master.nix
+++ b/nixos/modules/services/admin/salt/master.nix
@@ -20,7 +20,7 @@ in
 {
   options = {
     services.salt.master = {
-      enable = mkEnableOption (lib.mdDoc "Salt master service");
+      enable = mkEnableOption (lib.mdDoc "Salt configuration management system master service");
       configuration = mkOption {
         type = types.attrs;
         default = {};
diff --git a/nixos/modules/services/admin/salt/minion.nix b/nixos/modules/services/admin/salt/minion.nix
index 3ae02a4cc5d5d..28b52e07c40bd 100644
--- a/nixos/modules/services/admin/salt/minion.nix
+++ b/nixos/modules/services/admin/salt/minion.nix
@@ -21,7 +21,7 @@ in
 {
   options = {
     services.salt.minion = {
-      enable = mkEnableOption (lib.mdDoc "Salt minion service");
+      enable = mkEnableOption (lib.mdDoc "Salt configuration management system minion service");
       configuration = mkOption {
         type = types.attrs;
         default = {};
diff --git a/nixos/modules/services/audio/mpdscribble.nix b/nixos/modules/services/audio/mpdscribble.nix
index 132d9ad325886..e58fcdd25f63c 100644
--- a/nixos/modules/services/audio/mpdscribble.nix
+++ b/nixos/modules/services/audio/mpdscribble.nix
@@ -77,7 +77,7 @@ in {
 
   options.services.mpdscribble = {
 
-    enable = mkEnableOption (lib.mdDoc "mpdscribble");
+    enable = mkEnableOption (lib.mdDoc "mpdscribble, an MPD client which submits info about tracks being played to Last.fm (formerly AudioScrobbler)");
 
     proxy = mkOption {
       default = null;
diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix
index 6f4455d3be605..7d5714499f3a9 100644
--- a/nixos/modules/services/backup/borgbackup.nix
+++ b/nixos/modules/services/backup/borgbackup.nix
@@ -123,6 +123,7 @@ let
       };
       # if remote-backup wait for network
       after = optional (cfg.persistentTimer && !isLocalPath cfg.repo) "network-online.target";
+      wants = optional (cfg.persistentTimer && !isLocalPath cfg.repo) "network-online.target";
     };
 
   # utility function around makeWrapper
@@ -147,6 +148,9 @@ let
     let
       settings = { inherit (cfg) user group; };
     in lib.nameValuePair "borgbackup-job-${name}" ({
+      # Create parent dirs separately, to ensure correct ownership.
+      "${config.users.users."${cfg.user}".home}/.config".d = settings;
+      "${config.users.users."${cfg.user}".home}/.cache".d = settings;
       "${config.users.users."${cfg.user}".home}/.config/borg".d = settings;
       "${config.users.users."${cfg.user}".home}/.cache/borg".d = settings;
     } // optionalAttrs (isLocalPath cfg.repo && !cfg.removableDevice) {
diff --git a/nixos/modules/services/backup/restic-rest-server.nix b/nixos/modules/services/backup/restic-rest-server.nix
index 105a05caf3048..c9d5a37116a13 100644
--- a/nixos/modules/services/backup/restic-rest-server.nix
+++ b/nixos/modules/services/backup/restic-rest-server.nix
@@ -12,7 +12,7 @@ in
     enable = mkEnableOption (lib.mdDoc "Restic REST Server");
 
     listenAddress = mkOption {
-      default = ":8000";
+      default = "8000";
       example = "127.0.0.1:8080";
       type = types.str;
       description = lib.mdDoc "Listen on a specific IP address and port.";
@@ -61,14 +61,19 @@ in
   };
 
   config = mkIf cfg.enable {
+    assertions = [{
+      assertion = lib.substring 0 1 cfg.listenAddress != ":";
+      message = "The restic-rest-server now uses systemd socket activation, which expects only the Port number: services.restic.server.listenAddress = \"${lib.substring 1 6 cfg.listenAddress}\";";
+    }];
+
     systemd.services.restic-rest-server = {
       description = "Restic REST Server";
-      after = [ "network.target" ];
+      after = [ "network.target" "restic-rest-server.socket" ];
+      requires = [ "restic-rest-server.socket" ];
       wantedBy = [ "multi-user.target" ];
       serviceConfig = {
         ExecStart = ''
           ${cfg.package}/bin/rest-server \
-          --listen ${cfg.listenAddress} \
           --path ${cfg.dataDir} \
           ${optionalString cfg.appendOnly "--append-only"} \
           ${optionalString cfg.privateRepos "--private-repos"} \
@@ -80,16 +85,40 @@ in
         Group = "restic";
 
         # Security hardening
-        ReadWritePaths = [ cfg.dataDir ];
+        CapabilityBoundingSet = "";
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        NoNewPrivileges = true;
+        PrivateNetwork = true;
         PrivateTmp = true;
+        PrivateUsers = true;
+        ProtectClock = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectProc = "invisible";
         ProtectSystem = "strict";
         ProtectKernelTunables = true;
         ProtectKernelModules = true;
         ProtectControlGroups = true;
         PrivateDevices = true;
+        ReadWritePaths = [ cfg.dataDir ];
+        RemoveIPC = true;
+        RestrictAddressFamilies = "none";
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        SystemCallArchitectures = "native";
+        SystemCallFilter = "@system-service";
+        UMask = 027;
       };
     };
 
+    systemd.sockets.restic-rest-server = {
+      listenStreams = [ cfg.listenAddress ];
+      wantedBy = [ "sockets.target" ];
+    };
+
     systemd.tmpfiles.rules = mkIf cfg.privateRepos [
         "f ${cfg.dataDir}/.htpasswd 0700 restic restic -"
     ];
diff --git a/nixos/modules/services/backup/znapzend.nix b/nixos/modules/services/backup/znapzend.nix
index 2ebe8ad2f69ae..f1f7433a39cdd 100644
--- a/nixos/modules/services/backup/znapzend.nix
+++ b/nixos/modules/services/backup/znapzend.nix
@@ -465,5 +465,5 @@ in
     };
   };
 
-  meta.maintainers = with maintainers; [ infinisil SlothOfAnarchy ];
+  meta.maintainers = with maintainers; [ SlothOfAnarchy ];
 }
diff --git a/nixos/modules/services/databases/hbase-standalone.nix b/nixos/modules/services/databases/hbase-standalone.nix
index 08ae7625d50ab..de295a57193f7 100644
--- a/nixos/modules/services/databases/hbase-standalone.nix
+++ b/nixos/modules/services/databases/hbase-standalone.nix
@@ -43,7 +43,7 @@ in {
 
       enable = mkEnableOption (lib.mdDoc ''
         HBase master in standalone mode with embedded regionserver and zookeper.
-        Do not use this configuration for production nor for evaluating HBase performance.
+        Do not use this configuration for production nor for evaluating HBase performance
       '');
 
       package = mkPackageOption pkgs "hbase" { };
diff --git a/nixos/modules/services/databases/lldap.nix b/nixos/modules/services/databases/lldap.nix
index 033de7af886f2..75ce1ca54f87b 100644
--- a/nixos/modules/services/databases/lldap.nix
+++ b/nixos/modules/services/databases/lldap.nix
@@ -6,7 +6,7 @@ let
 in
 {
   options.services.lldap = with lib; {
-    enable = mkEnableOption (mdDoc "lldap");
+    enable = mkEnableOption (mdDoc "lldap, a lightweight authentication server that provides an opinionated, simplified LDAP interface for authentication");
 
     package = mkPackageOption pkgs "lldap" { };
 
diff --git a/nixos/modules/services/databases/victoriametrics.nix b/nixos/modules/services/databases/victoriametrics.nix
index 0ad2028c95b08..3d8ada394d20c 100644
--- a/nixos/modules/services/databases/victoriametrics.nix
+++ b/nixos/modules/services/databases/victoriametrics.nix
@@ -2,7 +2,7 @@
 let cfg = config.services.victoriametrics; in
 {
   options.services.victoriametrics = with lib; {
-    enable = mkEnableOption (lib.mdDoc "victoriametrics");
+    enable = mkEnableOption (lib.mdDoc "VictoriaMetrics, a time series database, long-term remote storage for Prometheus");
     package = mkPackageOption pkgs "victoriametrics" { };
     listenAddress = mkOption {
       default = ":8428";
diff --git a/nixos/modules/services/desktop-managers/plasma6.nix b/nixos/modules/services/desktop-managers/plasma6.nix
index 5f1f2cec79e8d..bc64397d5d882 100644
--- a/nixos/modules/services/desktop-managers/plasma6.nix
+++ b/nixos/modules/services/desktop-managers/plasma6.nix
@@ -170,7 +170,17 @@ in {
         breeze.qt5
         plasma-integration.qt5
         pkgs.plasma5Packages.kwayland-integration
-        pkgs.plasma5Packages.kio
+        (
+          # Only symlink the KIO plugins, so we don't accidentally pull any services
+          # like KCMs or kcookiejar
+          let
+            kioPluginPath = "${pkgs.plasma5Packages.qtbase.qtPluginPrefix}/kf5/kio";
+            inherit (pkgs.plasma5Packages) kio;
+          in pkgs.runCommand "kio5-plugins-only" {} ''
+            mkdir -p $out/${kioPluginPath}
+            ln -s ${kio}/${kioPluginPath}/* $out/${kioPluginPath}
+          ''
+        )
         kio-extras-kf5
       ]
       # Optional hardware support features
@@ -246,11 +256,11 @@ in {
     xdg.portal.configPackages = mkDefault [kdePackages.xdg-desktop-portal-kde];
     services.pipewire.enable = mkDefault true;
 
-    services.xserver.displayManager = {
+    services.displayManager = {
       sessionPackages = [kdePackages.plasma-workspace];
       defaultSession = mkDefault "plasma";
     };
-    services.xserver.displayManager.sddm = {
+    services.displayManager.sddm = {
       package = kdePackages.sddm;
       theme = mkDefault "breeze";
       wayland.compositor = "kwin";
diff --git a/nixos/modules/services/desktops/blueman.nix b/nixos/modules/services/desktops/blueman.nix
index fad2f21bce5bd..f09dd91c9af51 100644
--- a/nixos/modules/services/desktops/blueman.nix
+++ b/nixos/modules/services/desktops/blueman.nix
@@ -9,7 +9,7 @@ in {
   ###### interface
   options = {
     services.blueman = {
-      enable = mkEnableOption (lib.mdDoc "blueman");
+      enable = mkEnableOption (lib.mdDoc "blueman, a bluetooth manager");
     };
   };
 
diff --git a/nixos/modules/services/desktops/deepin/dde-api.nix b/nixos/modules/services/desktops/deepin/dde-api.nix
index 459876febf21f..ece1599f5cc85 100644
--- a/nixos/modules/services/desktops/deepin/dde-api.nix
+++ b/nixos/modules/services/desktops/deepin/dde-api.nix
@@ -15,7 +15,7 @@ with lib;
     services.deepin.dde-api = {
 
       enable = mkEnableOption (lib.mdDoc ''
-        some dbus interfaces that is used for screen zone detecting,
+        the DDE API, which provides some dbus interfaces that is used for screen zone detecting,
         thumbnail generating, and sound playing in Deepin Desktop Environment
       '');
 
diff --git a/nixos/modules/services/desktops/neard.nix b/nixos/modules/services/desktops/neard.nix
index 9130b8d3d216d..846297dfc1ad2 100644
--- a/nixos/modules/services/desktops/neard.nix
+++ b/nixos/modules/services/desktops/neard.nix
@@ -7,7 +7,7 @@ with lib;
   ###### interface
   options = {
     services.neard = {
-      enable = mkEnableOption (lib.mdDoc "neard, NFC daemon");
+      enable = mkEnableOption (lib.mdDoc "neard, an NFC daemon");
     };
   };
 
diff --git a/nixos/modules/services/desktops/zeitgeist.nix b/nixos/modules/services/desktops/zeitgeist.nix
index 0eb2a4c9c371b..caa2835316b03 100644
--- a/nixos/modules/services/desktops/zeitgeist.nix
+++ b/nixos/modules/services/desktops/zeitgeist.nix
@@ -14,7 +14,7 @@ with lib;
 
   options = {
     services.zeitgeist = {
-      enable = mkEnableOption (lib.mdDoc "zeitgeist");
+      enable = mkEnableOption (lib.mdDoc "zeitgeist, a service which logs the users' activities and events");
     };
   };
 
diff --git a/nixos/modules/services/development/distccd.nix b/nixos/modules/services/development/distccd.nix
index c33bf436bffb5..af59e1febd86b 100644
--- a/nixos/modules/services/development/distccd.nix
+++ b/nixos/modules/services/development/distccd.nix
@@ -8,7 +8,7 @@ in
 {
   options = {
     services.distccd = {
-      enable = mkEnableOption (lib.mdDoc "distccd");
+      enable = mkEnableOption (lib.mdDoc "distccd, a distributed C/C++ compiler");
 
       allowedClients = mkOption {
         type = types.listOf types.str;
diff --git a/nixos/modules/services/development/gemstash.nix b/nixos/modules/services/development/gemstash.nix
index eb7ccb98bde89..650c6680ee693 100644
--- a/nixos/modules/services/development/gemstash.nix
+++ b/nixos/modules/services/development/gemstash.nix
@@ -24,7 +24,7 @@ let
 in
 {
   options.services.gemstash = {
-    enable = mkEnableOption (lib.mdDoc "gemstash service");
+    enable = mkEnableOption (lib.mdDoc "gemstash, a cache for rubygems.org and a private gem server");
 
     openFirewall = mkOption {
       type = types.bool;
diff --git a/nixos/modules/services/display-managers/default.nix b/nixos/modules/services/display-managers/default.nix
new file mode 100644
index 0000000000000..7f5db9fbb509b
--- /dev/null
+++ b/nixos/modules/services/display-managers/default.nix
@@ -0,0 +1,257 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.displayManager;
+
+  installedSessions = pkgs.runCommand "desktops"
+    { # trivial derivation
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+    }
+    ''
+      mkdir -p "$out/share/"{xsessions,wayland-sessions}
+
+      ${lib.concatMapStrings (pkg: ''
+        for n in ${lib.concatStringsSep " " pkg.providedSessions}; do
+          if ! test -f ${pkg}/share/wayland-sessions/$n.desktop -o \
+                    -f ${pkg}/share/xsessions/$n.desktop; then
+            echo "Couldn't find provided session name, $n.desktop, in session package ${pkg.name}:"
+            echo "  ${pkg}"
+            return 1
+          fi
+        done
+
+        if test -d ${pkg}/share/xsessions; then
+          ${pkgs.buildPackages.xorg.lndir}/bin/lndir ${pkg}/share/xsessions $out/share/xsessions
+        fi
+        if test -d ${pkg}/share/wayland-sessions; then
+          ${pkgs.buildPackages.xorg.lndir}/bin/lndir ${pkg}/share/wayland-sessions $out/share/wayland-sessions
+        fi
+      '') cfg.sessionPackages}
+    '';
+
+  dmDefault = config.services.xserver.desktopManager.default;
+  # fallback default for cases when only default wm is set
+  dmFallbackDefault = if dmDefault != null then dmDefault else "none";
+  wmDefault = config.services.xserver.windowManager.default;
+  defaultSessionFromLegacyOptions = dmFallbackDefault + lib.optionalString (wmDefault != null && wmDefault != "none") "+${wmDefault}";
+in
+{
+  options = {
+    services.displayManager = {
+      enable = lib.mkEnableOption "systemd's display-manager service";
+
+      preStart = lib.mkOption {
+        type = lib.types.lines;
+        default = "";
+        example = "rm -f /var/log/my-display-manager.log";
+        description = lib.mdDoc "Script executed before the display manager is started.";
+      };
+
+      execCmd = lib.mkOption {
+        type = lib.types.str;
+        example = lib.literalExpression ''"''${pkgs.lightdm}/bin/lightdm"'';
+        description = lib.mdDoc "Command to start the display manager.";
+      };
+
+      environment = lib.mkOption {
+        type = with lib.types; attrsOf unspecified;
+        default = {};
+        description = lib.mdDoc "Additional environment variables needed by the display manager.";
+      };
+
+      hiddenUsers = lib.mkOption {
+        type = with lib.types; listOf str;
+        default = [ "nobody" ];
+        description = lib.mdDoc ''
+          A list of users which will not be shown in the display manager.
+        '';
+      };
+
+      logToFile = lib.mkOption {
+        type = lib.types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Whether the display manager redirects the output of the
+          session script to {file}`~/.xsession-errors`.
+        '';
+      };
+
+      logToJournal = lib.mkOption {
+        type = lib.types.bool;
+        default = true;
+        description = lib.mdDoc ''
+          Whether the display manager redirects the output of the
+          session script to the systemd journal.
+        '';
+      };
+
+      # Configuration for automatic login. Common for all DM.
+      autoLogin = lib.mkOption {
+        type = lib.types.submodule ({ config, options, ... }: {
+          options = {
+            enable = lib.mkOption {
+              type = lib.types.bool;
+              default = config.user != null;
+              defaultText = lib.literalExpression "config.${options.user} != null";
+              description = lib.mdDoc ''
+                Automatically log in as {option}`autoLogin.user`.
+              '';
+            };
+
+            user = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = null;
+              description = lib.mdDoc ''
+                User to be used for the automatic login.
+              '';
+            };
+          };
+        });
+
+        default = {};
+        description = lib.mdDoc ''
+          Auto login configuration attrset.
+        '';
+      };
+
+      defaultSession = lib.mkOption {
+        type = lib.types.nullOr lib.types.str // {
+          description = "session name";
+          check = d:
+            lib.assertMsg (d != null -> (lib.types.str.check d && lib.elem d config.services.displayManager.sessionData.sessionNames)) ''
+                Default graphical session, '${d}', not found.
+                Valid names for 'services.displayManager.defaultSession' are:
+                  ${lib.concatStringsSep "\n  " cfg.displayManager.sessionData.sessionNames}
+              '';
+        };
+        default =
+          if dmDefault != null || wmDefault != null then
+            defaultSessionFromLegacyOptions
+          else
+            null;
+        defaultText = lib.literalMD ''
+          Taken from display manager settings or window manager settings, if either is set.
+        '';
+        example = "gnome";
+        description = lib.mdDoc ''
+          Graphical session to pre-select in the session chooser (only effective for GDM, LightDM and SDDM).
+
+          On GDM, LightDM and SDDM, it will also be used as a session for auto-login.
+        '';
+      };
+
+      sessionData = lib.mkOption {
+        description = lib.mdDoc "Data exported for display managers’ convenience";
+        internal = true;
+        default = {};
+      };
+
+      sessionPackages = lib.mkOption {
+        type = lib.types.listOf (lib.types.package // {
+          description = "package with provided sessions";
+          check = p: lib.assertMsg
+            (lib.types.package.check p && p ? providedSessions
+            && p.providedSessions != [] && lib.all lib.isString p.providedSessions)
+            ''
+              Package, '${p.name}', did not specify any session names, as strings, in
+              'passthru.providedSessions'. This is required when used as a session package.
+
+              The session names can be looked up in:
+                ${p}/share/xsessions
+                ${p}/share/wayland-sessions
+           '';
+        });
+        default = [];
+        description = lib.mdDoc ''
+          A list of packages containing x11 or wayland session files to be passed to the display manager.
+        '';
+      };
+    };
+  };
+
+  imports = [
+    (lib.mkRenamedOptionModule [ "services" "xserver" "displayManager" "autoLogin" ] [ "services" "displayManager" "autoLogin" ])
+    (lib.mkRenamedOptionModule [ "services" "xserver" "displayManager" "defaultSession" ] [ "services" "displayManager" "defaultSession" ])
+    (lib.mkRenamedOptionModule [ "services" "xserver" "displayManager" "job" "environment" ] [ "services" "displayManager" "environment" ])
+    (lib.mkRenamedOptionModule [ "services" "xserver" "displayManager" "job" "execCmd" ] [ "services" "displayManager" "execCmd" ])
+    (lib.mkRenamedOptionModule [ "services" "xserver" "displayManager" "job" "logToFile" ] [ "services" "displayManager" "logToFile" ])
+    (lib.mkRenamedOptionModule [ "services" "xserver" "displayManager" "job" "logToJournal" ] [ "services" "displayManager" "logToJournal" ])
+    (lib.mkRenamedOptionModule [ "services" "xserver" "displayManager" "job" "preStart" ] [ "services" "displayManager" "preStart" ])
+  ];
+
+  config = lib.mkIf cfg.enable {
+    assertions = [
+      { assertion = cfg.autoLogin.enable -> cfg.autoLogin.user != null;
+        message = ''
+          services.displayManager.autoLogin.enable requires services.displayManager.autoLogin.user to be set
+        '';
+      }
+    ];
+
+    warnings =
+      lib.mkIf (dmDefault != null || wmDefault != null) [
+        ''
+          The following options are deprecated:
+            ${lib.concatStringsSep "\n  " (map ({c, t}: t) (lib.filter ({c, t}: c != null) [
+            { c = dmDefault; t = "- services.xserver.desktopManager.default"; }
+            { c = wmDefault; t = "- services.xserver.windowManager.default"; }
+            ]))}
+          Please use
+            services.displayManager.defaultSession = "${defaultSessionFromLegacyOptions}";
+          instead.
+        ''
+      ];
+
+    # Make xsessions and wayland sessions available in XDG_DATA_DIRS
+    # as some programs have behavior that depends on them being present
+    environment.sessionVariables.XDG_DATA_DIRS = lib.mkIf (cfg.sessionPackages != [ ]) [
+      "${cfg.sessionData.desktops}/share"
+    ];
+
+    services.displayManager.sessionData = {
+      desktops = installedSessions;
+      sessionNames = lib.concatMap (p: p.providedSessions) config.services.displayManager.sessionPackages;
+      # We do not want to force users to set defaultSession when they have only single DE.
+      autologinSession =
+        if cfg.defaultSession != null then
+          cfg.defaultSession
+        else if cfg.sessionData.sessionNames != [] then
+          lib.head cfg.sessionData.sessionNames
+        else
+          null;
+    };
+
+    # so that the service won't be enabled when only startx is used
+    systemd.services.display-manager.enable =
+      let dmConf = config.services.xserver.displayManager;
+          noDmUsed = !(dmConf.gdm.enable
+                    || cfg.sddm.enable
+                    || dmConf.xpra.enable
+                    || dmConf.lightdm.enable);
+      in lib.mkIf noDmUsed (lib.mkDefault false);
+
+    systemd.services.display-manager = {
+      description = "Display Manager";
+      after = [ "acpid.service" "systemd-logind.service" "systemd-user-sessions.service" ];
+      restartIfChanged = false;
+
+      environment = lib.optionalAttrs config.hardware.opengl.setLdLibraryPath {
+        LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.addOpenGLRunpath.driverLink ];
+      } // cfg.environment;
+
+      preStart = cfg.preStart;
+      script = lib.mkIf (config.systemd.services.display-manager.enable == true) cfg.execCmd;
+
+      # Stop restarting if the display manager stops (crashes) 2 times
+      # in one minute. Starting X typically takes 3-4s.
+      startLimitIntervalSec = 30;
+      startLimitBurst = 3;
+      serviceConfig = {
+        Restart = "always";
+        RestartSec = "200ms";
+        SyslogIdentifier = "display-manager";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/display-managers/greetd.nix b/nixos/modules/services/display-managers/greetd.nix
index 5ce67c3fb3fd2..0f0205f9e0e48 100644
--- a/nixos/modules/services/display-managers/greetd.nix
+++ b/nixos/modules/services/display-managers/greetd.nix
@@ -8,7 +8,7 @@ let
 in
 {
   options.services.greetd = {
-    enable = mkEnableOption (lib.mdDoc "greetd");
+    enable = mkEnableOption (lib.mdDoc "greetd, a minimal and flexible login manager daemon");
 
     package = mkPackageOption pkgs [ "greetd" "greetd" ] { };
 
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/display-managers/sddm.nix
index a315a3ebf3224..16efec04e6194 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/display-managers/sddm.nix
@@ -2,8 +2,8 @@
 
 let
   xcfg = config.services.xserver;
-  dmcfg = xcfg.displayManager;
-  cfg = dmcfg.sddm;
+  dmcfg = config.services.displayManager;
+  cfg = config.services.displayManager.sddm;
   xEnv = config.systemd.services.display-manager.environment;
 
   sddm = cfg.package.override (old: {
@@ -21,12 +21,12 @@ let
 
   xserverWrapper = pkgs.writeShellScript "xserver-wrapper" ''
     ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)}
-    exec systemd-cat -t xserver-wrapper ${dmcfg.xserverBin} ${toString dmcfg.xserverArgs} "$@"
+    exec systemd-cat -t xserver-wrapper ${xcfg.displayManager.xserverBin} ${toString xcfg.displayManager.xserverArgs} "$@"
   '';
 
   Xsetup = pkgs.writeShellScript "Xsetup" ''
     ${cfg.setupScript}
-    ${dmcfg.setupCommands}
+    ${xcfg.displayManager.setupCommands}
   '';
 
   Xstop = pkgs.writeShellScript "Xstop" ''
@@ -40,7 +40,7 @@ let
       Numlock = if cfg.autoNumlock then "on" else "none"; # on, off none
 
       # Implementation is done via pkgs/applications/display-managers/sddm/sddm-default-session.patch
-      DefaultSession = optionalString (dmcfg.defaultSession != null) "${dmcfg.defaultSession}.desktop";
+      DefaultSession = optionalString (config.services.displayManager.defaultSession != null) "${config.services.displayManager.defaultSession}.desktop";
 
       DisplayServer = if cfg.wayland.enable then "wayland" else "x11";
     } // optionalAttrs (cfg.wayland.compositor == "kwin") {
@@ -66,7 +66,7 @@ let
       HideShells = "/run/current-system/sw/bin/nologin";
     };
 
-    X11 = {
+    X11 = optionalAttrs xcfg.enable {
       MinimumVT = if xcfg.tty != null then xcfg.tty else 7;
       ServerPath = toString xserverWrapper;
       XephyrPath = "${pkgs.xorg.xorgserver.out}/bin/Xephyr";
@@ -128,23 +128,36 @@ let
 in
 {
   imports = [
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "autoLogin" "minimumUid" ] [ "services" "displayManager" "sddm" "autoLogin" "minimumUid" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "autoLogin" "relogin" ] [ "services" "displayManager" "sddm" "autoLogin" "relogin" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "autoNumlock" ] [ "services" "displayManager" "sddm" "autoNumlock" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "enable" ]      [ "services" "displayManager" "sddm" "enable" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "enableHidpi" ] [ "services" "displayManager" "sddm" "enableHidpi" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "extraPackages" ] [ "services" "displayManager" "sddm" "extraPackages" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "package" ]     [ "services" "displayManager" "sddm" "package" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "settings" ]    [ "services" "displayManager" "sddm" "settings" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "setupScript" ] [ "services" "displayManager" "sddm" "setupScript" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "stopScript" ]  [ "services" "displayManager" "sddm" "stopScript" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "theme" ]       [ "services" "displayManager" "sddm" "theme" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "wayland" "enable" ] [ "services" "displayManager" "sddm" "wayland" "enable" ])
+
     (mkRemovedOptionModule
-      [ "services" "xserver" "displayManager" "sddm" "themes" ]
-      "Set the option `services.xserver.displayManager.sddm.package' instead.")
+      [ "services" "displayManager" "sddm" "themes" ]
+      "Set the option `services.displayManager.sddm.package' instead.")
     (mkRenamedOptionModule
-      [ "services" "xserver" "displayManager" "sddm" "autoLogin" "enable" ]
-      [ "services" "xserver" "displayManager" "autoLogin" "enable" ])
+      [ "services" "displayManager" "sddm" "autoLogin" "enable" ]
+      [ "services" "displayManager" "autoLogin" "enable" ])
     (mkRenamedOptionModule
-      [ "services" "xserver" "displayManager" "sddm" "autoLogin" "user" ]
-      [ "services" "xserver" "displayManager" "autoLogin" "user" ])
+      [ "services" "displayManager" "sddm" "autoLogin" "user" ]
+      [ "services" "displayManager" "autoLogin" "user" ])
     (mkRemovedOptionModule
-      [ "services" "xserver" "displayManager" "sddm" "extraConfig" ]
-      "Set the option `services.xserver.displayManager.sddm.settings' instead.")
+      [ "services" "displayManager" "sddm" "extraConfig" ]
+      "Set the option `services.displayManager.sddm.settings' instead.")
   ];
 
   options = {
 
-    services.xserver.displayManager.sddm = {
+    services.displayManager.sddm = {
       enable = mkOption {
         type = types.bool;
         default = false;
@@ -268,19 +281,24 @@ in
 
     assertions = [
       {
-        assertion = xcfg.enable;
+        assertion = xcfg.enable || cfg.wayland.enable;
         message = ''
-          SDDM requires services.xserver.enable to be true
+          SDDM requires either services.xserver.enable or services.displayManager.sddm.wayland.enable to be true
         '';
       }
       {
-        assertion = dmcfg.autoLogin.enable -> autoLoginSessionName != null;
+        assertion = config.services.displayManager.autoLogin.enable -> autoLoginSessionName != null;
         message = ''
-          SDDM auto-login requires that services.xserver.displayManager.defaultSession is set.
+          SDDM auto-login requires that services.displayManager.defaultSession is set.
         '';
       }
     ];
 
+    services.displayManager = {
+      enable = true;
+      execCmd = "exec /run/current-system/sw/bin/sddm";
+    };
+
     security.pam.services = {
       sddm.text = ''
         auth      substack      login
@@ -338,7 +356,6 @@ in
     services = {
       dbus.packages = [ sddm ];
       xserver = {
-        displayManager.job.execCmd = "exec /run/current-system/sw/bin/sddm";
         # To enable user switching, allow sddm to allocate TTYs/displays dynamically.
         tty = null;
         display = null;
diff --git a/nixos/modules/services/finance/odoo.nix b/nixos/modules/services/finance/odoo.nix
index aa9bd0014d985..3a3b3c2fa6eec 100644
--- a/nixos/modules/services/finance/odoo.nix
+++ b/nixos/modules/services/finance/odoo.nix
@@ -9,7 +9,7 @@ in
 {
   options = {
     services.odoo = {
-      enable = mkEnableOption (lib.mdDoc "odoo");
+      enable = mkEnableOption (lib.mdDoc "odoo, an open source ERP and CRM system");
 
       package = mkPackageOption pkgs "odoo" { };
 
diff --git a/nixos/modules/services/games/mchprs.nix b/nixos/modules/services/games/mchprs.nix
index 71e546049c58b..36f7ea71d6351 100644
--- a/nixos/modules/services/games/mchprs.nix
+++ b/nixos/modules/services/games/mchprs.nix
@@ -22,7 +22,7 @@ in
 {
   options = {
     services.mchprs = {
-      enable = mkEnableOption "MCHPRS";
+      enable = mkEnableOption "MCHPRS, a Minecraft server";
 
       declarativeSettings = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/games/openarena.nix b/nixos/modules/services/games/openarena.nix
index 14e485b06a0df..592cec9a552f2 100644
--- a/nixos/modules/services/games/openarena.nix
+++ b/nixos/modules/services/games/openarena.nix
@@ -7,7 +7,7 @@ in
 {
   options = {
     services.openarena = {
-      enable = mkEnableOption (lib.mdDoc "OpenArena");
+      enable = mkEnableOption (lib.mdDoc "OpenArena game server");
       package = lib.mkPackageOption pkgs "openarena" { };
 
       openPorts = mkOption {
diff --git a/nixos/modules/services/hardware/kanata.nix b/nixos/modules/services/hardware/kanata.nix
index 05e76d8432154..fa589f685a028 100644
--- a/nixos/modules/services/hardware/kanata.nix
+++ b/nixos/modules/services/hardware/kanata.nix
@@ -151,7 +151,7 @@ let
 in
 {
   options.services.kanata = {
-    enable = mkEnableOption (mdDoc "kanata");
+    enable = mkEnableOption (mdDoc "kanata, a tool to improve keyboard comfort and usability with advanced customization");
     package = mkPackageOption pkgs "kanata" {
       example = "kanata-with-cmd";
       extraDescription = ''
diff --git a/nixos/modules/services/hardware/lirc.nix b/nixos/modules/services/hardware/lirc.nix
index 5b1a8d10c7299..c182c3895fb87 100644
--- a/nixos/modules/services/hardware/lirc.nix
+++ b/nixos/modules/services/hardware/lirc.nix
@@ -11,7 +11,7 @@ in {
   options = {
     services.lirc = {
 
-      enable = mkEnableOption (lib.mdDoc "LIRC daemon");
+      enable = mkEnableOption (lib.mdDoc "the LIRC daemon, to receive and send infrared signals");
 
       options = mkOption {
         type = types.lines;
diff --git a/nixos/modules/services/hardware/openrgb.nix b/nixos/modules/services/hardware/openrgb.nix
index 81b199e50778e..b400f77049f75 100644
--- a/nixos/modules/services/hardware/openrgb.nix
+++ b/nixos/modules/services/hardware/openrgb.nix
@@ -6,7 +6,7 @@ let
   cfg = config.services.hardware.openrgb;
 in {
   options.services.hardware.openrgb = {
-    enable = mkEnableOption (lib.mdDoc "OpenRGB server");
+    enable = mkEnableOption (lib.mdDoc "OpenRGB server, for RGB lighting control");
 
     package = mkPackageOption pkgs "openrgb" { };
 
diff --git a/nixos/modules/services/hardware/pcscd.nix b/nixos/modules/services/hardware/pcscd.nix
index 77c2d9b53f03d..34df1f3e91ba3 100644
--- a/nixos/modules/services/hardware/pcscd.nix
+++ b/nixos/modules/services/hardware/pcscd.nix
@@ -18,7 +18,7 @@ let
 in
 {
   options.services.pcscd = {
-    enable = mkEnableOption (lib.mdDoc "PCSC-Lite daemon");
+    enable = mkEnableOption (lib.mdDoc "PCSC-Lite daemon, to access smart cards using SCard API (PC/SC)");
 
     plugins = mkOption {
       type = types.listOf types.package;
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 670b9087f1107..2bf86a535fc10 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -200,7 +200,7 @@ in
     };
 
     services.udev = {
-      enable = mkEnableOption (lib.mdDoc "udev") // {
+      enable = mkEnableOption (lib.mdDoc "udev, a device manager for the Linux kernel") // {
         default = true;
       };
 
diff --git a/nixos/modules/services/hardware/undervolt.nix b/nixos/modules/services/hardware/undervolt.nix
index c4d4c6791a21b..ea4d60eac7c2c 100644
--- a/nixos/modules/services/hardware/undervolt.nix
+++ b/nixos/modules/services/hardware/undervolt.nix
@@ -37,7 +37,7 @@ in
     enable = mkEnableOption (lib.mdDoc ''
        Undervolting service for Intel CPUs.
 
-       Warning: This service is not endorsed by Intel and may permanently damage your hardware. Use at your own risk!
+       Warning: This service is not endorsed by Intel and may permanently damage your hardware. Use at your own risk
     '');
 
     verbose = mkOption {
diff --git a/nixos/modules/services/hardware/vdr.nix b/nixos/modules/services/hardware/vdr.nix
index 689d83f7eedcd..0c9cc0abf798d 100644
--- a/nixos/modules/services/hardware/vdr.nix
+++ b/nixos/modules/services/hardware/vdr.nix
@@ -9,7 +9,7 @@ in
   options = {
 
     services.vdr = {
-      enable = mkEnableOption (mdDoc "Start VDR");
+      enable = mkEnableOption (mdDoc "VDR, a video disk recorder");
 
       package = mkPackageOption pkgs "vdr" {
         example = "wrapVdr.override { plugins = with pkgs.vdrPlugins; [ hello ]; }";
diff --git a/nixos/modules/services/home-automation/ebusd.nix b/nixos/modules/services/home-automation/ebusd.nix
index f68a8bdb6bfa2..e1dcfb338421f 100644
--- a/nixos/modules/services/home-automation/ebusd.nix
+++ b/nixos/modules/services/home-automation/ebusd.nix
@@ -44,7 +44,7 @@ in
   meta.maintainers = with maintainers; [ nathan-gs ];
 
   options.services.ebusd = {
-    enable = mkEnableOption (lib.mdDoc "ebusd service");
+    enable = mkEnableOption (lib.mdDoc "ebusd, a daemon for communication with eBUS heating systems");
 
     device = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/home-automation/esphome.nix b/nixos/modules/services/home-automation/esphome.nix
index 3c0fd8aed08a4..ac623cf36b3a9 100644
--- a/nixos/modules/services/home-automation/esphome.nix
+++ b/nixos/modules/services/home-automation/esphome.nix
@@ -24,7 +24,7 @@ in
   meta.maintainers = with maintainers; [ oddlama ];
 
   options.services.esphome = {
-    enable = mkEnableOption (mdDoc "esphome");
+    enable = mkEnableOption (mdDoc "esphome, for making custom firmwares for ESP32/ESP8266");
 
     package = lib.mkPackageOption pkgs "esphome" { };
 
diff --git a/nixos/modules/services/logging/awstats.nix b/nixos/modules/services/logging/awstats.nix
index 708775bfcf03a..642118650c65e 100644
--- a/nixos/modules/services/logging/awstats.nix
+++ b/nixos/modules/services/logging/awstats.nix
@@ -95,7 +95,7 @@ in
   ];
 
   options.services.awstats = {
-    enable = mkEnableOption (lib.mdDoc "awstats");
+    enable = mkEnableOption (lib.mdDoc "awstats, a real-time logfile analyzer");
 
     dataDir = mkOption {
       type = types.path;
diff --git a/nixos/modules/services/logging/fluentd.nix b/nixos/modules/services/logging/fluentd.nix
index c8718f26db383..cfc584309835c 100644
--- a/nixos/modules/services/logging/fluentd.nix
+++ b/nixos/modules/services/logging/fluentd.nix
@@ -12,7 +12,7 @@ in {
   options = {
 
     services.fluentd = {
-      enable = mkEnableOption (lib.mdDoc "fluentd");
+      enable = mkEnableOption (lib.mdDoc "fluentd, a data/log collector");
 
       config = mkOption {
         type = types.lines;
diff --git a/nixos/modules/services/logging/graylog.nix b/nixos/modules/services/logging/graylog.nix
index 673930c4cb5c6..853539d4d63bf 100644
--- a/nixos/modules/services/logging/graylog.nix
+++ b/nixos/modules/services/logging/graylog.nix
@@ -33,7 +33,7 @@ in
 
     services.graylog = {
 
-      enable = mkEnableOption (lib.mdDoc "Graylog");
+      enable = mkEnableOption (lib.mdDoc "Graylog, a log management solution");
 
       package = mkOption {
         type = types.package;
diff --git a/nixos/modules/services/logging/heartbeat.nix b/nixos/modules/services/logging/heartbeat.nix
index 768ffe5315fe0..84c15b1caeb28 100644
--- a/nixos/modules/services/logging/heartbeat.nix
+++ b/nixos/modules/services/logging/heartbeat.nix
@@ -18,7 +18,7 @@ in
 
     services.heartbeat = {
 
-      enable = mkEnableOption (lib.mdDoc "heartbeat");
+      enable = mkEnableOption (lib.mdDoc "heartbeat, uptime monitoring");
 
       package = mkPackageOption pkgs "heartbeat" {
         example = "heartbeat7";
diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix
index 5d87fc87d4161..44763afa9d238 100644
--- a/nixos/modules/services/logging/logcheck.nix
+++ b/nixos/modules/services/logging/logcheck.nix
@@ -109,7 +109,7 @@ in
 {
   options = {
     services.logcheck = {
-      enable = mkEnableOption (lib.mdDoc "logcheck cron job");
+      enable = mkEnableOption (lib.mdDoc "logcheck cron job, to mail anomalies in the system logfiles to the administrator");
 
       user = mkOption {
         default = "logcheck";
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
index ba1445f083975..49cca0cb8112a 100644
--- a/nixos/modules/services/logging/logrotate.nix
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -104,9 +104,12 @@ in
         default = { };
         description = lib.mdDoc ''
           logrotate freeform settings: each attribute here will define its own section,
-          ordered by priority, which can either define files to rotate with their settings
+          ordered by {option}`services.logrotate.settings.<name>.priority`,
+          which can either define files to rotate with their settings
           or settings common to all further files settings.
-          Refer to <https://linux.die.net/man/8/logrotate> for details.
+          All attribute names not explicitly defined as sub-options here are passed through
+          as logrotate config directives,
+          refer to <https://linux.die.net/man/8/logrotate> for details.
         '';
         example = literalExpression ''
           {
@@ -125,6 +128,14 @@ in
                 "/var/log/second.log"
               ];
             };
+            # specify custom order of sections
+            "/var/log/myservice/*.log" = {
+              # ensure lower priority
+              priority = 110;
+              postrotate = '''
+                systemctl reload myservice
+              ''';
+            };
           };
           '';
         type = types.attrsOf (types.submodule ({ name, ... }: {
diff --git a/nixos/modules/services/logging/ulogd.nix b/nixos/modules/services/logging/ulogd.nix
index 05c9797bb28bc..9beb0859cef52 100644
--- a/nixos/modules/services/logging/ulogd.nix
+++ b/nixos/modules/services/logging/ulogd.nix
@@ -8,7 +8,7 @@ let
 in {
   options = {
     services.ulogd = {
-      enable = mkEnableOption (lib.mdDoc "ulogd");
+      enable = mkEnableOption (lib.mdDoc "ulogd, a userspace logging daemon for netfilter/iptables related logging");
 
       settings = mkOption {
         example = {
diff --git a/nixos/modules/services/logging/vector.nix b/nixos/modules/services/logging/vector.nix
index 9ccf8a4fa0610..92605c4030873 100644
--- a/nixos/modules/services/logging/vector.nix
+++ b/nixos/modules/services/logging/vector.nix
@@ -6,7 +6,7 @@ let cfg = config.services.vector;
 in
 {
   options.services.vector = {
-    enable = mkEnableOption (lib.mdDoc "Vector");
+    enable = mkEnableOption (lib.mdDoc "Vector, a high-performance observability data pipeline");
 
     package = mkPackageOption pkgs "vector" { };
 
diff --git a/nixos/modules/services/mail/goeland.nix b/nixos/modules/services/mail/goeland.nix
index 13092a65ed90e..a39d0d27d537b 100644
--- a/nixos/modules/services/mail/goeland.nix
+++ b/nixos/modules/services/mail/goeland.nix
@@ -8,7 +8,7 @@ let
 in
 {
   options.services.goeland = {
-    enable = mkEnableOption (mdDoc "goeland");
+    enable = mkEnableOption (mdDoc "goeland, an alternative to rss2email");
 
     settings = mkOption {
       description = mdDoc ''
diff --git a/nixos/modules/services/mail/mailcatcher.nix b/nixos/modules/services/mail/mailcatcher.nix
index d0f4550c19264..60abf3f2c5a02 100644
--- a/nixos/modules/services/mail/mailcatcher.nix
+++ b/nixos/modules/services/mail/mailcatcher.nix
@@ -11,7 +11,7 @@ in
   options = {
 
     services.mailcatcher = {
-      enable = mkEnableOption (lib.mdDoc "MailCatcher");
+      enable = mkEnableOption (lib.mdDoc "MailCatcher, an SMTP server and web interface to locally test outbound emails");
 
       http.ip = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/mail/mailhog.nix b/nixos/modules/services/mail/mailhog.nix
index 7ae62de291bab..14df891fbb1a4 100644
--- a/nixos/modules/services/mail/mailhog.nix
+++ b/nixos/modules/services/mail/mailhog.nix
@@ -27,7 +27,7 @@ in
   options = {
 
     services.mailhog = {
-      enable = mkEnableOption (lib.mdDoc "MailHog");
+      enable = mkEnableOption (lib.mdDoc "MailHog, web and API based SMTP testing");
 
       storage = mkOption {
         type = types.enum [ "maildir" "memory" ];
diff --git a/nixos/modules/services/matrix/mautrix-meta.nix b/nixos/modules/services/matrix/mautrix-meta.nix
new file mode 100644
index 0000000000000..f0905c3af1297
--- /dev/null
+++ b/nixos/modules/services/matrix/mautrix-meta.nix
@@ -0,0 +1,562 @@
+{ config, pkgs, lib, ... }:
+
+let
+  settingsFormat = pkgs.formats.yaml {};
+
+  upperConfig = config;
+  cfg = config.services.mautrix-meta;
+  upperCfg = cfg;
+
+  fullDataDir = cfg: "/var/lib/${cfg.dataDir}";
+
+  settingsFile = cfg: "${fullDataDir cfg}/config.yaml";
+  settingsFileUnsubstituted = cfg: settingsFormat.generate "mautrix-meta-config.yaml" cfg.settings;
+
+  metaName = name: "mautrix-meta-${name}";
+
+  enabledInstances = lib.filterAttrs (name: config: config.enable) config.services.mautrix-meta.instances;
+  registerToSynapseInstances = lib.filterAttrs (name: config: config.enable && config.registerToSynapse) config.services.mautrix-meta.instances;
+in {
+  options = {
+    services.mautrix-meta = {
+
+      package = lib.mkPackageOption pkgs "mautrix-meta" { };
+
+      instances = lib.mkOption {
+        type = lib.types.attrsOf (lib.types.submodule ({ config, name, ... }: {
+
+          options = {
+
+            enable = lib.mkEnableOption "Mautrix-Meta, a Matrix <-> Facebook and Matrix <-> Instagram hybrid puppeting/relaybot bridge";
+
+            dataDir = lib.mkOption {
+              type = lib.types.str;
+              default = metaName name;
+              description = ''
+                Path to the directory with database, registration, and other data for the bridge service.
+                This path is relative to `/var/lib`, it cannot start with `../` (it cannot be outside of `/var/lib`).
+              '';
+            };
+
+            registrationFile = lib.mkOption {
+              type = lib.types.path;
+              readOnly = true;
+              description = ''
+                Path to the yaml registration file of the appservice.
+              '';
+            };
+
+            registerToSynapse = lib.mkOption {
+              type = lib.types.bool;
+              default = true;
+              description = ''
+                Whether to add registration file to `services.matrix-synapse.settings.app_service_config_files` and
+                make Synapse wait for registration service.
+              '';
+            };
+
+            settings = lib.mkOption rec {
+              apply = lib.recursiveUpdate default;
+              inherit (settingsFormat) type;
+              default = {
+                homeserver = {
+                  software = "standard";
+
+                  domain = "";
+                  address = "";
+                };
+
+                appservice = {
+                  id = "";
+
+                  database = {
+                    type = "sqlite3-fk-wal";
+                    uri = "file:${fullDataDir config}/mautrix-meta.db?_txlock=immediate";
+                  };
+
+                  bot = {
+                    username = "";
+                  };
+
+                  hostname = "localhost";
+                  port = 29319;
+                  address = "http://${config.settings.appservice.hostname}:${toString config.settings.appservice.port}";
+                };
+
+                meta = {
+                  mode = "";
+                };
+
+                bridge = {
+                  # Enable encryption by default to make the bridge more secure
+                  encryption = {
+                    allow = true;
+                    default = true;
+                    require = true;
+
+                    # Recommended options from mautrix documentation
+                    # for additional security.
+                    delete_keys = {
+                      dont_store_outbound = true;
+                      ratchet_on_decrypt = true;
+                      delete_fully_used_on_decrypt = true;
+                      delete_prev_on_new_session = true;
+                      delete_on_device_delete = true;
+                      periodically_delete_expired = true;
+                      delete_outdated_inbound = true;
+                    };
+
+                    verification_levels = {
+                      receive = "cross-signed-tofu";
+                      send = "cross-signed-tofu";
+                      share = "cross-signed-tofu";
+                    };
+                  };
+
+                  permissions = {};
+                };
+
+                logging = {
+                  min_level = "info";
+                  writers = lib.singleton {
+                    type = "stdout";
+                    format = "pretty-colored";
+                    time_format = " ";
+                  };
+                };
+              };
+              defaultText = ''
+              {
+                homeserver = {
+                  software = "standard";
+                  address = "https://''${config.settings.homeserver.domain}";
+                };
+
+                appservice = {
+                  database = {
+                    type = "sqlite3-fk-wal";
+                    uri = "file:''${fullDataDir config}/mautrix-meta.db?_txlock=immediate";
+                  };
+
+                  hostname = "localhost";
+                  port = 29319;
+                  address = "http://''${config.settings.appservice.hostname}:''${toString config.settings.appservice.port}";
+                };
+
+                bridge = {
+                  # Require encryption by default to make the bridge more secure
+                  encryption = {
+                    allow = true;
+                    default = true;
+                    require = true;
+
+                    # Recommended options from mautrix documentation
+                    # for optimal security.
+                    delete_keys = {
+                      dont_store_outbound = true;
+                      ratchet_on_decrypt = true;
+                      delete_fully_used_on_decrypt = true;
+                      delete_prev_on_new_session = true;
+                      delete_on_device_delete = true;
+                      periodically_delete_expired = true;
+                      delete_outdated_inbound = true;
+                    };
+
+                    verification_levels = {
+                      receive = "cross-signed-tofu";
+                      send = "cross-signed-tofu";
+                      share = "cross-signed-tofu";
+                    };
+                  };
+                };
+
+                logging = {
+                  min_level = "info";
+                  writers = lib.singleton {
+                    type = "stdout";
+                    format = "pretty-colored";
+                    time_format = " ";
+                  };
+                };
+              };
+              '';
+              description = ''
+                {file}`config.yaml` configuration as a Nix attribute set.
+                Configuration options should match those described in
+                [example-config.yaml](https://github.com/mautrix/meta/blob/main/example-config.yaml).
+
+                Secret tokens should be specified using {option}`environmentFile`
+                instead
+              '';
+            };
+
+            environmentFile = lib.mkOption {
+              type = lib.types.nullOr lib.types.path;
+              default = null;
+              description = ''
+                File containing environment variables to substitute when copying the configuration
+                out of Nix store to the `services.mautrix-meta.dataDir`.
+
+                Can be used for storing the secrets without making them available in the Nix store.
+
+                For example, you can set `services.mautrix-meta.settings.appservice.as_token = "$MAUTRIX_META_APPSERVICE_AS_TOKEN"`
+                and then specify `MAUTRIX_META_APPSERVICE_AS_TOKEN="{token}"` in the environment file.
+                This value will get substituted into the configuration file as as token.
+              '';
+            };
+
+            serviceDependencies = lib.mkOption {
+              type = lib.types.listOf lib.types.str;
+              default =
+                [ config.registrationServiceUnit ] ++
+                (lib.lists.optional upperConfig.services.matrix-synapse.enable upperConfig.services.matrix-synapse.serviceUnit) ++
+                (lib.lists.optional upperConfig.services.matrix-conduit.enable "matrix-conduit.service") ++
+                (lib.lists.optional upperConfig.services.dendrite.enable "dendrite.service");
+
+              defaultText = ''
+                [ config.registrationServiceUnit ] ++
+                (lib.lists.optional upperConfig.services.matrix-synapse.enable upperConfig.services.matrix-synapse.serviceUnit) ++
+                (lib.lists.optional upperConfig.services.matrix-conduit.enable "matrix-conduit.service") ++
+                (lib.lists.optional upperConfig.services.dendrite.enable "dendrite.service");
+              '';
+              description = ''
+                List of Systemd services to require and wait for when starting the application service.
+              '';
+            };
+
+            serviceUnit = lib.mkOption {
+              type = lib.types.str;
+              readOnly = true;
+              description = ''
+                The systemd unit (a service or a target) for other services to depend on if they
+                need to be started after matrix-synapse.
+
+                This option is useful as the actual parent unit for all matrix-synapse processes
+                changes when configuring workers.
+              '';
+            };
+
+            registrationServiceUnit = lib.mkOption {
+              type = lib.types.str;
+              readOnly = true;
+              description = ''
+                The registration service that generates the registration file.
+
+                Systemd unit (a service or a target) for other services to depend on if they
+                need to be started after mautrix-meta registration service.
+
+                This option is useful as the actual parent unit for all matrix-synapse processes
+                changes when configuring workers.
+              '';
+            };
+          };
+
+          config = {
+            serviceUnit = (metaName name) + ".service";
+            registrationServiceUnit = (metaName name) + "-registration.service";
+            registrationFile = (fullDataDir config) + "/meta-registration.yaml";
+          };
+        }));
+
+        description = ''
+          Configuration of multiple `mautrix-meta` instances.
+          `services.mautrix-meta.instances.facebook` and `services.mautrix-meta.instances.instagram`
+          come preconfigured with meta.mode, appservice.id, bot username, display name and avatar.
+        '';
+
+        example = ''
+          {
+            facebook = {
+              enable = true;
+              settings = {
+                homeserver.domain = "example.com";
+              };
+            };
+
+            instagram = {
+              enable = true;
+              settings = {
+                homeserver.domain = "example.com";
+              };
+            };
+
+            messenger = {
+              enable = true;
+              settings = {
+                meta.mode = "messenger";
+                homeserver.domain = "example.com";
+                appservice = {
+                  id = "messenger";
+                  bot = {
+                    username = "messengerbot";
+                    displayname = "Messenger bridge bot";
+                    avatar = "mxc://maunium.net/ygtkteZsXnGJLJHRchUwYWak";
+                  };
+                };
+              };
+            };
+          }
+        '';
+      };
+    };
+  };
+
+  config = lib.mkMerge [
+    (lib.mkIf (enabledInstances != {}) {
+      assertions = lib.mkMerge (lib.attrValues (lib.mapAttrs (name: cfg: [
+        {
+          assertion = cfg.settings.homeserver.domain != "" && cfg.settings.homeserver.address != "";
+          message = ''
+            The options with information about the homeserver:
+            `services.mautrix-meta.instances.${name}.settings.homeserver.domain` and
+            `services.mautrix-meta.instances.${name}.settings.homeserver.address` have to be set.
+          '';
+        }
+        {
+          assertion = builtins.elem cfg.settings.meta.mode [ "facebook" "facebook-tor" "messenger" "instagram" ];
+          message = ''
+            The option `services.mautrix-meta.instances.${name}.settings.meta.mode` has to be set
+            to one of: facebook, facebook-tor, messenger, instagram.
+            This configures the mode of the bridge.
+          '';
+        }
+        {
+          assertion = cfg.settings.bridge.permissions != {};
+          message = ''
+            The option `services.mautrix-meta.instances.${name}.settings.bridge.permissions` has to be set.
+          '';
+        }
+        {
+          assertion = cfg.settings.appservice.id != "";
+          message = ''
+            The option `services.mautrix-meta.instances.${name}.settings.appservice.id` has to be set.
+          '';
+        }
+        {
+          assertion = cfg.settings.appservice.bot.username != "";
+          message = ''
+            The option `services.mautrix-meta.instances.${name}.settings.appservice.bot.username` has to be set.
+          '';
+        }
+      ]) enabledInstances));
+
+      users.users = lib.mapAttrs' (name: cfg: lib.nameValuePair "mautrix-meta-${name}" {
+        isSystemUser = true;
+        group = "mautrix-meta";
+        extraGroups = [ "mautrix-meta-registration" ];
+        description = "Mautrix-Meta-${name} bridge user";
+      }) enabledInstances;
+
+      users.groups.mautrix-meta = {};
+      users.groups.mautrix-meta-registration = {
+        members = lib.lists.optional config.services.matrix-synapse.enable "matrix-synapse";
+      };
+
+      services.matrix-synapse = lib.mkIf (config.services.matrix-synapse.enable) (let
+        registrationFiles = lib.attrValues
+          (lib.mapAttrs (name: cfg: cfg.registrationFile) registerToSynapseInstances);
+      in {
+        settings.app_service_config_files = registrationFiles;
+      });
+
+      systemd.services = lib.mkMerge [
+        {
+          matrix-synapse = lib.mkIf (config.services.matrix-synapse.enable) (let
+            registrationServices = lib.attrValues
+              (lib.mapAttrs (name: cfg: cfg.registrationServiceUnit) registerToSynapseInstances);
+          in {
+            wants = registrationServices;
+            after = registrationServices;
+          });
+        }
+
+        (lib.mapAttrs' (name: cfg: lib.nameValuePair "${metaName name}-registration" {
+          description = "Mautrix-Meta registration generation service - ${metaName name}";
+
+          path = [
+            pkgs.yq
+            pkgs.envsubst
+            upperCfg.package
+          ];
+
+          script = ''
+            # substitute the settings file by environment variables
+            # in this case read from EnvironmentFile
+            rm -f '${settingsFile cfg}'
+            old_umask=$(umask)
+            umask 0177
+            envsubst \
+              -o '${settingsFile cfg}' \
+              -i '${settingsFileUnsubstituted cfg}'
+
+            config_has_tokens=$(yq '.appservice | has("as_token") and has("hs_token")' '${settingsFile cfg}')
+            registration_already_exists=$([[ -f '${cfg.registrationFile}' ]] && echo "true" || echo "false")
+
+            echo "There are tokens in the config: $config_has_tokens"
+            echo "Registration already existed: $registration_already_exists"
+
+            # tokens not configured from config/environment file, and registration file
+            # is already generated, override tokens in config to make sure they are not lost
+            if [[ $config_has_tokens == "false" && $registration_already_exists == "true" ]]; then
+              echo "Copying as_token, hs_token from registration into configuration"
+              yq -sY '.[0].appservice.as_token = .[1].as_token
+                | .[0].appservice.hs_token = .[1].hs_token
+                | .[0]' '${settingsFile cfg}' '${cfg.registrationFile}' \
+                > '${settingsFile cfg}.tmp'
+              mv '${settingsFile cfg}.tmp' '${settingsFile cfg}'
+            fi
+
+            # make sure --generate-registration does not affect config.yaml
+            cp '${settingsFile cfg}' '${settingsFile cfg}.tmp'
+
+            echo "Generating registration file"
+            mautrix-meta \
+              --generate-registration \
+              --config='${settingsFile cfg}.tmp' \
+              --registration='${cfg.registrationFile}'
+
+            rm '${settingsFile cfg}.tmp'
+
+            # no tokens configured, and new were just generated by generate registration for first time
+            if [[ $config_has_tokens == "false" && $registration_already_exists == "false" ]]; then
+              echo "Copying newly generated as_token, hs_token from registration into configuration"
+              yq -sY '.[0].appservice.as_token = .[1].as_token
+                | .[0].appservice.hs_token = .[1].hs_token
+                | .[0]' '${settingsFile cfg}' '${cfg.registrationFile}' \
+                > '${settingsFile cfg}.tmp'
+              mv '${settingsFile cfg}.tmp' '${settingsFile cfg}'
+            fi
+
+            # Make sure correct tokens are in the registration file
+            if [[ $config_has_tokens == "true" || $registration_already_exists == "true" ]]; then
+              echo "Copying as_token, hs_token from configuration to the registration file"
+              yq -sY '.[1].as_token = .[0].appservice.as_token
+                | .[1].hs_token = .[0].appservice.hs_token
+                | .[1]' '${settingsFile cfg}' '${cfg.registrationFile}' \
+                > '${cfg.registrationFile}.tmp'
+              mv '${cfg.registrationFile}.tmp' '${cfg.registrationFile}'
+            fi
+
+            umask $old_umask
+
+            chown :mautrix-meta-registration '${cfg.registrationFile}'
+            chmod 640 '${cfg.registrationFile}'
+          '';
+
+          serviceConfig = {
+            Type = "oneshot";
+            UMask = 0027;
+
+            User = "mautrix-meta-${name}";
+            Group = "mautrix-meta";
+
+            SystemCallFilter = [ "@system-service" ];
+
+            ProtectSystem = "strict";
+            ProtectHome = true;
+
+            ReadWritePaths = fullDataDir cfg;
+            StateDirectory = cfg.dataDir;
+            EnvironmentFile = cfg.environmentFile;
+          };
+
+          restartTriggers = [ (settingsFileUnsubstituted cfg) ];
+        }) enabledInstances)
+
+        (lib.mapAttrs' (name: cfg: lib.nameValuePair "${metaName name}" {
+          description = "Mautrix-Meta bridge - ${metaName name}";
+          wantedBy = [ "multi-user.target" ];
+          wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
+          after = [ "network-online.target" ] ++ cfg.serviceDependencies;
+
+          serviceConfig = {
+            Type = "simple";
+
+            User = "mautrix-meta-${name}";
+            Group = "mautrix-meta";
+            PrivateUsers = true;
+
+            LockPersonality = true;
+            MemoryDenyWriteExecute = true;
+            NoNewPrivileges = true;
+            PrivateDevices = true;
+            PrivateTmp = true;
+            ProtectClock = true;
+            ProtectControlGroups = true;
+            ProtectHome = true;
+            ProtectHostname = true;
+            ProtectKernelLogs = true;
+            ProtectKernelModules = true;
+            ProtectKernelTunables = true;
+            ProtectSystem = "strict";
+            Restart = "on-failure";
+            RestartSec = "30s";
+            RestrictRealtime = true;
+            RestrictSUIDSGID = true;
+            SystemCallArchitectures = "native";
+            SystemCallErrorNumber = "EPERM";
+            SystemCallFilter = ["@system-service"];
+            UMask = 0027;
+
+            WorkingDirectory = fullDataDir cfg;
+            ReadWritePaths = fullDataDir cfg;
+            StateDirectory = cfg.dataDir;
+            EnvironmentFile = cfg.environmentFile;
+
+            ExecStart = lib.escapeShellArgs [
+              (lib.getExe upperCfg.package)
+              "--config=${settingsFile cfg}"
+            ];
+          };
+          restartTriggers = [ (settingsFileUnsubstituted cfg) ];
+        }) enabledInstances)
+      ];
+    })
+    {
+      services.mautrix-meta.instances = let
+        inherit (lib.modules) mkDefault;
+      in {
+        instagram = {
+          settings = {
+            meta.mode = mkDefault "instagram";
+
+            bridge = {
+              username_template = mkDefault "instagram_{{.}}";
+            };
+
+            appservice = {
+              id = mkDefault "instagram";
+              port = mkDefault 29320;
+              bot = {
+                username = mkDefault "instagrambot";
+                displayname = mkDefault "Instagram bridge bot";
+                avatar = mkDefault "mxc://maunium.net/JxjlbZUlCPULEeHZSwleUXQv";
+              };
+            };
+          };
+        };
+        facebook = {
+          settings = {
+            meta.mode = mkDefault "facebook";
+
+            bridge = {
+              username_template = mkDefault "facebook_{{.}}";
+            };
+
+            appservice = {
+              id = mkDefault "facebook";
+              port = mkDefault 29321;
+              bot = {
+                username = mkDefault "facebookbot";
+                displayname = mkDefault "Facebook bridge bot";
+                avatar = mkDefault "mxc://maunium.net/ygtkteZsXnGJLJHRchUwYWak";
+              };
+            };
+          };
+        };
+      };
+    }
+  ];
+
+  meta.maintainers = with lib.maintainers; [ rutherther ];
+}
diff --git a/nixos/modules/services/matrix/synapse.nix b/nixos/modules/services/matrix/synapse.nix
index 7291c0fcbcdda..e6b8462642dda 100644
--- a/nixos/modules/services/matrix/synapse.nix
+++ b/nixos/modules/services/matrix/synapse.nix
@@ -367,7 +367,7 @@ in {
     });
   in {
     services.matrix-synapse = {
-      enable = mkEnableOption (lib.mdDoc "matrix.org synapse");
+      enable = mkEnableOption (lib.mdDoc "matrix.org synapse, the reference homeserver");
 
       enableRegistrationScript = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/misc/ankisyncd.nix b/nixos/modules/services/misc/ankisyncd.nix
index f5acfbb0ee969..cb8671ebc5e67 100644
--- a/nixos/modules/services/misc/ankisyncd.nix
+++ b/nixos/modules/services/misc/ankisyncd.nix
@@ -22,7 +22,7 @@ let
 in
   {
     options.services.ankisyncd = {
-      enable = mkEnableOption (lib.mdDoc "ankisyncd");
+      enable = mkEnableOption (lib.mdDoc "ankisyncd, a standalone unofficial anky sync server");
 
       package = mkPackageOption pkgs "ankisyncd" { };
 
diff --git a/nixos/modules/services/misc/autorandr.nix b/nixos/modules/services/misc/autorandr.nix
index aa96acb613067..22d1fb727477c 100644
--- a/nixos/modules/services/misc/autorandr.nix
+++ b/nixos/modules/services/misc/autorandr.nix
@@ -260,6 +260,12 @@ in {
         description = lib.mdDoc "Treat outputs as connected even if their lids are closed";
       };
 
+      matchEdid = mkOption {
+        default = false;
+        type = types.bool;
+        description = lib.mdDoc "Match displays based on edid instead of name";
+      };
+
       hooks = mkOption {
         type = hooksModule;
         description = lib.mdDoc "Global hook scripts";
@@ -351,7 +357,8 @@ in {
             --batch \
             --change \
             --default ${cfg.defaultTarget} \
-            ${optionalString cfg.ignoreLid "--ignore-lid"}
+            ${optionalString cfg.ignoreLid "--ignore-lid"} \
+            ${optionalString cfg.matchEdid "--match-edid"}
         '';
         Type = "oneshot";
         RemainAfterExit = false;
diff --git a/nixos/modules/services/misc/bepasty.nix b/nixos/modules/services/misc/bepasty.nix
index 70d07629493b6..1061a78983784 100644
--- a/nixos/modules/services/misc/bepasty.nix
+++ b/nixos/modules/services/misc/bepasty.nix
@@ -13,7 +13,7 @@ let
 in
 {
   options.services.bepasty = {
-    enable = mkEnableOption (lib.mdDoc "Bepasty servers");
+    enable = mkEnableOption (lib.mdDoc "bepasty, a binary pastebin server");
 
     servers = mkOption {
       default = {};
diff --git a/nixos/modules/services/misc/calibre-server.nix b/nixos/modules/services/misc/calibre-server.nix
index 66ae5fa91bb68..efc4b17c88747 100644
--- a/nixos/modules/services/misc/calibre-server.nix
+++ b/nixos/modules/services/misc/calibre-server.nix
@@ -32,7 +32,7 @@ in
   options = {
     services.calibre-server = {
 
-      enable = mkEnableOption (lib.mdDoc "calibre-server");
+      enable = mkEnableOption (lib.mdDoc "calibre-server (e-book software)");
       package = lib.mkPackageOption pkgs "calibre" { };
 
       libraries = mkOption {
diff --git a/nixos/modules/services/misc/confd.nix b/nixos/modules/services/misc/confd.nix
index 93731547ede8b..98776f6e839f7 100644
--- a/nixos/modules/services/misc/confd.nix
+++ b/nixos/modules/services/misc/confd.nix
@@ -17,7 +17,7 @@ let
 
 in {
   options.services.confd = {
-    enable = mkEnableOption (lib.mdDoc "confd service");
+    enable = mkEnableOption (lib.mdDoc "confd, a service to manage local application configuration files using templates and data from etcd/consul/redis/zookeeper");
 
     backend = mkOption {
       description = lib.mdDoc "Confd config storage backend to use.";
diff --git a/nixos/modules/services/misc/etesync-dav.nix b/nixos/modules/services/misc/etesync-dav.nix
index ae2b5ad043433..ef2ba9086af46 100644
--- a/nixos/modules/services/misc/etesync-dav.nix
+++ b/nixos/modules/services/misc/etesync-dav.nix
@@ -7,7 +7,7 @@ let
 in
   {
     options.services.etesync-dav = {
-      enable = mkEnableOption (lib.mdDoc "etesync-dav");
+      enable = mkEnableOption (lib.mdDoc "etesync-dav, end-to-end encrypted sync for contacts, calendars and tasks");
 
       host = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/evdevremapkeys.nix b/nixos/modules/services/misc/evdevremapkeys.nix
index 11ea6a5f03f23..d623c038b174f 100644
--- a/nixos/modules/services/misc/evdevremapkeys.nix
+++ b/nixos/modules/services/misc/evdevremapkeys.nix
@@ -8,7 +8,7 @@ let
 in
 {
   options.services.evdevremapkeys = {
-    enable = mkEnableOption (lib.mdDoc ''evdevremapkeys'');
+    enable = mkEnableOption (lib.mdDoc ''evdevremapkeys, a daemon to remap events on linux input devices'');
 
     settings = mkOption {
       type = format.type;
diff --git a/nixos/modules/services/misc/forgejo.nix b/nixos/modules/services/misc/forgejo.nix
index 2b1700626870f..d9fd33ddedb1a 100644
--- a/nixos/modules/services/misc/forgejo.nix
+++ b/nixos/modules/services/misc/forgejo.nix
@@ -55,7 +55,7 @@ in
 
   options = {
     services.forgejo = {
-      enable = mkEnableOption (mdDoc "Forgejo");
+      enable = mkEnableOption (mdDoc "Forgejo, a software forge");
 
       package = mkPackageOption pkgs "forgejo" { };
 
diff --git a/nixos/modules/services/misc/geoipupdate.nix b/nixos/modules/services/misc/geoipupdate.nix
index 27c1157e9a8c7..f18645ffb5895 100644
--- a/nixos/modules/services/misc/geoipupdate.nix
+++ b/nixos/modules/services/misc/geoipupdate.nix
@@ -12,7 +12,7 @@ in
   options = {
     services.geoipupdate = {
       enable = lib.mkEnableOption (lib.mdDoc ''
-        periodic downloading of GeoIP databases using geoipupdate.
+        periodic downloading of GeoIP databases using geoipupdate
       '');
 
       interval = lib.mkOption {
diff --git a/nixos/modules/services/misc/gollum.nix b/nixos/modules/services/misc/gollum.nix
index e31eeaf8a30a8..04ac89970e3f6 100644
--- a/nixos/modules/services/misc/gollum.nix
+++ b/nixos/modules/services/misc/gollum.nix
@@ -8,7 +8,7 @@ in
 
 {
   options.services.gollum = {
-    enable = mkEnableOption (lib.mdDoc "Gollum service");
+    enable = mkEnableOption (lib.mdDoc "Gollum, a git-powered wiki service");
 
     address = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/misc/graphical-desktop.nix b/nixos/modules/services/misc/graphical-desktop.nix
new file mode 100644
index 0000000000000..a88c02e610bf4
--- /dev/null
+++ b/nixos/modules/services/misc/graphical-desktop.nix
@@ -0,0 +1,54 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+let
+  xcfg = config.services.xserver;
+  dmcfg = config.services.displayManager;
+in
+{
+  config = lib.mkIf (xcfg.enable || dmcfg.enable) {
+    # The default max inotify watches is 8192.
+    # Nowadays most apps require a good number of inotify watches,
+    # the value below is used by default on several other distros.
+    boot.kernel.sysctl = {
+      "fs.inotify.max_user_instances" = lib.mkDefault 524288;
+      "fs.inotify.max_user_watches" = lib.mkDefault 524288;
+    };
+
+    environment = {
+      # localectl looks into 00-keyboard.conf
+      etc."X11/xorg.conf.d/00-keyboard.conf".text = ''
+        Section "InputClass"
+          Identifier "Keyboard catchall"
+          MatchIsKeyboard "on"
+          Option "XkbModel" "${xcfg.xkb.model}"
+          Option "XkbLayout" "${xcfg.xkb.layout}"
+          Option "XkbOptions" "${xcfg.xkb.options}"
+          Option "XkbVariant" "${xcfg.xkb.variant}"
+        EndSection
+      '';
+      systemPackages = with pkgs; [
+        nixos-icons # needed for gnome and pantheon about dialog, nixos-manual and maybe more
+        xdg-utils
+      ];
+    };
+
+    fonts.enableDefaultPackages = lib.mkDefault true;
+
+    hardware.opengl.enable = lib.mkDefault true;
+
+    programs.gnupg.agent.pinentryPackage = lib.mkOverride 1100 pkgs.pinentry-gnome3;
+
+    systemd.defaultUnit = lib.mkIf (xcfg.autorun || dmcfg.enable) "graphical.target";
+
+    xdg = {
+      autostart.enable = true;
+      menus.enable = true;
+      mime.enable = true;
+      icons.enable = true;
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/greenclip.nix b/nixos/modules/services/misc/greenclip.nix
index ecfb864ab2b78..554769b63331f 100644
--- a/nixos/modules/services/misc/greenclip.nix
+++ b/nixos/modules/services/misc/greenclip.nix
@@ -7,7 +7,7 @@ let
 in {
 
   options.services.greenclip = {
-    enable = mkEnableOption (lib.mdDoc "Greenclip daemon");
+    enable = mkEnableOption (lib.mdDoc "Greenclip, a clipboard manager");
 
     package = mkPackageOption pkgs [ "haskellPackages" "greenclip" ] { };
   };
diff --git a/nixos/modules/services/misc/homepage-dashboard.nix b/nixos/modules/services/misc/homepage-dashboard.nix
index 02f1378cb0d59..e1b0264230ba5 100644
--- a/nixos/modules/services/misc/homepage-dashboard.nix
+++ b/nixos/modules/services/misc/homepage-dashboard.nix
@@ -12,7 +12,7 @@ in
 {
   options = {
     services.homepage-dashboard = {
-      enable = lib.mkEnableOption (lib.mdDoc "Homepage Dashboard");
+      enable = lib.mkEnableOption (lib.mdDoc "Homepage Dashboard, a highly customizable application dashboard");
 
       package = lib.mkPackageOption pkgs "homepage-dashboard" { };
 
diff --git a/nixos/modules/services/misc/jackett.nix b/nixos/modules/services/misc/jackett.nix
index c0bb0a575f01d..ad9288e45dd29 100644
--- a/nixos/modules/services/misc/jackett.nix
+++ b/nixos/modules/services/misc/jackett.nix
@@ -9,7 +9,7 @@ in
 {
   options = {
     services.jackett = {
-      enable = mkEnableOption (lib.mdDoc "Jackett");
+      enable = mkEnableOption (lib.mdDoc "Jackett, API support for your favorite torrent trackers");
 
       dataDir = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/languagetool.nix b/nixos/modules/services/misc/languagetool.nix
index 9adf792373b5a..902e55320b46d 100644
--- a/nixos/modules/services/misc/languagetool.nix
+++ b/nixos/modules/services/misc/languagetool.nix
@@ -7,7 +7,7 @@ let
   settingsFormat = pkgs.formats.javaProperties {};
 in {
   options.services.languagetool = {
-    enable = mkEnableOption (mdDoc "the LanguageTool server");
+    enable = mkEnableOption (mdDoc "the LanguageTool server, a multilingual spelling, style, and grammar checker that helps correct or paraphrase texts");
 
     port = mkOption {
       type = types.port;
diff --git a/nixos/modules/services/misc/leaps.nix b/nixos/modules/services/misc/leaps.nix
index 5522223ecc97c..b021937f8715c 100644
--- a/nixos/modules/services/misc/leaps.nix
+++ b/nixos/modules/services/misc/leaps.nix
@@ -9,7 +9,7 @@ in
 {
   options = {
     services.leaps = {
-      enable = mkEnableOption (lib.mdDoc "leaps");
+      enable = mkEnableOption (lib.mdDoc "leaps, a pair programming service");
       port = mkOption {
         type = types.port;
         default = 8080;
diff --git a/nixos/modules/services/misc/lidarr.nix b/nixos/modules/services/misc/lidarr.nix
index 8ceb567e88010..42627344dcd95 100644
--- a/nixos/modules/services/misc/lidarr.nix
+++ b/nixos/modules/services/misc/lidarr.nix
@@ -8,7 +8,7 @@ in
 {
   options = {
     services.lidarr = {
-      enable = mkEnableOption (lib.mdDoc "Lidarr");
+      enable = mkEnableOption (lib.mdDoc "Lidarr, a Usenet/BitTorrent music downloader");
 
       dataDir = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/lifecycled.nix b/nixos/modules/services/misc/lifecycled.nix
index fb5cabb4f038b..fa36ec693a844 100644
--- a/nixos/modules/services/misc/lifecycled.nix
+++ b/nixos/modules/services/misc/lifecycled.nix
@@ -25,7 +25,7 @@ in
 
   options = {
     services.lifecycled = {
-      enable = mkEnableOption (lib.mdDoc "lifecycled");
+      enable = mkEnableOption (lib.mdDoc "lifecycled, a daemon for responding to AWS AutoScaling Lifecycle Hooks");
 
       queueCleaner = {
         enable = mkEnableOption (lib.mdDoc "lifecycled-queue-cleaner");
diff --git a/nixos/modules/services/misc/logkeys.nix b/nixos/modules/services/misc/logkeys.nix
index 75d073a0c94bf..85f453b0d9da1 100644
--- a/nixos/modules/services/misc/logkeys.nix
+++ b/nixos/modules/services/misc/logkeys.nix
@@ -6,7 +6,7 @@ let
   cfg = config.services.logkeys;
 in {
   options.services.logkeys = {
-    enable = mkEnableOption (lib.mdDoc "logkeys service");
+    enable = mkEnableOption (lib.mdDoc "logkeys, a keylogger service");
 
     device = mkOption {
       description = lib.mdDoc "Use the given device as keyboard input event device instead of /dev/input/eventX default.";
diff --git a/nixos/modules/services/misc/mbpfan.nix b/nixos/modules/services/misc/mbpfan.nix
index ef56ea49d1a95..69f6331169f7d 100644
--- a/nixos/modules/services/misc/mbpfan.nix
+++ b/nixos/modules/services/misc/mbpfan.nix
@@ -4,14 +4,13 @@ with lib;
 let
   cfg = config.services.mbpfan;
   verbose = optionalString cfg.verbose "v";
-  settingsFormat = pkgs.formats.ini {};
-  settingsFile = settingsFormat.generate "mbpfan.ini" cfg.settings;
+  format = pkgs.formats.ini {};
+  cfgfile = format.generate "mbpfan.ini" cfg.settings;
 
 in {
   options.services.mbpfan = {
     enable = mkEnableOption (lib.mdDoc "mbpfan, fan controller daemon for Apple Macs and MacBooks");
-
-    package = mkPackageOption pkgs "mbpfan" { };
+    package = mkPackageOption pkgs "mbpfan" {};
 
     verbose = mkOption {
       type = types.bool;
@@ -29,7 +28,7 @@ in {
       default = {};
       description = lib.mdDoc "INI configuration for Mbpfan.";
       type = types.submodule {
-        freeformType = settingsFormat.type;
+        freeformType = format.type;
 
         options.general.low_temp = mkOption {
           type = types.int;
@@ -70,12 +69,12 @@ in {
   config = mkIf cfg.enable {
     boot.kernelModules = [ "coretemp" "applesmc" ];
     environment.systemPackages = [ cfg.package ];
-    environment.etc."mbpfan.conf".source = settingsFile;
+    environment.etc."mbpfan.conf".source = cfgfile;
 
     systemd.services.mbpfan = {
       description = "A fan manager daemon for MacBook Pro";
       wantedBy = [ "sysinit.target" ];
-      after = [ "syslog.target" "sysinit.target" ];
+      after = [ "sysinit.target" ];
       restartTriggers = [ config.environment.etc."mbpfan.conf".source ];
 
       serviceConfig = {
diff --git a/nixos/modules/services/misc/nitter.nix b/nixos/modules/services/misc/nitter.nix
index d2cf7c0de2b77..0f2f62153b00e 100644
--- a/nixos/modules/services/misc/nitter.nix
+++ b/nixos/modules/services/misc/nitter.nix
@@ -52,7 +52,7 @@ in
 
   options = {
     services.nitter = {
-      enable = mkEnableOption (lib.mdDoc "Nitter");
+      enable = mkEnableOption (lib.mdDoc "Nitter, an alternative Twitter front-end");
 
       package = mkPackageOption pkgs "nitter" { };
 
diff --git a/nixos/modules/services/misc/nix-optimise.nix b/nixos/modules/services/misc/nix-optimise.nix
index 0398229a13da9..514855abaee46 100644
--- a/nixos/modules/services/misc/nix-optimise.nix
+++ b/nixos/modules/services/misc/nix-optimise.nix
@@ -42,9 +42,11 @@ in
         startAt = lib.optionals cfg.automatic cfg.dates;
       };
 
-      timers.nix-optimise.timerConfig = {
-        Persistent = true;
-        RandomizedDelaySec = 1800;
+      timers.nix-optimise = lib.mkIf cfg.automatic {
+        timerConfig = {
+          Persistent = true;
+          RandomizedDelaySec = 1800;
+        };
       };
     };
   };
diff --git a/nixos/modules/services/misc/nzbget.nix b/nixos/modules/services/misc/nzbget.nix
index d02fda62fa4fa..122b3dd249af4 100644
--- a/nixos/modules/services/misc/nzbget.nix
+++ b/nixos/modules/services/misc/nzbget.nix
@@ -25,7 +25,7 @@ in
 
   options = {
     services.nzbget = {
-      enable = mkEnableOption (lib.mdDoc "NZBGet");
+      enable = mkEnableOption (lib.mdDoc "NZBGet, for downloading files from news servers");
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/nzbhydra2.nix b/nixos/modules/services/misc/nzbhydra2.nix
index 536a4e4b00758..2c1a5eae076d2 100644
--- a/nixos/modules/services/misc/nzbhydra2.nix
+++ b/nixos/modules/services/misc/nzbhydra2.nix
@@ -7,7 +7,7 @@ let cfg = config.services.nzbhydra2;
 in {
   options = {
     services.nzbhydra2 = {
-      enable = mkEnableOption (lib.mdDoc "NZBHydra2");
+      enable = mkEnableOption (lib.mdDoc "NZBHydra2, Usenet meta search");
 
       dataDir = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/ollama.nix b/nixos/modules/services/misc/ollama.nix
index 7a5661510e251..30c2b26d8322e 100644
--- a/nixos/modules/services/misc/ollama.nix
+++ b/nixos/modules/services/misc/ollama.nix
@@ -15,6 +15,22 @@ in
     services.ollama = {
       enable = lib.mkEnableOption "ollama server for local large language models";
       package = lib.mkPackageOption pkgs "ollama" { };
+      home = lib.mkOption {
+        type = types.str;
+        default = "%S/ollama";
+        example = "/home/foo";
+        description = ''
+          The home directory that the ollama service is started in.
+        '';
+      };
+      models = lib.mkOption {
+        type = types.str;
+        default = "%S/ollama/models";
+        example = "/path/to/ollama/models";
+        description = ''
+          The directory that the ollama service will read models from and download new models to.
+        '';
+      };
       listenAddress = lib.mkOption {
         type = types.str;
         default = "127.0.0.1:11434";
@@ -58,8 +74,8 @@ in
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
       environment = cfg.environmentVariables // {
-        HOME = "%S/ollama";
-        OLLAMA_MODELS = "%S/ollama/models";
+        HOME = cfg.home;
+        OLLAMA_MODELS = cfg.models;
         OLLAMA_HOST = cfg.listenAddress;
       };
       serviceConfig = {
diff --git a/nixos/modules/services/misc/ombi.nix b/nixos/modules/services/misc/ombi.nix
index 8bf6a9b116ec2..2e452f7d88eac 100644
--- a/nixos/modules/services/misc/ombi.nix
+++ b/nixos/modules/services/misc/ombi.nix
@@ -8,7 +8,9 @@ in {
   options = {
     services.ombi = {
       enable = mkEnableOption (lib.mdDoc ''
-        Ombi.
+        Ombi, a web application that automatically gives your shared Plex or
+        Emby users the ability to request content by themselves!
+
         Optionally see <https://docs.ombi.app/info/reverse-proxy>
         on how to set up a reverse proxy
       '');
diff --git a/nixos/modules/services/misc/owncast.nix b/nixos/modules/services/misc/owncast.nix
index 01fe34cf50fec..cbb6ba29e3227 100644
--- a/nixos/modules/services/misc/owncast.nix
+++ b/nixos/modules/services/misc/owncast.nix
@@ -5,7 +5,7 @@ in {
 
   options.services.owncast = {
 
-    enable = mkEnableOption (lib.mdDoc "owncast");
+    enable = mkEnableOption (lib.mdDoc "owncast, a video live streaming solution");
 
     dataDir = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/misc/paperless.nix b/nixos/modules/services/misc/paperless.nix
index 9301d1f687254..9a81fdde62af8 100644
--- a/nixos/modules/services/misc/paperless.nix
+++ b/nixos/modules/services/misc/paperless.nix
@@ -220,15 +220,16 @@ in
   config = mkIf cfg.enable {
     services.redis.servers.paperless.enable = mkIf enableRedis true;
 
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' - ${cfg.user} ${config.users.users.${cfg.user}.group} - -"
-      "d '${cfg.mediaDir}' - ${cfg.user} ${config.users.users.${cfg.user}.group} - -"
-      (if cfg.consumptionDirIsPublic then
-        "d '${cfg.consumptionDir}' 777 - - - -"
-      else
-        "d '${cfg.consumptionDir}' - ${cfg.user} ${config.users.users.${cfg.user}.group} - -"
-      )
-    ];
+    systemd.tmpfiles.settings."10-paperless" = let
+      defaultRule = {
+        inherit (cfg) user;
+        inherit (config.users.users.${cfg.user}) group;
+      };
+    in {
+      "${cfg.dataDir}".d = defaultRule;
+      "${cfg.mediaDir}".d = defaultRule;
+      "${cfg.consumptionDir}".d = if cfg.consumptionDirIsPublic then { mode = "777"; } else defaultRule;
+    };
 
     systemd.services.paperless-scheduler = {
       description = "Paperless Celery Beat";
@@ -238,6 +239,7 @@ in
         User = cfg.user;
         ExecStart = "${pkg}/bin/celery --app paperless beat --loglevel INFO";
         Restart = "on-failure";
+        LoadCredential = lib.optionalString (cfg.passwordFile != null) "PAPERLESS_ADMIN_PASSWORD:${cfg.passwordFile}";
       };
       environment = env;
 
@@ -270,7 +272,7 @@ in
       ''
       + optionalString (cfg.passwordFile != null) ''
         export PAPERLESS_ADMIN_USER="''${PAPERLESS_ADMIN_USER:-admin}"
-        export PAPERLESS_ADMIN_PASSWORD=$(cat "${cfg.dataDir}/superuser-password")
+        export PAPERLESS_ADMIN_PASSWORD=$(cat $CREDENTIALS_DIRECTORY/PAPERLESS_ADMIN_PASSWORD)
         superuserState="$PAPERLESS_ADMIN_USER:$PAPERLESS_ADMIN_PASSWORD"
         superuserStateFile="${cfg.dataDir}/superuser-state"
 
@@ -298,19 +300,6 @@ in
       environment = env;
     };
 
-    # Reading the user-provided password file requires root access
-    systemd.services.paperless-copy-password = mkIf (cfg.passwordFile != null) {
-      requiredBy = [ "paperless-scheduler.service" ];
-      before = [ "paperless-scheduler.service" ];
-      serviceConfig = {
-        ExecStart = ''
-          ${pkgs.coreutils}/bin/install --mode 600 --owner '${cfg.user}' --compare \
-            '${cfg.passwordFile}' '${cfg.dataDir}/superuser-password'
-        '';
-        Type = "oneshot";
-      };
-    };
-
     systemd.services.paperless-consumer = {
       description = "Paperless document consumer";
       # Bind to `paperless-scheduler` so that the consumer never runs
diff --git a/nixos/modules/services/misc/pinnwand.nix b/nixos/modules/services/misc/pinnwand.nix
index 5fca9f4125a83..466d045a7b16b 100644
--- a/nixos/modules/services/misc/pinnwand.nix
+++ b/nixos/modules/services/misc/pinnwand.nix
@@ -10,7 +10,7 @@ let
 in
 {
   options.services.pinnwand = {
-    enable = mkEnableOption (lib.mdDoc "Pinnwand");
+    enable = mkEnableOption (lib.mdDoc "Pinnwand, a pastebin");
 
     port = mkOption {
       type = types.port;
diff --git a/nixos/modules/services/misc/plikd.nix b/nixos/modules/services/misc/plikd.nix
index 9b0825bf40c98..bb5d3c1a36ca5 100644
--- a/nixos/modules/services/misc/plikd.nix
+++ b/nixos/modules/services/misc/plikd.nix
@@ -11,7 +11,7 @@ in
 {
   options = {
     services.plikd = {
-      enable = mkEnableOption (lib.mdDoc "the plikd server");
+      enable = mkEnableOption (lib.mdDoc "plikd, a temporary file upload system");
 
       openFirewall = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/misc/prowlarr.nix b/nixos/modules/services/misc/prowlarr.nix
index 84d365003992c..952f95485bd08 100644
--- a/nixos/modules/services/misc/prowlarr.nix
+++ b/nixos/modules/services/misc/prowlarr.nix
@@ -9,7 +9,7 @@ in
 {
   options = {
     services.prowlarr = {
-      enable = mkEnableOption (lib.mdDoc "Prowlarr");
+      enable = mkEnableOption (lib.mdDoc "Prowlarr, an indexer manager/proxy for Torrent trackers and Usenet indexers");
 
       package = mkPackageOption pkgs "prowlarr" { };
 
diff --git a/nixos/modules/services/misc/radarr.nix b/nixos/modules/services/misc/radarr.nix
index a5f264331ed36..eaf49673d3c7e 100644
--- a/nixos/modules/services/misc/radarr.nix
+++ b/nixos/modules/services/misc/radarr.nix
@@ -9,7 +9,7 @@ in
 {
   options = {
     services.radarr = {
-      enable = mkEnableOption (lib.mdDoc "Radarr");
+      enable = mkEnableOption (lib.mdDoc "Radarr, a UsetNet/BitTorrent movie downloader");
 
       package = mkPackageOption pkgs "radarr" { };
 
diff --git a/nixos/modules/services/misc/readarr.nix b/nixos/modules/services/misc/readarr.nix
index 73868b4baa953..486e2b4155b56 100644
--- a/nixos/modules/services/misc/readarr.nix
+++ b/nixos/modules/services/misc/readarr.nix
@@ -8,7 +8,7 @@ in
 {
   options = {
     services.readarr = {
-      enable = mkEnableOption (lib.mdDoc "Readarr");
+      enable = mkEnableOption (lib.mdDoc "Readarr, a Usenet/BitTorrent ebook downloader");
 
       dataDir = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/redmine.nix b/nixos/modules/services/misc/redmine.nix
index 8ebc46b42dcc8..f99fe7a845be4 100644
--- a/nixos/modules/services/misc/redmine.nix
+++ b/nixos/modules/services/misc/redmine.nix
@@ -56,7 +56,7 @@ in
   # interface
   options = {
     services.redmine = {
-      enable = mkEnableOption (lib.mdDoc "Redmine");
+      enable = mkEnableOption (lib.mdDoc "Redmine, a project management web application");
 
       package = mkPackageOption pkgs "redmine" {
         example = "redmine.override { ruby = pkgs.ruby_3_2; }";
diff --git a/nixos/modules/services/misc/rippled.nix b/nixos/modules/services/misc/rippled.nix
index 68a8318942506..08833e4135419 100644
--- a/nixos/modules/services/misc/rippled.nix
+++ b/nixos/modules/services/misc/rippled.nix
@@ -207,7 +207,7 @@ in
 
   options = {
     services.rippled = {
-      enable = mkEnableOption (lib.mdDoc "rippled");
+      enable = mkEnableOption (lib.mdDoc "rippled, a decentralized cryptocurrency blockchain daemon implementing the XRP Ledger protocol in C++");
 
       package = mkPackageOption pkgs "rippled" { };
 
diff --git a/nixos/modules/services/misc/signald.nix b/nixos/modules/services/misc/signald.nix
index 32ba154506ce3..44b82a931cd84 100644
--- a/nixos/modules/services/misc/signald.nix
+++ b/nixos/modules/services/misc/signald.nix
@@ -8,7 +8,7 @@ let
 in
 {
   options.services.signald = {
-    enable = mkEnableOption (lib.mdDoc "the signald service");
+    enable = mkEnableOption (lib.mdDoc "signald, the unofficial daemon for interacting with Signal");
 
     user = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/monitoring/nezha-agent.nix b/nixos/modules/services/monitoring/nezha-agent.nix
new file mode 100644
index 0000000000000..ef6878798f377
--- /dev/null
+++ b/nixos/modules/services/monitoring/nezha-agent.nix
@@ -0,0 +1,103 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+let
+  cfg = config.services.nezha-agent;
+in
+{
+  meta = {
+    maintainers = with lib.maintainers; [ moraxyc ];
+  };
+  options = {
+    services.nezha-agent = {
+      enable = lib.mkEnableOption (lib.mdDoc "Agent of Nezha Monitoring");
+
+      package = lib.mkPackageOption pkgs "nezha-agent" { };
+      debug = lib.mkEnableOption (lib.mdDoc "verbose log");
+      tls = lib.mkOption {
+        type = lib.types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Enable SSL/TLS encryption.
+        '';
+      };
+      disableCommandExecute = lib.mkOption {
+        type = lib.types.bool;
+        default = true;
+        description = lib.mdDoc ''
+          Disable executing the command from dashboard.
+        '';
+      };
+      skipConnection = lib.mkOption {
+        type = lib.types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Do not monitor the number of connections.
+        '';
+      };
+      skipProcess = lib.mkOption {
+        type = lib.types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Do not monitor the number of processes.
+        '';
+      };
+      reportDelay = lib.mkOption {
+        type = lib.types.enum [ 1 2 3 4 ];
+        default = 1;
+        description = lib.mdDoc ''
+          The interval between system status reportings.
+          The value must be an integer from 1 to 4
+        '';
+      };
+      passwordFile = lib.mkOption {
+        type = with lib.types; nullOr str;
+        default = null;
+        description = lib.mdDoc ''
+          Path to the file contained the password from dashboard.
+        '';
+      };
+      server = lib.mkOption {
+        type = lib.types.str;
+        description = lib.mdDoc ''
+          Address to the dashboard
+        '';
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    systemd.packages = [ cfg.package ];
+
+    systemd.services.nezha-agent = {
+      serviceConfig = {
+        ProtectSystem = "full";
+        PrivateDevices = "yes";
+        PrivateTmp = "yes";
+        NoNewPrivileges = true;
+      };
+      path = [ cfg.package ];
+      startLimitIntervalSec = 10;
+      startLimitBurst = 3;
+      script = lib.concatStringsSep " " (
+        [
+          "${cfg.package}/bin/agent"
+          "--disable-auto-update"
+          "--disable-force-update"
+          "--password $(cat ${cfg.passwordFile})"
+        ]
+        ++ lib.optional cfg.debug "--debug"
+        ++ lib.optional cfg.disableCommandExecute "--disable-command-execute"
+        ++ lib.optional (cfg.reportDelay != null) "--report-delay ${toString cfg.reportDelay}"
+        ++ lib.optional (cfg.server != null) "--server ${cfg.server}"
+        ++ lib.optional cfg.skipConnection "--skip-conn"
+        ++ lib.optional cfg.skipProcess "--skip-procs"
+        ++ lib.optional cfg.tls "--tls"
+      );
+      wantedBy = [ "multi-user.target" ];
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix
index 640c6c339cf62..0331a07b5109d 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -55,6 +55,7 @@ let
     "modemmanager"
     "mongodb"
     "mysqld"
+    "nats"
     "nextcloud"
     "nginx"
     "nginxlog"
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/nats.nix b/nixos/modules/services/monitoring/prometheus/exporters/nats.nix
new file mode 100644
index 0000000000000..83e60426f5ed2
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/exporters/nats.nix
@@ -0,0 +1,34 @@
+{ config, lib, pkgs, options, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.prometheus.exporters.nats;
+
+in
+{
+  port = 7777;
+
+  extraOpts = {
+    url = mkOption {
+      type = types.str;
+      default = "http://127.0.0.1:8222";
+      description = ''
+        NATS monitor endpoint to query.
+      '';
+    };
+  };
+
+  serviceOpts = {
+    serviceConfig = {
+      ExecStart = ''
+        ${pkgs.prometheus-nats-exporter}/bin/prometheus-nats-exporter \
+          -addr ${cfg.listenAddress} \
+          -port ${toString cfg.port} \
+          ${concatStringsSep " \\\n  " cfg.extraFlags} \
+          ${cfg.url}
+      '';
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/thanos.nix b/nixos/modules/services/monitoring/thanos.nix
index 02502816ef5d7..f9ec271c6ef55 100644
--- a/nixos/modules/services/monitoring/thanos.nix
+++ b/nixos/modules/services/monitoring/thanos.nix
@@ -353,6 +353,10 @@ let
         See <https://tools.ietf.org/html/rfc4366#section-3.1>
       '';
 
+      grpc-compression = mkParam types.str ''
+        Compression algorithm to use for gRPC requests to other clients.
+      '';
+
       web.route-prefix = mkParam types.str ''
         Prefix for API and UI endpoints.
 
@@ -642,6 +646,10 @@ let
 
     receive = params.common cfg.receive // params.objstore cfg.receive // {
 
+      receive.grpc-compression = mkParam types.str ''
+        Compression algorithm to use for gRPC requests to other receivers.
+      '';
+
       remote-write.address = mkParamDef types.str "0.0.0.0:19291" ''
         Address to listen on for remote write requests.
       '';
diff --git a/nixos/modules/services/networking/bind.nix b/nixos/modules/services/networking/bind.nix
index da8633d5066f7..0a4fa4c524a6c 100644
--- a/nixos/modules/services/networking/bind.nix
+++ b/nixos/modules/services/networking/bind.nix
@@ -121,7 +121,7 @@ in
       package = mkPackageOption pkgs "bind" { };
 
       cacheNetworks = mkOption {
-        default = [ "127.0.0.0/24" ];
+        default = [ "127.0.0.0/24" "::1/128" ];
         type = types.listOf types.str;
         description = lib.mdDoc ''
           What networks are allowed to use us as a resolver.  Note
diff --git a/nixos/modules/services/networking/cloudflared.nix b/nixos/modules/services/networking/cloudflared.nix
index b9556bfa60d06..76db339a1831c 100644
--- a/nixos/modules/services/networking/cloudflared.nix
+++ b/nixos/modules/services/networking/cloudflared.nix
@@ -11,7 +11,7 @@ let
       default = null;
       example = "30s";
       description = lib.mdDoc ''
-        Timeout for establishing a new TCP connection to your origin server. This excludes the time taken to establish TLS, which is controlled by [https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configuration/local-management/ingress/#tlstimeout](tlsTimeout).
+        Timeout for establishing a new TCP connection to your origin server. This excludes the time taken to establish TLS, which is controlled by [tlsTimeout](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configuration/local-management/ingress/#tlstimeout).
       '';
     };
 
diff --git a/nixos/modules/services/networking/i2p.nix b/nixos/modules/services/networking/i2p.nix
index c5c7a955cbd4f..5c6c08831a43d 100644
--- a/nixos/modules/services/networking/i2p.nix
+++ b/nixos/modules/services/networking/i2p.nix
@@ -5,7 +5,8 @@ with lib;
 let
   cfg = config.services.i2p;
   homeDir = "/var/lib/i2p";
-in {
+in
+{
   ###### interface
   options.services.i2p.enable = mkEnableOption (lib.mdDoc "I2P router");
 
@@ -27,7 +28,7 @@ in {
         User = "i2p";
         WorkingDirectory = homeDir;
         Restart = "on-abort";
-        ExecStart = "${pkgs.i2p}/bin/i2prouter-plain";
+        ExecStart = "${pkgs.i2p}/bin/i2prouter";
       };
     };
   };
diff --git a/nixos/modules/services/networking/kea.nix b/nixos/modules/services/networking/kea.nix
index 656ddd41fd12b..5fd6427c90f86 100644
--- a/nixos/modules/services/networking/kea.nix
+++ b/nixos/modules/services/networking/kea.nix
@@ -9,7 +9,6 @@ with lib;
 let
   cfg = config.services.kea;
 
-  xor = x: y: (!x && y) || (x && !y);
   format = pkgs.formats.json {};
 
   chooseNotNull = x: y: if x != null then x else y;
diff --git a/nixos/modules/services/networking/mihomo.nix b/nixos/modules/services/networking/mihomo.nix
index ae700603b5290..312530caeaade 100644
--- a/nixos/modules/services/networking/mihomo.nix
+++ b/nixos/modules/services/networking/mihomo.nix
@@ -12,7 +12,7 @@ let
 in
 {
   options.services.mihomo = {
-    enable = lib.mkEnableOption "Mihomo, A rule-based proxy in Go.";
+    enable = lib.mkEnableOption "Mihomo, A rule-based proxy in Go";
 
     package = lib.mkPackageOption pkgs "mihomo" { };
 
@@ -28,14 +28,14 @@ in
       description = ''
         Local web interface to use.
 
-        You can also use the following website, just in case:
+        You can also use the following website:
         - metacubexd:
           - https://d.metacubex.one
           - https://metacubex.github.io/metacubexd
           - https://metacubexd.pages.dev
         - yacd:
           - https://yacd.haishan.me
-        - clash-dashboard (buggy):
+        - clash-dashboard:
           - https://clash.razord.top
       '';
     };
@@ -49,7 +49,7 @@ in
     tunMode = lib.mkEnableOption ''
       necessary permission for Mihomo's systemd service for TUN mode to function properly.
 
-      Keep in mind, that you still need to enable TUN mode manually in Mihomo's configuration.
+      Keep in mind, that you still need to enable TUN mode manually in Mihomo's configuration
     '';
   };
 
diff --git a/nixos/modules/services/networking/radicale.nix b/nixos/modules/services/networking/radicale.nix
index 00dbd6bbe386d..d6b2f652c8887 100644
--- a/nixos/modules/services/networking/radicale.nix
+++ b/nixos/modules/services/networking/radicale.nix
@@ -200,5 +200,5 @@ in {
     };
   };
 
-  meta.maintainers = with lib.maintainers; [ infinisil dotlambda ];
+  meta.maintainers = with lib.maintainers; [ dotlambda ];
 }
diff --git a/nixos/modules/services/networking/soju.nix b/nixos/modules/services/networking/soju.nix
index d69ec08ca13a0..810957be65f57 100644
--- a/nixos/modules/services/networking/soju.nix
+++ b/nixos/modules/services/networking/soju.nix
@@ -5,7 +5,10 @@ with lib;
 let
   cfg = config.services.soju;
   stateDir = "/var/lib/soju";
-  listenCfg = concatMapStringsSep "\n" (l: "listen ${l}") cfg.listen;
+  runtimeDir = "/run/soju";
+  listen = cfg.listen
+    ++ optional cfg.adminSocket.enable "unix+admin://${runtimeDir}/admin";
+  listenCfg = concatMapStringsSep "\n" (l: "listen ${l}") listen;
   tlsCfg = optionalString (cfg.tlsCertificate != null)
     "tls ${cfg.tlsCertificate} ${cfg.tlsCertificateKey}";
   logCfg = optionalString cfg.enableMessageLogging
@@ -22,6 +25,10 @@ let
 
     ${cfg.extraConfig}
   '';
+
+  sojuctl = pkgs.writeShellScriptBin "sojuctl" ''
+    exec ${cfg.package}/bin/sojuctl --config ${configFile} "$@"
+  '';
 in
 {
   ###### interface
@@ -29,6 +36,8 @@ in
   options.services.soju = {
     enable = mkEnableOption (lib.mdDoc "soju");
 
+    package = mkPackageOption pkgs "soju" { };
+
     listen = mkOption {
       type = types.listOf types.str;
       default = [ ":6697" ];
@@ -66,6 +75,14 @@ in
       description = lib.mdDoc "Whether to enable message logging.";
     };
 
+    adminSocket.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = lib.mdDoc ''
+        Listen for admin connections from sojuctl at /run/soju/admin.
+      '';
+    };
+
     httpOrigins = mkOption {
       type = types.listOf types.str;
       default = [];
@@ -107,6 +124,8 @@ in
       }
     ];
 
+    environment.systemPackages = [ sojuctl ];
+
     systemd.services.soju = {
       description = "soju IRC bouncer";
       wantedBy = [ "multi-user.target" ];
@@ -115,8 +134,9 @@ in
       serviceConfig = {
         DynamicUser = true;
         Restart = "always";
-        ExecStart = "${pkgs.soju}/bin/soju -config ${configFile}";
+        ExecStart = "${cfg.package}/bin/soju -config ${configFile}";
         StateDirectory = "soju";
+        RuntimeDirectory = "soju";
       };
     };
   };
diff --git a/nixos/modules/services/networking/technitium-dns-server.nix b/nixos/modules/services/networking/technitium-dns-server.nix
new file mode 100644
index 0000000000000..0c8499e072d4f
--- /dev/null
+++ b/nixos/modules/services/networking/technitium-dns-server.nix
@@ -0,0 +1,109 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+
+let
+  cfg = config.services.technitium-dns-server;
+  stateDir = "/var/lib/technitium-dns-server";
+  inherit (lib)
+    mkEnableOption
+    mkPackageOption
+    mkOption
+    mkIf
+    types
+    ;
+in
+{
+  options.services.technitium-dns-server = {
+    enable = mkEnableOption "Technitium DNS Server";
+
+    package = mkPackageOption pkgs "technitium-dns-server" { };
+
+    openFirewall = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to open ports in the firewall.
+        Standard ports are 53 (UDP and TCP, for DNS), 5380 and 53443 (TCP, HTTP and HTTPS for web interface).
+        Specify different or additional ports in options firewallUDPPorts and firewallTCPPorts if necessary.
+      '';
+    };
+
+    firewallUDPPorts = mkOption {
+      type = with types; listOf int;
+      default = [ 53 ];
+      description = ''
+        List of UDP ports to open in firewall.
+      '';
+    };
+
+    firewallTCPPorts = mkOption {
+      type = with types; listOf int;
+      default = [
+        53
+        5380 # web interface HTTP
+        53443 # web interface HTTPS
+      ];
+      description = ''
+        List of TCP ports to open in firewall.
+        You might want to open ports 443 and 853 if you intend to use DNS over HTTPS or DNS over TLS.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.technitium-dns-server = {
+      description = "Technitium DNS Server";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/technitium-dns-server ${stateDir}";
+
+        DynamicUser = true;
+
+        StateDirectory = "technitium-dns-server";
+        WorkingDirectory = stateDir;
+        BindPaths = stateDir;
+
+        Restart = "always";
+        RestartSec = 10;
+        TimeoutStopSec = 10;
+        KillSignal = "SIGINT";
+
+        # Harden the service
+        LockPersonality = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateMounts = true;
+        PrivateTmp = true;
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectSystem = "strict";
+        RemoveIPC = true;
+        RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_NETLINK";
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+
+        AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
+        CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
+      };
+    };
+
+    networking.firewall = mkIf cfg.openFirewall {
+      allowedUDPPorts = cfg.firewallUDPPorts;
+      allowedTCPPorts = cfg.firewallTCPPorts;
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ fabianrig ];
+}
diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix
index eb769f53901cf..5e20c83652988 100644
--- a/nixos/modules/services/networking/tinc.nix
+++ b/nixos/modules/services/networking/tinc.nix
@@ -348,7 +348,7 @@ in
         (flip mapAttrsToList cfg.networks (network: data:
           flip mapAttrs' data.hosts (host: text: nameValuePair
             ("tinc/${network}/hosts/${host}")
-            ({ mode = "0644"; user = "tinc.${network}"; inherit text; })
+            ({ mode = "0644"; user = "tinc-${network}"; inherit text; })
           ) // {
             "tinc/${network}/tinc.conf" = {
               mode = "0444";
@@ -375,13 +375,13 @@ in
             Restart = "always";
             RestartSec = "3";
             ExecReload = mkIf (versionAtLeast version "1.1pre") "${data.package}/bin/tinc -n ${network} reload";
-            ExecStart = "${data.package}/bin/tincd -D -U tinc.${network} -n ${network} ${optionalString (data.chroot) "-R"} --pidfile /run/tinc.${network}.pid -d ${toString data.debugLevel}";
+            ExecStart = "${data.package}/bin/tincd -D -U tinc-${network} -n ${network} ${optionalString (data.chroot) "-R"} --pidfile /run/tinc.${network}.pid -d ${toString data.debugLevel}";
           };
           preStart = ''
             mkdir -p /etc/tinc/${network}/hosts
-            chown tinc.${network} /etc/tinc/${network}/hosts
+            chown tinc-${network} /etc/tinc/${network}/hosts
             mkdir -p /etc/tinc/${network}/invitations
-            chown tinc.${network} /etc/tinc/${network}/invitations
+            chown tinc-${network} /etc/tinc/${network}/invitations
 
             # Determine how we should generate our keys
             if type tinc >/dev/null 2>&1; then
@@ -420,14 +420,14 @@ in
       in [ cli-wrappers ];
 
       users.users = flip mapAttrs' cfg.networks (network: _:
-        nameValuePair ("tinc.${network}") ({
+        nameValuePair ("tinc-${network}") ({
           description = "Tinc daemon user for ${network}";
           isSystemUser = true;
-          group = "tinc.${network}";
+          group = "tinc-${network}";
         })
       );
       users.groups = flip mapAttrs' cfg.networks (network: _:
-        nameValuePair "tinc.${network}" {}
+        nameValuePair "tinc-${network}" {}
       );
     });
 
diff --git a/nixos/modules/services/security/yubikey-agent.nix b/nixos/modules/services/security/yubikey-agent.nix
index 3d5f84af2cf48..f7ee952e7f61e 100644
--- a/nixos/modules/services/security/yubikey-agent.nix
+++ b/nixos/modules/services/security/yubikey-agent.nix
@@ -23,7 +23,7 @@ in
           SSH_AUTH_SOCK to point at yubikey-agent.
 
           Note that yubikey-agent will use whatever pinentry is
-          specified in programs.gnupg.agent.pinentryFlavor.
+          specified in programs.gnupg.agent.pinentryPackage.
         '';
       };
 
diff --git a/nixos/modules/services/system/cloud-init.nix b/nixos/modules/services/system/cloud-init.nix
index 00ae77be4271c..689e0000fdd54 100644
--- a/nixos/modules/services/system/cloud-init.nix
+++ b/nixos/modules/services/system/cloud-init.nix
@@ -17,6 +17,7 @@ let
   ++ optional cfg.ext4.enable e2fsprogs
   ++ optional cfg.xfs.enable xfsprogs
   ;
+  hasFs = fsName: lib.any (fs: fs.fsType == fsName) (lib.attrValues config.fileSystems);
   settingsFormat = pkgs.formats.yaml { };
   cfgfile = settingsFormat.generate "cloud.cfg" cfg.settings;
 in
@@ -44,7 +45,8 @@ in
 
       btrfs.enable = mkOption {
         type = types.bool;
-        default = false;
+        default = hasFs "btrfs";
+        defaultText = literalExpression ''hasFs "btrfs"'';
         description = mdDoc ''
           Allow the cloud-init service to operate `btrfs` filesystem.
         '';
@@ -52,7 +54,8 @@ in
 
       ext4.enable = mkOption {
         type = types.bool;
-        default = true;
+        default = hasFs "ext4";
+        defaultText = literalExpression ''hasFs "ext4"'';
         description = mdDoc ''
           Allow the cloud-init service to operate `ext4` filesystem.
         '';
@@ -60,7 +63,8 @@ in
 
       xfs.enable = mkOption {
         type = types.bool;
-        default = false;
+        default = hasFs "xfs";
+        defaultText = literalExpression ''hasFs "xfs"'';
         description = mdDoc ''
           Allow the cloud-init service to operate `xfs` filesystem.
         '';
@@ -204,7 +208,7 @@ in
       description = "Apply the settings specified in cloud-config";
       wantedBy = [ "multi-user.target" ];
       wants = [ "network-online.target" ];
-      after = [ "network-online.target" "syslog.target" "cloud-config.target" ];
+      after = [ "network-online.target" "cloud-config.target" ];
 
       path = path;
       serviceConfig = {
@@ -220,7 +224,7 @@ in
       description = "Execute cloud user/final scripts";
       wantedBy = [ "multi-user.target" ];
       wants = [ "network-online.target" ];
-      after = [ "network-online.target" "syslog.target" "cloud-config.service" "rc-local.service" ];
+      after = [ "network-online.target" "cloud-config.service" "rc-local.service" ];
       requires = [ "cloud-config.target" ];
       path = path;
       serviceConfig = {
diff --git a/nixos/modules/services/system/nix-daemon.nix b/nixos/modules/services/system/nix-daemon.nix
index ce255cd8d0a46..550ef6b1e18c2 100644
--- a/nixos/modules/services/system/nix-daemon.nix
+++ b/nixos/modules/services/system/nix-daemon.nix
@@ -247,7 +247,7 @@ in
 
     users.users = nixbldUsers;
 
-    services.xserver.displayManager.hiddenUsers = attrNames nixbldUsers;
+    services.displayManager.hiddenUsers = attrNames nixbldUsers;
 
     # Legacy configuration conversion.
     nix.settings = mkMerge [
diff --git a/nixos/modules/services/web-apps/castopod.nix b/nixos/modules/services/web-apps/castopod.nix
index 0ccba217be4dd..0b905bb50761e 100644
--- a/nixos/modules/services/web-apps/castopod.nix
+++ b/nixos/modules/services/web-apps/castopod.nix
@@ -21,7 +21,7 @@ in
 
   options.services = {
     castopod = {
-      enable = lib.mkEnableOption (lib.mdDoc "Castopod");
+      enable = lib.mkEnableOption (lib.mdDoc "Castopod, a hosting platform for podcasters");
       package = lib.mkOption {
         type = lib.types.package;
         default = pkgs.castopod;
diff --git a/nixos/modules/services/web-apps/healthchecks.nix b/nixos/modules/services/web-apps/healthchecks.nix
index 1d439f162313b..04b40e6eb8b08 100644
--- a/nixos/modules/services/web-apps/healthchecks.nix
+++ b/nixos/modules/services/web-apps/healthchecks.nix
@@ -213,8 +213,7 @@ in
           preStart = ''
             ${pkg}/opt/healthchecks/manage.py collectstatic --no-input
             ${pkg}/opt/healthchecks/manage.py remove_stale_contenttypes --no-input
-            ${pkg}/opt/healthchecks/manage.py compress
-          '';
+          '' + lib.optionalString (cfg.settings.DEBUG != "True") "${pkg}/opt/healthchecks/manage.py compress";
 
           serviceConfig = commonConfig // {
             Restart = "always";
diff --git a/nixos/modules/services/web-apps/hledger-web.nix b/nixos/modules/services/web-apps/hledger-web.nix
index be8ecc645e59c..2e888d081a9f9 100644
--- a/nixos/modules/services/web-apps/hledger-web.nix
+++ b/nixos/modules/services/web-apps/hledger-web.nix
@@ -26,28 +26,17 @@ in {
       '';
     };
 
-    capabilities = {
-      view = mkOption {
-        type = types.bool;
-        default = true;
-        description = lib.mdDoc ''
-          Enable the view capability.
-        '';
-      };
-      add = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc ''
-          Enable the add capability.
-        '';
-      };
-      manage = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc ''
-          Enable the manage capability.
-        '';
-      };
+    allow = mkOption {
+      type = types.enum [ "view" "add" "edit" "sandstorm" ];
+      default = "view";
+      description = lib.mdDoc ''
+        User's access level for changing data.
+
+        * view: view only permission.
+        * add: view and add permissions.
+        * edit: view, add, and edit permissions.
+        * sandstorm: permissions from the `X-Sandstorm-Permissions` request header.
+      '';
     };
 
     stateDir = mkOption {
@@ -89,6 +78,11 @@ in {
 
   };
 
+  imports = [
+    (mkRemovedOptionModule [ "services" "hledger-web" "capabilities" ]
+      "This option has been replaced by new option `services.hledger-web.allow`.")
+  ];
+
   config = mkIf cfg.enable {
 
     users.users.hledger = {
@@ -102,16 +96,11 @@ in {
     users.groups.hledger = {};
 
     systemd.services.hledger-web = let
-      capabilityString = with cfg.capabilities; concatStringsSep "," (
-        (optional view "view")
-        ++ (optional add "add")
-        ++ (optional manage "manage")
-      );
       serverArgs = with cfg; escapeShellArgs ([
         "--serve"
         "--host=${host}"
         "--port=${toString port}"
-        "--capabilities=${capabilityString}"
+        "--allow=${allow}"
         (optionalString (cfg.baseUrl != null) "--base-url=${cfg.baseUrl}")
         (optionalString (cfg.serveApi) "--serve-api")
       ] ++ (map (f: "--file=${stateDir}/${f}") cfg.journalFiles)
diff --git a/nixos/modules/services/web-apps/kavita.nix b/nixos/modules/services/web-apps/kavita.nix
index c90697bcfa8b2..81b8edc5e0066 100644
--- a/nixos/modules/services/web-apps/kavita.nix
+++ b/nixos/modules/services/web-apps/kavita.nix
@@ -34,8 +34,8 @@ in
     tokenKeyFile = lib.mkOption {
       type = lib.types.path;
       description = lib.mdDoc ''
-        A file containing the TokenKey, a secret with at 128+ bits.
-        It can be generated with `head -c 32 /dev/urandom | base64`.
+        A file containing the TokenKey, a secret with at 512+ bits.
+        It can be generated with `head -c 64 /dev/urandom | base64 --wrap=0`.
       '';
     };
 
diff --git a/nixos/modules/services/web-apps/movim.nix b/nixos/modules/services/web-apps/movim.nix
new file mode 100644
index 0000000000000..bb88a185b4618
--- /dev/null
+++ b/nixos/modules/services/web-apps/movim.nix
@@ -0,0 +1,711 @@
+{ config, lib, pkgs, ... }:
+
+let
+  inherit (lib)
+    filterAttrsRecursive
+    generators
+    literalExpression
+    mkDefault
+    mkIf
+    mkOption
+    mkEnableOption
+    mkPackageOption
+    mkMerge
+    pipe
+    types
+    ;
+
+  cfg = config.services.movim;
+
+  defaultPHPCfg = {
+    "output_buffering" = 0;
+    "error_reporting" = "E_ALL & ~E_DEPRECATED & ~E_STRICT";
+    "opcache.enable_cli" = 1;
+    "opcache.interned_strings_buffer" = 8;
+    "opcache.max_accelerated_files" = 6144;
+    "opcache.memory_consumption" = 128;
+    "opcache.revalidate_freq" = 2;
+    "opcache.fast_shutdown" = 1;
+  };
+
+  phpCfg = generators.toKeyValue
+    { mkKeyValue = generators.mkKeyValueDefault { } " = "; }
+    (defaultPHPCfg // cfg.phpCfg);
+
+  podConfigFlags =
+    let
+      bevalue = a: lib.escapeShellArg (generators.mkValueStringDefault { } a);
+    in
+    lib.concatStringsSep " "
+      (lib.attrsets.foldlAttrs
+        (acc: k: v: acc ++ lib.optional (v != null) "--${k}=${bevalue v}")
+        [ ]
+        cfg.podConfig);
+
+  package =
+    let
+      p = cfg.package.override
+        ({
+          inherit phpCfg;
+          withPgsql = cfg.database.type == "pgsql";
+          withMysql = cfg.database.type == "mysql";
+          inherit (cfg) minifyStaticFiles;
+        } // lib.optionalAttrs (lib.isAttrs cfg.minifyStaticFiles) (with cfg.minifyStaticFiles; {
+          esbuild = esbuild.package;
+          lightningcss = lightningcss.package;
+          scour = scour.package;
+        }));
+    in
+    p.overrideAttrs (finalAttrs: prevAttrs:
+      let
+        appDir = "$out/share/php/${finalAttrs.pname}";
+
+        stateDirectories = ''
+          # Symlinking in our state directories
+          rm -rf $out/.env $out/cache ${appDir}/public/cache
+          ln -s ${cfg.dataDir}/.env ${appDir}/.env
+          ln -s ${cfg.dataDir}/public/cache ${appDir}/public/cache
+          ln -s ${cfg.logDir} ${appDir}/log
+          ln -s ${cfg.runtimeDir}/cache ${appDir}/cache
+        '';
+
+        exposeComposer = ''
+          # Expose PHP Composer for scripts
+          mkdir -p $out/bin
+          echo "#!${lib.getExe pkgs.dash}" > $out/bin/movim-composer
+          echo "${finalAttrs.php.packages.composer}/bin/composer --working-dir="${appDir}" \"\$@\"" >> $out/bin/movim-composer
+          chmod +x $out/bin/movim-composer
+        '';
+
+        podConfigInputDisableReplace = lib.optionalString (podConfigFlags != "")
+          (lib.concatStringsSep "\n"
+            (lib.attrsets.foldlAttrs
+              (acc: k: v:
+                acc ++ lib.optional (v != null)
+                  # Disable all Admin panel options that were set in the
+                  # `cfg.podConfig` to prevent confusing situtions where the
+                  # values are rewritten on server reboot
+                  ''
+                    substituteInPlace ${appDir}/app/widgets/AdminMain/adminmain.tpl \
+                      --replace-warn 'name="${k}"' 'name="${k}" disabled'
+                  '')
+              [ ]
+              cfg.podConfig));
+
+        precompressStaticFilesJobs =
+          let
+            inherit (cfg.precompressStaticFiles) brotli gzip;
+
+            findTextFileNames = lib.concatStringsSep " -o "
+              (builtins.map (n: ''-iname "*.${n}"'')
+                [ "css" "ini" "js" "json" "manifest" "mjs" "svg" "webmanifest" ]);
+          in
+          lib.concatStringsSep "\n" [
+            (lib.optionalString brotli.enable ''
+              echo -n "Precompressing static files with Brotli …"
+              find ${appDir}/public -type f ${findTextFileNames} \
+                | ${lib.getExe pkgs.parallel} ${lib.escapeShellArgs [
+                    "--will-cite"
+                    "-j $NIX_BUILD_CORES"
+                    "${lib.getExe brotli.package} --keep --quality=${builtins.toString brotli.compressionLevel} --output={}.br {}"
+                   ]}
+              echo " done."
+            '')
+            (lib.optionalString gzip.enable ''
+              echo -n "Precompressing static files with Gzip …"
+              find ${appDir}/public -type f ${findTextFileNames} \
+                | ${lib.getExe pkgs.parallel} ${lib.escapeShellArgs [
+                    "--will-cite"
+                    "-j $NIX_BUILD_CORES"
+                    "${lib.getExe gzip.package} -c -${builtins.toString gzip.compressionLevel} {} > {}.gz"
+                   ]}
+              echo " done."
+            '')
+          ];
+      in
+      {
+        postInstall = lib.concatStringsSep "\n\n" [
+          prevAttrs.postInstall
+          stateDirectories
+          exposeComposer
+          podConfigInputDisableReplace
+          precompressStaticFilesJobs
+        ];
+      });
+
+  configFile = pipe cfg.settings [
+    (filterAttrsRecursive (_: v: v != null))
+    (generators.toKeyValue { })
+    (pkgs.writeText "movim-env")
+  ];
+
+  pool = "movim";
+  fpm = config.services.phpfpm.pools.${pool};
+  phpExecutionUnit = "phpfpm-${pool}";
+
+  dbService = {
+    "postgresql" = "postgresql.service";
+    "mysql" = "mysql.service";
+  }.${cfg.database.type};
+in
+{
+  options.services = {
+    movim = {
+      enable = mkEnableOption "a Movim instance";
+      package = mkPackageOption pkgs "movim" { };
+      phpPackage = mkPackageOption pkgs "php" { };
+
+      phpCfg = mkOption {
+        type = with types; attrsOf (oneOf [ int str bool ]);
+        defaultText = literalExpression (generators.toPretty { } defaultPHPCfg);
+        default = { };
+        description = "Extra PHP INI options such as `memory_limit`, `max_execution_time`, etc.";
+      };
+
+      user = mkOption {
+        type = types.nonEmptyStr;
+        default = "movim";
+        description = "User running Movim service";
+      };
+
+      group = mkOption {
+        type = types.nonEmptyStr;
+        default = "movim";
+        description = "Group running Movim service";
+      };
+
+      dataDir = mkOption {
+        type = types.nonEmptyStr;
+        default = "/var/lib/movim";
+        description = "State directory of the `movim` user which holds the application’s state & data.";
+      };
+
+      logDir = mkOption {
+        type = types.nonEmptyStr;
+        default = "/var/log/movim";
+        description = "Log directory of the `movim` user which holds the application’s logs.";
+      };
+
+      runtimeDir = mkOption {
+        type = types.nonEmptyStr;
+        default = "/run/movim";
+        description = "Runtime directory of the `movim` user which holds the application’s caches & temporary files.";
+      };
+
+      domain = mkOption {
+        type = types.nonEmptyStr;
+        description = "Fully-qualified domain name (FQDN) for the Movim instance.";
+      };
+
+      port = mkOption {
+        type = types.port;
+        default = 8080;
+        description = "Movim daemon port.";
+      };
+
+      debug = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Debugging logs.";
+      };
+
+      verbose = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Verbose logs.";
+      };
+
+      minifyStaticFiles = mkOption {
+        type = with types; either bool (submodule {
+          options = {
+            script = mkOption {
+              type = types.submodule {
+                options = {
+                  enable = mkEnableOption "Script minification";
+                  package = mkPackageOption pkgs "esbuild" { };
+                  target = mkOption {
+                    type = with types; nullOr nonEmptyStr;
+                    default = null;
+                  };
+                };
+              };
+            };
+            style = mkOption {
+              type = types.submodule {
+                options = {
+                  enable = mkEnableOption "Script minification";
+                  package = mkPackageOption pkgs "lightningcss" { };
+                  target = mkOption {
+                    type = with types; nullOr nonEmptyStr;
+                    default = null;
+                  };
+                };
+              };
+            };
+            svg = mkOption {
+              type = types.submodule {
+                options = {
+                  enable = mkEnableOption "SVG minification";
+                  package = mkPackageOption pkgs "scour" { };
+                };
+              };
+            };
+          };
+        });
+        default = true;
+        description = "Do minification on public static files";
+      };
+
+      precompressStaticFiles = mkOption {
+        type = with types; submodule {
+          options = {
+            brotli = {
+              enable = mkEnableOption "Brotli precompression";
+              package = mkPackageOption pkgs "brotli" { };
+              compressionLevel = mkOption {
+                type = types.ints.between 0 11;
+                default = 11;
+                description = "Brotli compression level";
+              };
+            };
+            gzip = {
+              enable = mkEnableOption "Gzip precompression";
+              package = mkPackageOption pkgs "gzip" { };
+              compressionLevel = mkOption {
+                type = types.ints.between 1 9;
+                default = 9;
+                description = "Gzip compression level";
+              };
+            };
+          };
+        };
+        default = {
+          brotli.enable = true;
+          gzip.enable = false;
+        };
+        description = "Aggressively precompress static files";
+      };
+
+      podConfig = mkOption {
+        type = types.submodule {
+          options = {
+            info = mkOption {
+              type = with types; nullOr str;
+              default = null;
+              description = "Content of the info box on the login page";
+            };
+
+            description = mkOption {
+              type = with types; nullOr str;
+              default = null;
+              description = "General description of the instance";
+            };
+
+            timezone = mkOption {
+              type = with types; nullOr str;
+              default = null;
+              description = "The server timezone";
+            };
+
+            restrictsuggestions = mkOption {
+              type = with types; nullOr bool;
+              default = null;
+              description = "Only suggest chatrooms, Communities and other contents that are available on the user XMPP server and related services";
+            };
+
+            chatonly = mkOption {
+              type = with types; nullOr bool;
+              default = null;
+              description = "Disable all the social feature (Communities, Blog…) and keep only the chat ones";
+            };
+
+            disableregistration = mkOption {
+              type = with types; nullOr bool;
+              default = null;
+              description = "Remove the XMPP registration flow and buttons from the interface";
+            };
+
+            loglevel = mkOption {
+              type = with types; nullOr (ints.between 0 3);
+              default = null;
+              description = "The server loglevel";
+            };
+
+            locale = mkOption {
+              type = with types; nullOr str;
+              default = null;
+              description = "The server main locale";
+            };
+
+            xmppdomain = mkOption {
+              type = with types; nullOr str;
+              default = null;
+              description = "The default XMPP server domain";
+            };
+
+            xmppdescription = mkOption {
+              type = with types; nullOr str;
+              default = null;
+              description = "The default XMPP server description";
+            };
+
+            xmppwhitelist = mkOption {
+              type = with types; nullOr str;
+              default = null;
+              description = "The allowlisted XMPP servers";
+            };
+          };
+        };
+        default = { };
+        description = ''
+          Pod configuration (values from `php daemon.php config --help`).
+          Note that these values will now be disabled in the admin panel.
+        '';
+      };
+
+      settings = mkOption {
+        type = with types; attrsOf (nullOr (oneOf [ int str bool ]));
+        default = { };
+        description = ".env settings for Movim. Secrets should use `secretFile` option instead. `null`s will be culled.";
+      };
+
+      secretFile = mkOption {
+        type = with types; nullOr path;
+        default = null;
+        description = "The secret file to be sourced for the .env settings.";
+      };
+
+      database = {
+        type = mkOption {
+          type = types.enum [ "mysql" "postgresql" ];
+          example = "mysql";
+          default = "postgresql";
+          description = "Database engine to use.";
+        };
+
+        name = mkOption {
+          type = types.str;
+          default = "movim";
+          description = "Database name.";
+        };
+
+        user = mkOption {
+          type = types.str;
+          default = "movim";
+          description = "Database username.";
+        };
+
+        createLocally = mkOption {
+          type = types.bool;
+          default = true;
+          description = "local database using UNIX socket authentication";
+        };
+      };
+
+      nginx = mkOption {
+        type = with types; nullOr (submodule
+          (import ../web-servers/nginx/vhost-options.nix {
+            inherit config lib;
+          }));
+        default = null;
+        example = lib.literalExpression /* nginx */ ''
+          {
+            serverAliases = [
+              "pics.''${config.networking.domain}"
+            ];
+            enableACME = true;
+            forceHttps = true;
+          }
+        '';
+        description = ''
+          With this option, you can customize an nginx virtual host which already has sensible defaults for Movim.
+          Set to `{ }` if you do not need any customization to the virtual host.
+          If enabled, then by default, the {option}`serverName` is `''${domain}`,
+          If this is set to null (the default), no nginx virtualHost will be configured.
+        '';
+      };
+
+      poolConfig = mkOption {
+        type = with types; attrsOf (oneOf [ int str bool ]);
+        default = { };
+        description = "Options for Movim’s PHP-FPM pool.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ cfg.package ];
+
+    users = {
+      users = {
+        movim = mkIf (cfg.user == "movim") {
+          isSystemUser = true;
+          group = cfg.group;
+        };
+        "${config.services.nginx.user}".extraGroups = [ cfg.group ];
+      };
+      groups = {
+        ${cfg.group} = { };
+      };
+    };
+
+    services = {
+      movim = {
+        settings = mkMerge [
+          {
+            DAEMON_URL = "//${cfg.domain}";
+            DAEMON_PORT = cfg.port;
+            DAEMON_INTERFACE = "127.0.0.1";
+            DAEMON_DEBUG = cfg.debug;
+            DAEMON_VERBOSE = cfg.verbose;
+          }
+          (mkIf cfg.database.createLocally {
+            DB_DRIVER = {
+              "postgresql" = "pgsql";
+              "mysql" = "mysql";
+            }.${cfg.database.type};
+            DB_HOST = "localhost";
+            DB_PORT = config.services.${cfg.database.type}.settings.port;
+            DB_DATABASE = cfg.database.name;
+            DB_USERNAME = cfg.database.user;
+            DB_PASSWORD = "";
+          })
+        ];
+
+        poolConfig = lib.mapAttrs' (n: v: lib.nameValuePair n (lib.mkDefault v)) {
+          "pm" = "dynamic";
+          "php_admin_value[error_log]" = "stderr";
+          "php_admin_flag[log_errors]" = true;
+          "catch_workers_output" = true;
+          "pm.max_children" = 32;
+          "pm.start_servers" = 2;
+          "pm.min_spare_servers" = 2;
+          "pm.max_spare_servers" = 8;
+          "pm.max_requests" = 500;
+        };
+      };
+
+      nginx = mkIf (cfg.nginx != null) {
+        enable = true;
+        recommendedOptimisation = true;
+        recommendedGzipSettings = true;
+        recommendedBrotliSettings = true;
+        recommendedProxySettings = true;
+        # TODO: recommended cache options already in Nginx⁇
+        appendHttpConfig = /* nginx */ ''
+          fastcgi_cache_path /tmp/nginx_cache levels=1:2 keys_zone=nginx_cache:100m inactive=60m;
+          fastcgi_cache_key "$scheme$request_method$host$request_uri";
+        '';
+        virtualHosts."${cfg.domain}" = mkMerge [
+          cfg.nginx
+          {
+            root = lib.mkForce "${package}/share/php/movim/public";
+            locations = {
+              "/favicon.ico" = {
+                priority = 100;
+                extraConfig = /* nginx */ ''
+                  access_log off;
+                  log_not_found off;
+                '';
+              };
+              "/robots.txt" = {
+                priority = 100;
+                extraConfig = /* nginx */ ''
+                  access_log off;
+                  log_not_found off;
+                '';
+              };
+              "~ /\\.(?!well-known).*" = {
+                priority = 210;
+                extraConfig = /* nginx */ ''
+                  deny all;
+                '';
+              };
+              # Ask nginx to cache every URL starting with "/picture"
+              "/picture" = {
+                priority = 400;
+                tryFiles = "$uri $uri/ /index.php$is_args$args";
+                extraConfig = /* nginx */ ''
+                  set $no_cache 0; # Enable cache only there
+                '';
+              };
+              "/" = {
+                priority = 490;
+                tryFiles = "$uri $uri/ /index.php$is_args$args";
+                extraConfig = /* nginx */ ''
+                  # https://github.com/movim/movim/issues/314
+                  add_header Content-Security-Policy "default-src 'self'; img-src 'self' aesgcm: https:; media-src 'self' aesgcm: https:; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline';";
+                  set $no_cache 1;
+                '';
+              };
+              "~ \\.php$" = {
+                priority = 500;
+                tryFiles = "$uri =404";
+                extraConfig = /* nginx */ ''
+                  include ${config.services.nginx.package}/conf/fastcgi.conf;
+                  add_header X-Cache $upstream_cache_status;
+                  fastcgi_ignore_headers "Cache-Control" "Expires" "Set-Cookie";
+                  fastcgi_cache nginx_cache;
+                  fastcgi_cache_valid any 7d;
+                  fastcgi_cache_bypass $no_cache;
+                  fastcgi_no_cache $no_cache;
+                  fastcgi_split_path_info ^(.+\.php)(/.+)$;
+                  fastcgi_index index.php;
+                  fastcgi_pass unix:${fpm.socket};
+                '';
+              };
+              "/ws/" = {
+                priority = 900;
+                proxyPass = "http://${cfg.settings.DAEMON_INTERFACE}:${builtins.toString cfg.port}/";
+                proxyWebsockets = true;
+                recommendedProxySettings = true;
+                extraConfig = /* nginx */ ''
+                  proxy_set_header X-Forwarded-Proto $scheme;
+                  proxy_redirect off;
+                '';
+              };
+            };
+            extraConfig = /* ngnix */ ''
+              index index.php;
+            '';
+          }
+        ];
+      };
+
+      mysql = mkIf (cfg.database.createLocally && cfg.database.type == "mysql") {
+        enable = mkDefault true;
+        package = mkDefault pkgs.mariadb;
+        ensureDatabases = [ cfg.database.name ];
+        ensureUsers = [{
+          name = cfg.user;
+          ensureDBOwnership = true;
+        }];
+      };
+
+      postgresql = mkIf (cfg.database.createLocally && cfg.database.type == "postgresql") {
+        enable = mkDefault true;
+        ensureDatabases = [ cfg.database.name ];
+        ensureUsers = [{
+          name = cfg.user;
+          ensureDBOwnership = true;
+        }];
+        authentication = ''
+          host ${cfg.database.name} ${cfg.database.user} localhost trust
+        '';
+      };
+
+      phpfpm.pools.${pool} =
+        let
+          socketOwner =
+            if (cfg.nginx != null)
+            then config.services.nginx.user
+            else cfg.user;
+        in
+        {
+          phpPackage = package.php;
+          user = cfg.user;
+          group = cfg.group;
+
+          phpOptions = ''
+            error_log = 'stderr'
+            log_errors = on
+          '';
+
+          settings = {
+            "listen.owner" = socketOwner;
+            "listen.group" = cfg.group;
+            "listen.mode" = "0660";
+            "catch_workers_output" = true;
+          } // cfg.poolConfig;
+        };
+    };
+
+    systemd = {
+      services.movim-data-setup = {
+        description = "Movim setup: .env file, databases init, cache reload";
+        wantedBy = [ "multi-user.target" ];
+        requiredBy = [ "${phpExecutionUnit}.service" ];
+        before = [ "${phpExecutionUnit}.service" ];
+        after = lib.optional cfg.database.createLocally dbService;
+        requires = lib.optional cfg.database.createLocally dbService;
+
+        serviceConfig = {
+          Type = "oneshot";
+          User = cfg.user;
+          Group = cfg.group;
+          UMask = "077";
+        } // lib.optionalAttrs (cfg.secretFile != null) {
+          LoadCredential = "env-secrets:${cfg.secretFile}";
+        };
+
+        script = ''
+          # Env vars
+          rm -f ${cfg.dataDir}/.env
+          cp --no-preserve=all ${configFile} ${cfg.dataDir}/.env
+          echo -e '\n' >> ${cfg.dataDir}/.env
+          if [[ -f "$CREDENTIALS_DIRECTORY/env-secrets"  ]]; then
+            cat "$CREDENTIALS_DIRECTORY/env-secrets" >> ${cfg.dataDir}/.env
+            echo -e '\n' >> ${cfg.dataDir}/.env
+          fi
+
+          # Caches, logs
+          mkdir -p ${cfg.dataDir}/public/cache ${cfg.logDir} ${cfg.runtimeDir}/cache
+          chmod -R ug+rw ${cfg.dataDir}/public/cache
+          chmod -R ug+rw ${cfg.logDir}
+          chmod -R ug+rwx ${cfg.runtimeDir}/cache
+
+          # Migrations
+          MOVIM_VERSION="${package.version}"
+          if [[ ! -f "${cfg.dataDir}/.migration-version" ]] || [[ "$MOVIM_VERSION" != "$(<${cfg.dataDir}/.migration-version)" ]]; then
+            ${package}/bin/movim-composer movim:migrate && echo $MOVIM_VERSION > ${cfg.dataDir}/.migration-version
+          fi
+        ''
+        + lib.optionalString (podConfigFlags != "") (
+          let
+            flags = lib.concatStringsSep " "
+              ([ "--no-interaction" ]
+                ++ lib.optional cfg.debug "-vvv"
+                ++ lib.optional (!cfg.debug && cfg.verbose) "-v");
+          in
+          ''
+            ${lib.getExe package} config ${podConfigFlags}
+          ''
+        );
+      };
+
+      services.movim = {
+        description = "Movim daemon";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "movim-data-setup.service" ];
+        requires = [ "movim-data-setup.service" ]
+          ++ lib.optional cfg.database.createLocally dbService;
+        environment = {
+          PUBLIC_URL = "//${cfg.domain}";
+          WS_PORT = builtins.toString cfg.port;
+        };
+
+        serviceConfig = {
+          User = cfg.user;
+          Group = cfg.group;
+          WorkingDirectory = "${package}/share/php/movim";
+          ExecStart = "${lib.getExe package} start";
+        };
+      };
+
+      services.${phpExecutionUnit} = {
+        after = [ "movim-data-setup.service" ];
+        requires = [ "movim-data-setup.service" ]
+          ++ lib.optional cfg.database.createLocally dbService;
+      };
+
+      tmpfiles.settings."10-movim" = with cfg; {
+        "${dataDir}".d = { inherit user group; mode = "0710"; };
+        "${dataDir}/public".d = { inherit user group; mode = "0750"; };
+        "${dataDir}/public/cache".d = { inherit user group; mode = "0750"; };
+        "${runtimeDir}".d = { inherit user group; mode = "0700"; };
+        "${runtimeDir}/cache".d = { inherit user group; mode = "0700"; };
+        "${logDir}".d = { inherit user group; mode = "0700"; };
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/web-apps/outline.nix b/nixos/modules/services/web-apps/outline.nix
index 09dd6f83f39ac..891d78d4045b4 100644
--- a/nixos/modules/services/web-apps/outline.nix
+++ b/nixos/modules/services/web-apps/outline.nix
@@ -784,7 +784,7 @@ in
         # onboarding files:
         WorkingDirectory = "${cfg.package}/share/outline";
         # In case this directory is not in /var/lib/outline, it needs to be made writable explicitly
-        ReadWritePaths = [ cfg.storage.localRootDir ];
+        ReadWritePaths = lib.mkIf (cfg.storage.storageType == "local") [ cfg.storage.localRootDir ];
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/silverbullet.nix b/nixos/modules/services/web-apps/silverbullet.nix
new file mode 100644
index 0000000000000..a0c6ee34d262f
--- /dev/null
+++ b/nixos/modules/services/web-apps/silverbullet.nix
@@ -0,0 +1,123 @@
+{ config
+, pkgs
+, lib
+, ...
+}:
+let
+  cfg = config.services.silverbullet;
+  defaultUser = "silverbullet";
+  defaultGroup = defaultUser;
+  defaultSpaceDir = "/var/lib/silverbullet";
+in
+{
+  options = {
+    services.silverbullet = {
+      enable = lib.mkEnableOption (lib.mdDoc "Silverbullet, an open-source, self-hosted, offline-capable Personal Knowledge Management (PKM) web application.");
+
+      package = lib.mkPackageOptionMD pkgs "silverbullet" { };
+
+      openFirewall = lib.mkOption {
+        type = lib.types.bool;
+        default = false;
+        description = lib.mdDoc "Open port in the firewall.";
+      };
+
+      listenPort = lib.mkOption {
+        type = lib.types.int;
+        default = 3000;
+        description = lib.mdDoc "Port to listen on.";
+      };
+
+      listenAddress = lib.mkOption {
+        type = lib.types.str;
+        default = "127.0.0.1";
+        description = lib.mdDoc "Address or hostname to listen on. Defaults to 127.0.0.1.";
+      };
+
+      spaceDir = lib.mkOption {
+        type = lib.types.path;
+        default = defaultSpaceDir;
+        example = "/home/yourUser/silverbullet";
+        description = lib.mdDoc ''
+          Folder to store Silverbullet's space/workspace.
+          By default it is located at `${defaultSpaceDir}`.
+        '';
+      };
+
+      user = lib.mkOption {
+        type = lib.types.str;
+        default = defaultUser;
+        example = "yourUser";
+        description = lib.mdDoc ''
+          The user to run Silverbullet as.
+          By default, a user named `${defaultUser}` will be created whose space
+          directory is [spaceDir](#opt-services.silverbullet.spaceDir).
+        '';
+      };
+
+      group = lib.mkOption {
+        type = lib.types.str;
+        default = defaultGroup;
+        example = "yourGroup";
+        description = lib.mdDoc ''
+          The group to run Silverbullet under.
+          By default, a group named `${defaultGroup}` will be created.
+        '';
+      };
+
+      envFile = lib.mkOption {
+        type = lib.types.nullOr lib.types.path;
+        default = null;
+        example = "/etc/silverbullet.env";
+        description = lib.mdDoc ''
+          File containing extra environment variables. For example:
+
+          ```
+          SB_USER=user:password
+          SB_AUTH_TOKEN=abcdefg12345
+          ```
+        '';
+      };
+
+      extraArgs = lib.mkOption {
+        type = lib.types.listOf lib.types.str;
+        default = [ ];
+        example = [ "--db /path/to/silverbullet.db" ];
+        description = lib.mdDoc "Extra arguments passed to silverbullet.";
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    systemd.services.silverbullet = {
+      description = "Silverbullet service";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      preStart = lib.mkIf (!lib.hasPrefix "/var/lib/" cfg.spaceDir) "mkdir -p '${cfg.spaceDir}'";
+      serviceConfig = {
+        Type = "simple";
+        User = "${cfg.user}";
+        Group = "${cfg.group}";
+        EnvironmentFile = lib.mkIf (cfg.envFile != null) "${cfg.envFile}";
+        StateDirectory = lib.mkIf (lib.hasPrefix "/var/lib/" cfg.spaceDir) (lib.last (lib.splitString "/" cfg.spaceDir));
+        ExecStart = "${lib.getExe cfg.package} --port ${toString cfg.listenPort} --hostname '${cfg.listenAddress}' '${cfg.spaceDir}' " + lib.concatStringsSep " " cfg.extraArgs;
+        Restart = "on-failure";
+      };
+    };
+
+    networking.firewall = lib.mkIf cfg.openFirewall {
+      allowedTCPPorts = [ cfg.listenPort ];
+    };
+
+    users.users.${defaultUser} = lib.mkIf (cfg.user == defaultUser) {
+      isSystemUser = true;
+      group = cfg.group;
+      description = "Silverbullet daemon user";
+    };
+
+    users.groups.${defaultGroup} = lib.mkIf (cfg.group == defaultGroup) { };
+  };
+
+  meta.maintainers = with lib.maintainers; [ aorith ];
+}
diff --git a/nixos/modules/services/x11/desktop-managers/budgie.nix b/nixos/modules/services/x11/desktop-managers/budgie.nix
index 466ef5c565b7e..d6e6bb2fa14e8 100644
--- a/nixos/modules/services/x11/desktop-managers/budgie.nix
+++ b/nixos/modules/services/x11/desktop-managers/budgie.nix
@@ -43,6 +43,8 @@ let
   budgie-control-center = pkgs.budgie.budgie-control-center.override {
     enableSshSocket = config.services.openssh.startWhenNeeded;
   };
+
+  notExcluded = pkg: (!(lib.elem pkg config.environment.budgie.excludePackages));
 in {
   meta.maintainers = lib.teams.budgie.members;
 
@@ -91,7 +93,7 @@ in {
   };
 
   config = mkIf cfg.enable {
-    services.xserver.displayManager.sessionPackages = with pkgs; [
+    services.displayManager.sessionPackages = with pkgs; [
       budgie.budgie-desktop
     ];
 
@@ -160,7 +162,7 @@ in {
       ++ cfg.sessionPath;
 
     # Both budgie-desktop-view and nemo defaults to this emulator.
-    programs.gnome-terminal.enable = mkDefault true;
+    programs.gnome-terminal.enable = mkDefault (notExcluded pkgs.gnome.gnome-terminal);
 
     # Fonts.
     fonts.packages = [
diff --git a/nixos/modules/services/x11/desktop-managers/cinnamon.nix b/nixos/modules/services/x11/desktop-managers/cinnamon.nix
index f5a6c05865c47..6983b51376fd4 100644
--- a/nixos/modules/services/x11/desktop-managers/cinnamon.nix
+++ b/nixos/modules/services/x11/desktop-managers/cinnamon.nix
@@ -60,7 +60,7 @@ in
 
   config = mkMerge [
     (mkIf cfg.enable {
-      services.xserver.displayManager.sessionPackages = [ pkgs.cinnamon.cinnamon-common ];
+      services.displayManager.sessionPackages = [ pkgs.cinnamon.cinnamon-common ];
 
       services.xserver.displayManager.lightdm.greeters.slick = {
         enable = mkDefault true;
@@ -95,7 +95,7 @@ in
       '';
 
       # Default services
-      services.blueman.enable = mkDefault true;
+      services.blueman.enable = mkDefault (notExcluded pkgs.blueman);
       hardware.bluetooth.enable = mkDefault true;
       hardware.pulseaudio.enable = mkDefault true;
       security.polkit.enable = true;
@@ -228,10 +228,10 @@ in
     })
 
     (mkIf serviceCfg.apps.enable {
-      programs.geary.enable = mkDefault true;
-      programs.gnome-disks.enable = mkDefault true;
-      programs.gnome-terminal.enable = mkDefault true;
-      programs.file-roller.enable = mkDefault true;
+      programs.geary.enable = mkDefault (notExcluded pkgs.gnome.geary);
+      programs.gnome-disks.enable = mkDefault (notExcluded pkgs.gnome.gnome-disk-utility);
+      programs.gnome-terminal.enable = mkDefault (notExcluded pkgs.gnome.gnome-terminal);
+      programs.file-roller.enable = mkDefault (notExcluded pkgs.gnome.file-roller);
 
       environment.systemPackages = with pkgs // pkgs.gnome // pkgs.cinnamon; utils.removePackagesByName [
         # cinnamon team apps
diff --git a/nixos/modules/services/x11/desktop-managers/deepin.nix b/nixos/modules/services/x11/desktop-managers/deepin.nix
index 902e3a9317dd1..61f6fece58708 100644
--- a/nixos/modules/services/x11/desktop-managers/deepin.nix
+++ b/nixos/modules/services/x11/desktop-managers/deepin.nix
@@ -38,8 +38,8 @@ in
 
   config = mkIf cfg.enable
     {
-      services.xserver.displayManager.sessionPackages = [ pkgs.deepin.dde-session ];
-      services.xserver.displayManager.defaultSession = mkDefault "dde-x11";
+      services.displayManager.sessionPackages = [ pkgs.deepin.dde-session ];
+      services.displayManager.defaultSession = mkDefault "dde-x11";
 
       # Update the DBus activation environment after launching the desktop manager.
       services.xserver.displayManager.sessionCommands = ''
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index 33d0a7b526436..896d8dcbff40f 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -87,7 +87,7 @@ in
         default = null;
         example = "none";
         description = lib.mdDoc ''
-          **Deprecated**, please use [](#opt-services.xserver.displayManager.defaultSession) instead.
+          **Deprecated**, please use [](#opt-services.displayManager.defaultSession) instead.
 
           Default desktop manager loaded if none have been chosen.
         '';
diff --git a/nixos/modules/services/x11/desktop-managers/enlightenment.nix b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
index 28dd408c923c8..d241c63436faa 100644
--- a/nixos/modules/services/x11/desktop-managers/enlightenment.nix
+++ b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
@@ -54,7 +54,7 @@ in
       "/share/locale"
     ];
 
-    services.xserver.displayManager.sessionPackages = [ pkgs.enlightenment.enlightenment ];
+    services.displayManager.sessionPackages = [ pkgs.enlightenment.enlightenment ];
 
     services.xserver.displayManager.sessionCommands = ''
       if test "$XDG_CURRENT_DESKTOP" = "Enlightenment"; then
diff --git a/nixos/modules/services/x11/desktop-managers/gnome.nix b/nixos/modules/services/x11/desktop-managers/gnome.nix
index 2cf9bc2eac37e..cc959bcf7bd58 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome.nix
@@ -261,7 +261,7 @@ in
       services.gnome.core-shell.enable = true;
       services.gnome.core-utilities.enable = mkDefault true;
 
-      services.xserver.displayManager.sessionPackages = [ pkgs.gnome.gnome-session.sessions ];
+      services.displayManager.sessionPackages = [ pkgs.gnome.gnome-session.sessions ];
 
       environment.extraInit = ''
         ${concatMapStrings (p: ''
@@ -285,7 +285,7 @@ in
     })
 
     (mkIf flashbackEnabled {
-      services.xserver.displayManager.sessionPackages =
+      services.displayManager.sessionPackages =
         let
           wmNames = map (wm: wm.wmName) flashbackWms;
           namesAreUnique = lib.unique wmNames == wmNames;
diff --git a/nixos/modules/services/x11/desktop-managers/lumina.nix b/nixos/modules/services/x11/desktop-managers/lumina.nix
index 7b694106bf7ee..9df9fe42a1ff6 100644
--- a/nixos/modules/services/x11/desktop-managers/lumina.nix
+++ b/nixos/modules/services/x11/desktop-managers/lumina.nix
@@ -27,7 +27,7 @@ in
 
   config = mkIf cfg.enable {
 
-    services.xserver.displayManager.sessionPackages = [
+    services.displayManager.sessionPackages = [
       pkgs.lumina.lumina
     ];
 
diff --git a/nixos/modules/services/x11/desktop-managers/mate.nix b/nixos/modules/services/x11/desktop-managers/mate.nix
index 957eac7848e7f..e475442b9ef47 100644
--- a/nixos/modules/services/x11/desktop-managers/mate.nix
+++ b/nixos/modules/services/x11/desktop-managers/mate.nix
@@ -49,7 +49,7 @@ in
 
   config = mkMerge [
     (mkIf (cfg.enable || cfg.enableWaylandSession) {
-      services.xserver.displayManager.sessionPackages = [
+      services.displayManager.sessionPackages = [
         pkgs.mate.mate-session-manager
       ];
 
@@ -103,7 +103,7 @@ in
       environment.sessionVariables.NIX_GSETTINGS_OVERRIDES_DIR = "${pkgs.mate.mate-gsettings-overrides}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
 
       environment.systemPackages = [ pkgs.mate.mate-wayland-session ];
-      services.xserver.displayManager.sessionPackages = [ pkgs.mate.mate-wayland-session ];
+      services.displayManager.sessionPackages = [ pkgs.mate.mate-wayland-session ];
     })
   ];
 }
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index 2cfdc69b86e06..2115f8f0ab235 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -12,6 +12,7 @@ let
     extraGSettingsOverrides = cfg.extraGSettingsOverrides;
   };
 
+  notExcluded = pkg: (!(lib.elem pkg config.environment.pantheon.excludePackages));
 in
 
 {
@@ -96,7 +97,7 @@ in
         pkgs.pantheon.pantheon-agent-geoclue2
       ] config.environment.pantheon.excludePackages;
 
-      services.xserver.displayManager.sessionPackages = [ pkgs.pantheon.elementary-session-settings ];
+      services.displayManager.sessionPackages = [ pkgs.pantheon.elementary-session-settings ];
 
       # Ensure lightdm is used when Pantheon is enabled
       # Without it screen locking will be nonfunctional because of the use of lightlocker
@@ -109,7 +110,7 @@ in
 
       # Without this, elementary LightDM greeter will pre-select non-existent `default` session
       # https://github.com/elementary/greeter/issues/368
-      services.xserver.displayManager.defaultSession = mkDefault "pantheon";
+      services.displayManager.defaultSession = mkDefault "pantheon";
 
       services.xserver.displayManager.sessionCommands = ''
         if test "$XDG_CURRENT_DESKTOP" = "Pantheon"; then
@@ -190,22 +191,6 @@ in
         "org.gnome.SettingsDaemon.XSettings.service"
       ];
 
-      # https://github.com/elementary/gala/issues/1826#issuecomment-1890461298
-      systemd.user.services."io.elementary.gala.daemon@" = {
-        unitConfig = {
-          Description = "Gala Daemon";
-          BindsTo = "io.elementary.gala@.service";
-          After = "io.elementary.gala@.service";
-        };
-
-        serviceConfig = {
-          Type = "dbus";
-          BusName = "org.pantheon.gala.daemon";
-          ExecStart = "${pkgs.pantheon.gala}/bin/gala-daemon";
-          Slice = "session.slice";
-        };
-      };
-
       # Global environment
       environment.systemPackages = (with pkgs.pantheon; [
         elementary-session-settings
@@ -304,8 +289,8 @@ in
     })
 
     (mkIf serviceCfg.apps.enable {
-      programs.evince.enable = mkDefault true;
-      programs.file-roller.enable = mkDefault true;
+      programs.evince.enable = mkDefault (notExcluded pkgs.gnome.evince);
+      programs.file-roller.enable = mkDefault (notExcluded pkgs.gnome.file-roller);
 
       environment.systemPackages = utils.removePackagesByName ([
         pkgs.gnome.gnome-font-viewer
diff --git a/nixos/modules/services/x11/desktop-managers/phosh.nix b/nixos/modules/services/x11/desktop-managers/phosh.nix
index 75e02130addc5..41107788db0a5 100644
--- a/nixos/modules/services/x11/desktop-managers/phosh.nix
+++ b/nixos/modules/services/x11/desktop-managers/phosh.nix
@@ -220,7 +220,7 @@ in
 
     services.gnome.core-shell.enable = true;
     services.gnome.core-os-services.enable = true;
-    services.xserver.displayManager.sessionPackages = [ cfg.package ];
+    services.displayManager.sessionPackages = [ cfg.package ];
 
     environment.etc."phosh/phoc.ini".source =
       if builtins.isPath cfg.phocConfig then cfg.phocConfig
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index f516a29fb5db3..bb6e5873deff9 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -357,7 +357,7 @@ in
         pkgs.media-player-info
       ];
 
-      services.xserver.displayManager.sddm = {
+      services.displayManager.sddm = {
         theme = mkDefault "breeze";
       };
 
@@ -403,16 +403,16 @@ in
       system.nixos-generate-config.desktopConfiguration = [
         ''
           # Enable the Plasma 5 Desktop Environment.
-          services.xserver.displayManager.sddm.enable = true;
+          services.displayManager.sddm.enable = true;
           services.xserver.desktopManager.plasma5.enable = true;
         ''
       ];
 
-      services.xserver.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-workspace ];
+      services.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-workspace ];
       # Default to be `plasma` (X11) instead of `plasmawayland`, since plasma wayland currently has
       # many tiny bugs.
       # See: https://github.com/NixOS/nixpkgs/issues/143272
-      services.xserver.displayManager.defaultSession = mkDefault "plasma";
+      services.displayManager.defaultSession = mkDefault "plasma";
 
       environment.systemPackages =
         with pkgs.plasma5Packages;
@@ -538,7 +538,7 @@ in
         };
       };
 
-      services.xserver.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-mobile ];
+      services.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-mobile ];
     })
 
     # Plasma Bigscreen
@@ -559,7 +559,7 @@ in
           kdeconnect-kde
         ];
 
-      services.xserver.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-bigscreen ];
+      services.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-bigscreen ];
 
       # required for plasma-remotecontrollers to work correctly
       hardware.uinput.enable = true;
diff --git a/nixos/modules/services/x11/desktop-managers/surf-display.nix b/nixos/modules/services/x11/desktop-managers/surf-display.nix
index 38ebb9d02b4ac..e5f2c76f4ac25 100644
--- a/nixos/modules/services/x11/desktop-managers/surf-display.nix
+++ b/nixos/modules/services/x11/desktop-managers/surf-display.nix
@@ -119,7 +119,7 @@ in {
   };
 
   config = mkIf cfg.enable {
-    services.xserver.displayManager.sessionPackages = [
+    services.displayManager.sessionPackages = [
       pkgs.surf-display
     ];
 
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index c22048c6692e9..129bafefabe99 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -14,7 +14,6 @@ with lib;
 let
 
   cfg = config.services.xserver;
-  opt = options.services.xserver;
   xorg = pkgs.xorg;
 
   fontconfig = config.fonts.fontconfig;
@@ -70,14 +69,14 @@ let
           source ~/.xprofile
       fi
 
-      ${optionalString cfg.displayManager.job.logToJournal ''
+      ${optionalString config.services.displayManager.logToJournal ''
         if [ -z "$_DID_SYSTEMD_CAT" ]; then
           export _DID_SYSTEMD_CAT=1
           exec ${config.systemd.package}/bin/systemd-cat -t xsession "$0" "$@"
         fi
       ''}
 
-      ${optionalString cfg.displayManager.job.logToFile ''
+      ${optionalString config.services.displayManager.logToFile ''
         exec &> >(tee ~/.xsession-errors)
       ''}
 
@@ -130,41 +129,6 @@ let
           exit 1
       fi
     '';
-
-  installedSessions = pkgs.runCommand "desktops"
-    { # trivial derivation
-      preferLocalBuild = true;
-      allowSubstitutes = false;
-    }
-    ''
-      mkdir -p "$out/share/"{xsessions,wayland-sessions}
-
-      ${concatMapStrings (pkg: ''
-        for n in ${concatStringsSep " " pkg.providedSessions}; do
-          if ! test -f ${pkg}/share/wayland-sessions/$n.desktop -o \
-                    -f ${pkg}/share/xsessions/$n.desktop; then
-            echo "Couldn't find provided session name, $n.desktop, in session package ${pkg.name}:"
-            echo "  ${pkg}"
-            return 1
-          fi
-        done
-
-        if test -d ${pkg}/share/xsessions; then
-          ${pkgs.buildPackages.xorg.lndir}/bin/lndir ${pkg}/share/xsessions $out/share/xsessions
-        fi
-        if test -d ${pkg}/share/wayland-sessions; then
-          ${pkgs.buildPackages.xorg.lndir}/bin/lndir ${pkg}/share/wayland-sessions $out/share/wayland-sessions
-        fi
-      '') cfg.displayManager.sessionPackages}
-    '';
-
-  dmDefault = cfg.desktopManager.default;
-  # fallback default for cases when only default wm is set
-  dmFallbackDefault = if dmDefault != null then dmDefault else "none";
-  wmDefault = cfg.windowManager.default;
-
-  defaultSessionFromLegacyOptions = dmFallbackDefault + optionalString (wmDefault != null && wmDefault != "none") "+${wmDefault}";
-
 in
 
 {
@@ -215,35 +179,6 @@ in
         '';
       };
 
-      hiddenUsers = mkOption {
-        type = types.listOf types.str;
-        default = [ "nobody" ];
-        description = lib.mdDoc ''
-          A list of users which will not be shown in the display manager.
-        '';
-      };
-
-      sessionPackages = mkOption {
-        type = with types; listOf (package // {
-          description = "package with provided sessions";
-          check = p: assertMsg
-            (package.check p && p ? providedSessions
-            && p.providedSessions != [] && all isString p.providedSessions)
-            ''
-              Package, '${p.name}', did not specify any session names, as strings, in
-              'passthru.providedSessions'. This is required when used as a session package.
-
-              The session names can be looked up in:
-                ${p}/share/xsessions
-                ${p}/share/wayland-sessions
-           '';
-        });
-        default = [];
-        description = lib.mdDoc ''
-          A list of packages containing x11 or wayland session files to be passed to the display manager.
-        '';
-      };
-
       session = mkOption {
         default = [];
         type = types.listOf types.attrs;
@@ -274,51 +209,6 @@ in
         '';
       };
 
-      sessionData = mkOption {
-        description = lib.mdDoc "Data exported for display managers’ convenience";
-        internal = true;
-        default = {};
-        apply = val: {
-          wrapper = xsessionWrapper;
-          desktops = installedSessions;
-          sessionNames = concatMap (p: p.providedSessions) cfg.displayManager.sessionPackages;
-          # We do not want to force users to set defaultSession when they have only single DE.
-          autologinSession =
-            if cfg.displayManager.defaultSession != null then
-              cfg.displayManager.defaultSession
-            else if cfg.displayManager.sessionData.sessionNames != [] then
-              head cfg.displayManager.sessionData.sessionNames
-            else
-              null;
-        };
-      };
-
-      defaultSession = mkOption {
-        type = with types; nullOr str // {
-          description = "session name";
-          check = d:
-            assertMsg (d != null -> (str.check d && elem d cfg.displayManager.sessionData.sessionNames)) ''
-                Default graphical session, '${d}', not found.
-                Valid names for 'services.xserver.displayManager.defaultSession' are:
-                  ${concatStringsSep "\n  " cfg.displayManager.sessionData.sessionNames}
-              '';
-        };
-        default =
-          if dmDefault != null || wmDefault != null then
-            defaultSessionFromLegacyOptions
-          else
-            null;
-        defaultText = literalMD ''
-          Taken from display manager settings or window manager settings, if either is set.
-        '';
-        example = "gnome";
-        description = lib.mdDoc ''
-          Graphical session to pre-select in the session chooser (only effective for GDM, LightDM and SDDM).
-
-          On GDM, LightDM and SDDM, it will also be used as a session for auto-login.
-        '';
-      };
-
       importedVariables = mkOption {
         type = types.listOf (types.strMatching "[a-zA-Z_][a-zA-Z0-9_]*");
         visible = false;
@@ -327,106 +217,19 @@ in
         '';
       };
 
-      job = {
-
-        preStart = mkOption {
-          type = types.lines;
-          default = "";
-          example = "rm -f /var/log/my-display-manager.log";
-          description = lib.mdDoc "Script executed before the display manager is started.";
-        };
-
-        execCmd = mkOption {
-          type = types.str;
-          example = literalExpression ''"''${pkgs.lightdm}/bin/lightdm"'';
-          description = lib.mdDoc "Command to start the display manager.";
-        };
-
-        environment = mkOption {
-          type = types.attrsOf types.unspecified;
-          default = {};
-          description = lib.mdDoc "Additional environment variables needed by the display manager.";
-        };
-
-        logToFile = mkOption {
-          type = types.bool;
-          default = false;
-          description = lib.mdDoc ''
-            Whether the display manager redirects the output of the
-            session script to {file}`~/.xsession-errors`.
-          '';
-        };
-
-        logToJournal = mkOption {
-          type = types.bool;
-          default = true;
-          description = lib.mdDoc ''
-            Whether the display manager redirects the output of the
-            session script to the systemd journal.
-          '';
-        };
-
-      };
-
-      # Configuration for automatic login. Common for all DM.
-      autoLogin = mkOption {
-        type = types.submodule ({ config, options, ... }: {
-          options = {
-            enable = mkOption {
-              type = types.bool;
-              default = config.user != null;
-              defaultText = literalExpression "config.${options.user} != null";
-              description = lib.mdDoc ''
-                Automatically log in as {option}`autoLogin.user`.
-              '';
-            };
-
-            user = mkOption {
-              type = types.nullOr types.str;
-              default = null;
-              description = lib.mdDoc ''
-                User to be used for the automatic login.
-              '';
-            };
-          };
-        });
-
-        default = {};
-        description = lib.mdDoc ''
-          Auto login configuration attrset.
-        '';
-      };
-
     };
 
   };
 
   config = {
     assertions = [
-      { assertion = cfg.displayManager.autoLogin.enable -> cfg.displayManager.autoLogin.user != null;
-        message = ''
-          services.xserver.displayManager.autoLogin.enable requires services.xserver.displayManager.autoLogin.user to be set
-        '';
-      }
       {
         assertion = cfg.desktopManager.default != null || cfg.windowManager.default != null -> cfg.displayManager.defaultSession == defaultSessionFromLegacyOptions;
-        message = "You cannot use both services.xserver.displayManager.defaultSession option and legacy options (services.xserver.desktopManager.default and services.xserver.windowManager.default).";
+        message = "You cannot use both services.displayManager.defaultSession option and legacy options (services.xserver.desktopManager.default and services.xserver.windowManager.default).";
       }
     ];
 
-    warnings =
-      mkIf (dmDefault != null || wmDefault != null) [
-        ''
-          The following options are deprecated:
-            ${concatStringsSep "\n  " (map ({c, t}: t) (filter ({c, t}: c != null) [
-            { c = dmDefault; t = "- services.xserver.desktopManager.default"; }
-            { c = wmDefault; t = "- services.xserver.windowManager.default"; }
-            ]))}
-          Please use
-            services.xserver.displayManager.defaultSession = "${defaultSessionFromLegacyOptions}";
-          instead.
-        ''
-      ];
+    services.displayManager.sessionData.wrapper = xsessionWrapper;
 
     services.xserver.displayManager.xserverBin = "${xorg.xorgserver.out}/bin/X";
 
@@ -449,7 +252,7 @@ in
 
     # Create desktop files and scripts for starting sessions for WMs/DMs
     # that do not have upstream session files (those defined using services.{display,desktop,window}Manager.session options).
-    services.xserver.displayManager.sessionPackages =
+    services.displayManager.sessionPackages =
       let
         dms = filter (s: s.manage == "desktop") cfg.displayManager.session;
         wms = filter (s: s.manage == "window") cfg.displayManager.session;
@@ -511,20 +314,14 @@ in
             )
             (cartesianProductOfSets { dm = dms; wm = wms; })
           );
-
-    # Make xsessions and wayland sessions available in XDG_DATA_DIRS
-    # as some programs have behavior that depends on them being present
-    environment.sessionVariables.XDG_DATA_DIRS = lib.mkIf (cfg.displayManager.sessionPackages != [ ]) [
-      "${cfg.displayManager.sessionData.desktops}/share"
-    ];
   };
 
   imports = [
     (mkRemovedOptionModule [ "services" "xserver" "displayManager" "desktopManagerHandlesLidAndPower" ]
      "The option is no longer necessary because all display managers have already delegated lid management to systemd.")
-    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "job" "logsXsession" ] [ "services" "xserver" "displayManager" "job" "logToFile" ])
-    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "logToJournal" ] [ "services" "xserver" "displayManager" "job" "logToJournal" ])
-    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "extraSessionFilesPackages" ] [ "services" "xserver" "displayManager" "sessionPackages" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "job" "logsXsession" ] [ "services" "displayManager" "logToFile" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "logToJournal" ] [ "services" "displayManager" "logToJournal" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "extraSessionFilesPackages" ] [ "services" "displayManager" "sessionPackages" ])
   ];
 
 }
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index 400e5601dc59a..6bdfe9ea6f8cd 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -32,7 +32,7 @@ let
     load-module module-position-event-sounds
   '';
 
-  defaultSessionName = config.services.xserver.displayManager.defaultSession;
+  defaultSessionName = config.services.displayManager.defaultSession;
 
   setSessionScript = pkgs.callPackage ./account-service-util.nix { };
 in
@@ -41,14 +41,12 @@ in
   imports = [
     (mkRenamedOptionModule [ "services" "xserver" "displayManager" "gdm" "autoLogin" "enable" ] [
       "services"
-      "xserver"
       "displayManager"
       "autoLogin"
       "enable"
     ])
     (mkRenamedOptionModule [ "services" "xserver" "displayManager" "gdm" "autoLogin" "user" ] [
       "services"
-      "xserver"
       "displayManager"
       "autoLogin"
       "user"
@@ -148,14 +146,14 @@ in
     services.xserver.display = null;
     services.xserver.verbose = null;
 
-    services.xserver.displayManager.job =
+    services.displayManager =
       {
         environment = {
           GDM_X_SERVER_EXTRA_ARGS = toString
             (filter (arg: arg != "-terminate") cfg.xserverArgs);
           XDG_DATA_DIRS = lib.makeSearchPath "share" [
             gdm # for gnome-login.session
-            cfg.sessionData.desktops
+            config.services.displayManager.sessionData.desktops
             pkgs.gnome.gnome-control-center # for accessibility icon
             pkgs.gnome.adwaita-icon-theme
             pkgs.hicolor-icon-theme # empty icon theme as a base
@@ -169,7 +167,7 @@ in
         execCmd = "exec ${gdm}/bin/gdm";
         preStart = optionalString (defaultSessionName != null) ''
           # Set default session in session chooser to a specified values – basically ignore session history.
-          ${setSessionScript}/bin/set-session ${cfg.sessionData.autologinSession}
+          ${setSessionScript}/bin/set-session ${config.services.displayManager.sessionData.autologinSession}
         '';
       };
 
@@ -265,14 +263,14 @@ in
       daemon = mkMerge [
         { WaylandEnable = cfg.gdm.wayland; }
         # nested if else didn't work
-        (mkIf (cfg.autoLogin.enable && cfg.gdm.autoLogin.delay != 0 ) {
+        (mkIf (config.services.displayManager.autoLogin.enable && cfg.gdm.autoLogin.delay != 0 ) {
           TimedLoginEnable = true;
-          TimedLogin = cfg.autoLogin.user;
+          TimedLogin = config.services.displayManager.autoLogin.user;
           TimedLoginDelay = cfg.gdm.autoLogin.delay;
         })
-        (mkIf (cfg.autoLogin.enable && cfg.gdm.autoLogin.delay == 0 ) {
+        (mkIf (config.services.displayManager.autoLogin.enable && cfg.gdm.autoLogin.delay == 0 ) {
           AutomaticLoginEnable = true;
-          AutomaticLogin = cfg.autoLogin.user;
+          AutomaticLogin = config.services.displayManager.autoLogin.user;
         })
       ];
       debug = mkIf cfg.gdm.debug {
@@ -282,7 +280,7 @@ in
 
     environment.etc."gdm/custom.conf".source = configFile;
 
-    environment.etc."gdm/Xsession".source = config.services.xserver.displayManager.sessionData.wrapper;
+    environment.etc."gdm/Xsession".source = config.services.displayManager.sessionData.wrapper;
 
     # GDM LFS PAM modules, adapted somehow to NixOS
     security.pam.services = {
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
index f4195c4c2dc39..8702d0b97ed2e 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
@@ -60,7 +60,7 @@ in
 
           Note that this greeter starts only the default X session.
           You can configure the default X session using
-          [](#opt-services.xserver.displayManager.defaultSession).
+          [](#opt-services.displayManager.defaultSession).
         '';
       };
 
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix
index dede7680ecb3a..b2ea8e6d94f21 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix
@@ -22,7 +22,7 @@ in
 
           Note that this greeter starts only the default X session.
           You can configure the default X session using
-          [](#opt-services.xserver.displayManager.defaultSession).
+          [](#opt-services.displayManager.defaultSession).
         '';
       };
 
@@ -81,7 +81,7 @@ in
       {
         assertion = dmcfg.defaultSession != null;
         message = ''
-          Please set: services.xserver.displayManager.defaultSession
+          Please set: services.displayManager.defaultSession
         '';
       }
     ];
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index 548d3c5bc46a5..cb6365bace352 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -5,9 +5,9 @@ with lib;
 let
 
   xcfg = config.services.xserver;
-  dmcfg = xcfg.displayManager;
+  dmcfg = config.services.displayManager;
   xEnv = config.systemd.services.display-manager.environment;
-  cfg = dmcfg.lightdm;
+  cfg = xcfg.displayManager.lightdm;
   sessionData = dmcfg.sessionData;
 
   setSessionScript = pkgs.callPackage ./account-service-util.nix { };
@@ -26,7 +26,7 @@ let
       else additionalArgs="-logfile /var/log/X.$display.log"
       fi
 
-      exec ${dmcfg.xserverBin} ${toString dmcfg.xserverArgs} $additionalArgs "$@"
+      exec ${xcfg.displayManager.xserverBin} ${toString xcfg.displayManager.xserverArgs} $additionalArgs "$@"
     '';
 
   usersConf = writeText "users.conf"
@@ -58,10 +58,10 @@ let
         autologin-user-timeout = ${toString cfg.autoLogin.timeout}
         autologin-session = ${sessionData.autologinSession}
       ''}
-      ${optionalString (dmcfg.setupCommands != "") ''
+      ${optionalString (xcfg.displayManager.setupCommands != "") ''
         display-setup-script=${pkgs.writeScript "lightdm-display-setup" ''
           #!${pkgs.bash}/bin/bash
-          ${dmcfg.setupCommands}
+          ${xcfg.displayManager.setupCommands}
         ''}
       ''}
       ${cfg.extraSeatDefaults}
@@ -86,14 +86,12 @@ in
     ./lightdm-greeters/mobile.nix
     (mkRenamedOptionModule [ "services" "xserver" "displayManager" "lightdm" "autoLogin" "enable" ] [
       "services"
-      "xserver"
       "displayManager"
       "autoLogin"
       "enable"
     ])
     (mkRenamedOptionModule [ "services" "xserver" "displayManager" "lightdm" "autoLogin" "user" ] [
      "services"
-     "xserver"
      "displayManager"
      "autoLogin"
      "user"
@@ -187,7 +185,7 @@ in
       }
       { assertion = dmcfg.autoLogin.enable -> sessionData.autologinSession != null;
         message = ''
-          LightDM auto-login requires that services.xserver.displayManager.defaultSession is set.
+          LightDM auto-login requires that services.displayManager.defaultSession is set.
         '';
       }
       { assertion = !cfg.greeter.enable -> (dmcfg.autoLogin.enable && cfg.autoLogin.timeout == 0);
@@ -203,12 +201,12 @@ in
 
     # Set default session in session chooser to a specified values – basically ignore session history.
     # Auto-login is already covered by a config value.
-    services.xserver.displayManager.job.preStart = optionalString (!dmcfg.autoLogin.enable && dmcfg.defaultSession != null) ''
+    services.displayManager.preStart = optionalString (!dmcfg.autoLogin.enable && dmcfg.defaultSession != null) ''
       ${setSessionScript}/bin/set-session ${dmcfg.defaultSession}
     '';
 
     # setSessionScript needs session-files in XDG_DATA_DIRS
-    services.xserver.displayManager.job.environment.XDG_DATA_DIRS = "${dmcfg.sessionData.desktops}/share/";
+    services.displayManager.environment.XDG_DATA_DIRS = "${dmcfg.sessionData.desktops}/share/";
 
     # setSessionScript wants AccountsService
     systemd.services.display-manager.wants = [
@@ -216,7 +214,7 @@ in
     ];
 
     # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH
-    services.xserver.displayManager.job.execCmd = ''
+    services.displayManager.execCmd = ''
       export PATH=${lightdm}/sbin:$PATH
       exec ${lightdm}/sbin/lightdm
     '';
diff --git a/nixos/modules/services/x11/display-managers/xpra.nix b/nixos/modules/services/x11/display-managers/xpra.nix
index 3e7c6b01b3e91..ce80e013e81e2 100644
--- a/nixos/modules/services/x11/display-managers/xpra.nix
+++ b/nixos/modules/services/x11/display-managers/xpra.nix
@@ -226,7 +226,7 @@ in
       VideoRam 192000
     '';
 
-    services.xserver.displayManager.job.execCmd = ''
+    services.displayManager.execCmd = ''
       ${optionalString (cfg.pulseaudio)
         "export PULSE_COOKIE=/run/pulse/.config/pulse/cookie"}
       exec ${pkgs.xpra}/bin/xpra ${if cfg.desktop == null then "start" else "start-desktop --start=${cfg.desktop}"} \
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
index e180f2693e0c6..527c95bb14ac3 100644
--- a/nixos/modules/services/x11/window-managers/default.nix
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -77,7 +77,7 @@ in
         default = null;
         example = "wmii";
         description = lib.mdDoc ''
-          **Deprecated**, please use [](#opt-services.xserver.displayManager.defaultSession) instead.
+          **Deprecated**, please use [](#opt-services.displayManager.defaultSession) instead.
 
           Default window manager loaded if none have been chosen.
         '';
diff --git a/nixos/modules/services/x11/window-managers/ragnarwm.nix b/nixos/modules/services/x11/window-managers/ragnarwm.nix
index 7242c8b1324c4..0f4c2660b1e07 100644
--- a/nixos/modules/services/x11/window-managers/ragnarwm.nix
+++ b/nixos/modules/services/x11/window-managers/ragnarwm.nix
@@ -18,7 +18,7 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
-    services.xserver.displayManager.sessionPackages = [ cfg.package ];
+    services.displayManager.sessionPackages = [ cfg.package ];
     environment.systemPackages = [ cfg.package ];
   };
 
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index c5b168e608a4d..b9d39aa2b2ef2 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -639,28 +639,18 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
+    services.displayManager.enable = true;
 
     services.xserver.displayManager.lightdm.enable =
       let dmConf = cfg.displayManager;
           default = !(dmConf.gdm.enable
-                    || dmConf.sddm.enable
+                    || config.services.displayManager.sddm.enable
                     || dmConf.xpra.enable
                     || dmConf.sx.enable
                     || dmConf.startx.enable
                     || config.services.greetd.enable);
       in mkIf (default) (mkDefault true);
 
-    # so that the service won't be enabled when only startx is used
-    systemd.services.display-manager.enable  =
-      let dmConf = cfg.displayManager;
-          noDmUsed = !(dmConf.gdm.enable
-                    || dmConf.sddm.enable
-                    || dmConf.xpra.enable
-                    || dmConf.lightdm.enable);
-      in mkIf (noDmUsed) (mkDefault false);
-
-    hardware.opengl.enable = mkDefault true;
-
     services.xserver.videoDrivers = mkIf (cfg.videoDriver != null) [ cfg.videoDriver ];
 
     # FIXME: somehow check for unknown driver names.
@@ -694,19 +684,6 @@ in
           # -xkbdir command line option does not seems to be passed to xkbcomp.
           "X11/xkb".source = "${cfg.xkb.dir}";
         })
-      # localectl looks into 00-keyboard.conf
-      //{
-          "X11/xorg.conf.d/00-keyboard.conf".text = ''
-            Section "InputClass"
-              Identifier "Keyboard catchall"
-              MatchIsKeyboard "on"
-              Option "XkbModel" "${cfg.xkb.model}"
-              Option "XkbLayout" "${cfg.xkb.layout}"
-              Option "XkbOptions" "${cfg.xkb.options}"
-              Option "XkbVariant" "${cfg.xkb.variant}"
-            EndSection
-          '';
-        }
       # Needed since 1.18; see https://bugs.freedesktop.org/show_bug.cgi?id=89023#c5
       // (let cfgPath = "X11/xorg.conf.d/10-evdev.conf"; in
         {
@@ -726,31 +703,12 @@ in
         xorg.xprop
         xorg.xauth
         pkgs.xterm
-        pkgs.xdg-utils
         xorg.xf86inputevdev.out # get evdev.4 man page
-        pkgs.nixos-icons # needed for gnome and pantheon about dialog, nixos-manual and maybe more
       ] config.services.xserver.excludePackages
       ++ optional (elem "virtualbox" cfg.videoDrivers) xorg.xrefresh;
 
     environment.pathsToLink = [ "/share/X11" ];
 
-    xdg = {
-      autostart.enable = true;
-      menus.enable = true;
-      mime.enable = true;
-      icons.enable = true;
-    };
-
-    # The default max inotify watches is 8192.
-    # Nowadays most apps require a good number of inotify watches,
-    # the value below is used by default on several other distros.
-    boot.kernel.sysctl."fs.inotify.max_user_instances" = mkDefault 524288;
-    boot.kernel.sysctl."fs.inotify.max_user_watches" = mkDefault 524288;
-
-    programs.gnupg.agent.pinentryPackage = lib.mkOverride 1100 pkgs.pinentry-gnome3;
-
-    systemd.defaultUnit = mkIf cfg.autorun "graphical.target";
-
     systemd.services.display-manager =
       { description = "Display Manager";
 
@@ -761,17 +719,17 @@ in
         environment =
           optionalAttrs config.hardware.opengl.setLdLibraryPath
             { LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.addOpenGLRunpath.driverLink ]; }
-          // cfg.displayManager.job.environment;
+          // config.services.displayManager.environment;
 
         preStart =
           ''
-            ${cfg.displayManager.job.preStart}
+            ${config.services.displayManager.preStart}
 
             rm -f /tmp/.X0-lock
           '';
 
         # TODO: move declaring the systemd service to its own mkIf
-        script = mkIf (config.systemd.services.display-manager.enable == true) "${cfg.displayManager.job.execCmd}";
+        script = mkIf (config.systemd.services.display-manager.enable == true) "${config.services.displayManager.execCmd}";
 
         # Stop restarting if the display manager stops (crashes) 2 times
         # in one minute. Starting X typically takes 3-4s.
@@ -910,7 +868,6 @@ in
         ${cfg.extraConfig}
       '';
 
-    fonts.enableDefaultPackages = mkDefault true;
     fonts.packages = [
       (if cfg.upscaleDefaultCursor then fontcursormisc_hidpi else pkgs.xorg.fontcursormisc)
       pkgs.xorg.fontmiscmisc