about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/configuration/gpu-accel.chapter.md4
-rw-r--r--nixos/doc/manual/development/option-declarations.section.md4
-rw-r--r--nixos/doc/manual/from_md/configuration/gpu-accel.chapter.xml4
-rw-r--r--nixos/doc/manual/from_md/development/option-declarations.section.xml4
-rw-r--r--nixos/doc/manual/from_md/release-notes/rl-2211.section.xml6
-rw-r--r--nixos/doc/manual/release-notes/rl-2211.section.md2
-rw-r--r--nixos/lib/make-options-doc/default.nix31
-rw-r--r--nixos/lib/make-options-doc/mergeJSON.py243
-rw-r--r--nixos/maintainers/scripts/lxd/lxd-image-inner.nix2
-rw-r--r--nixos/modules/config/i18n.nix7
-rw-r--r--nixos/modules/config/resolvconf.nix6
-rw-r--r--nixos/modules/config/shells-environment.nix4
-rw-r--r--nixos/modules/config/system-environment.nix10
-rw-r--r--nixos/modules/config/users-groups.nix39
-rw-r--r--nixos/modules/config/xdg/portal.nix2
-rw-r--r--nixos/modules/hardware/logitech.nix5
-rw-r--r--nixos/modules/hardware/tuxedo-keyboard.nix2
-rw-r--r--nixos/modules/hardware/video/uvcvideo/default.nix12
-rw-r--r--nixos/modules/installer/cd-dvd/iso-image.nix2
-rw-r--r--nixos/modules/installer/tools/tools.nix2
-rw-r--r--nixos/modules/misc/nixpkgs.nix44
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/profiles/all-hardware.nix3
-rw-r--r--nixos/modules/programs/adb.nix4
-rw-r--r--nixos/modules/programs/firejail.nix7
-rw-r--r--nixos/modules/programs/gphoto2.nix4
-rw-r--r--nixos/modules/programs/kdeconnect.nix2
-rw-r--r--nixos/modules/programs/neovim.nix4
-rw-r--r--nixos/modules/programs/nncp.nix18
-rw-r--r--nixos/modules/programs/noisetorch.nix4
-rw-r--r--nixos/modules/programs/ssh.nix2
-rw-r--r--nixos/modules/programs/sway.nix2
-rw-r--r--nixos/modules/programs/turbovnc.nix6
-rw-r--r--nixos/modules/security/acme/default.nix8
-rw-r--r--nixos/modules/security/dhparams.nix2
-rw-r--r--nixos/modules/security/doas.nix60
-rw-r--r--nixos/modules/security/misc.nix4
-rw-r--r--nixos/modules/security/pam.nix111
-rw-r--r--nixos/modules/security/pam_mount.nix15
-rw-r--r--nixos/modules/security/pam_usb.nix5
-rw-r--r--nixos/modules/security/sudo.nix22
-rw-r--r--nixos/modules/services/backup/duplicity.nix6
-rw-r--r--nixos/modules/services/backup/restic.nix2
-rw-r--r--nixos/modules/services/backup/syncoid.nix6
-rw-r--r--nixos/modules/services/backup/zrepl.nix5
-rw-r--r--nixos/modules/services/continuous-integration/github-runner.nix5
-rw-r--r--nixos/modules/services/continuous-integration/gitlab-runner.nix94
-rw-r--r--nixos/modules/services/continuous-integration/hydra/default.nix2
-rw-r--r--nixos/modules/services/databases/firebird.nix6
-rw-r--r--nixos/modules/services/databases/mysql.nix6
-rw-r--r--nixos/modules/services/databases/neo4j.nix131
-rw-r--r--nixos/modules/services/databases/openldap.nix10
-rw-r--r--nixos/modules/services/databases/pgmanage.nix8
-rw-r--r--nixos/modules/services/databases/postgresql.nix9
-rw-r--r--nixos/modules/services/databases/victoriametrics.nix8
-rw-r--r--nixos/modules/services/development/zammad.nix2
-rw-r--r--nixos/modules/services/games/asf.nix4
-rw-r--r--nixos/modules/services/games/crossfire-server.nix2
-rw-r--r--nixos/modules/services/games/deliantra-server.nix2
-rw-r--r--nixos/modules/services/hardware/kanata.nix14
-rw-r--r--nixos/modules/services/hardware/lcd.nix9
-rw-r--r--nixos/modules/services/hardware/udev.nix23
-rw-r--r--nixos/modules/services/home-automation/home-assistant.nix8
-rw-r--r--nixos/modules/services/logging/filebeat.nix23
-rw-r--r--nixos/modules/services/logging/logrotate.nix10
-rw-r--r--nixos/modules/services/mail/mailman.nix4
-rw-r--r--nixos/modules/services/mail/nullmailer.nix12
-rw-r--r--nixos/modules/services/mail/postfixadmin.nix6
-rw-r--r--nixos/modules/services/mail/public-inbox.nix10
-rw-r--r--nixos/modules/services/mail/roundcube.nix10
-rw-r--r--nixos/modules/services/mail/sympa.nix18
-rw-r--r--nixos/modules/services/matrix/appservice-discord.nix17
-rw-r--r--nixos/modules/services/matrix/mautrix-facebook.nix11
-rw-r--r--nixos/modules/services/matrix/mautrix-telegram.nix11
-rw-r--r--nixos/modules/services/misc/autorandr.nix8
-rw-r--r--nixos/modules/services/misc/bees.nix13
-rw-r--r--nixos/modules/services/misc/etcd.nix4
-rw-r--r--nixos/modules/services/misc/etebase-server.nix4
-rw-r--r--nixos/modules/services/misc/geoipupdate.nix5
-rw-r--r--nixos/modules/services/misc/gitit.nix10
-rw-r--r--nixos/modules/services/misc/klipper.nix2
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix6
-rw-r--r--nixos/modules/services/misc/persistent-evdev.nix4
-rw-r--r--nixos/modules/services/misc/sourcehut/default.nix10
-rw-r--r--nixos/modules/services/misc/sssd.nix2
-rw-r--r--nixos/modules/services/misc/zoneminder.nix4
-rw-r--r--nixos/modules/services/monitoring/cadvisor.nix14
-rw-r--r--nixos/modules/services/monitoring/grafana-image-renderer.nix2
-rw-r--r--nixos/modules/services/monitoring/graphite.nix4
-rw-r--r--nixos/modules/services/monitoring/metricbeat.nix10
-rw-r--r--nixos/modules/services/monitoring/munin.nix28
-rw-r--r--nixos/modules/services/monitoring/nagios.nix2
-rw-r--r--nixos/modules/services/monitoring/netdata.nix8
-rw-r--r--nixos/modules/services/monitoring/parsedmarc.nix39
-rw-r--r--nixos/modules/services/monitoring/prometheus/default.nix15
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix8
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/process.nix2
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/script.nix2
-rw-r--r--nixos/modules/services/networking/biboumi.nix10
-rw-r--r--nixos/modules/services/networking/bird-lg.nix12
-rw-r--r--nixos/modules/services/networking/bird.nix12
-rw-r--r--nixos/modules/services/networking/coredns.nix5
-rw-r--r--nixos/modules/services/networking/ghostunnel.nix18
-rw-r--r--nixos/modules/services/networking/hans.nix6
-rw-r--r--nixos/modules/services/networking/iodine.nix6
-rw-r--r--nixos/modules/services/networking/kea.nix32
-rw-r--r--nixos/modules/services/networking/ncdns.nix4
-rw-r--r--nixos/modules/services/networking/networkmanager.nix11
-rw-r--r--nixos/modules/services/networking/nntp-proxy.nix4
-rw-r--r--nixos/modules/services/networking/nsd.nix4
-rw-r--r--nixos/modules/services/networking/ntp/ntpd.nix17
-rw-r--r--nixos/modules/services/networking/openconnect.nix14
-rw-r--r--nixos/modules/services/networking/openvpn.nix6
-rw-r--r--nixos/modules/services/networking/pleroma.nix8
-rw-r--r--nixos/modules/services/networking/seafile.nix2
-rw-r--r--nixos/modules/services/networking/smokeping.nix2
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix33
-rw-r--r--nixos/modules/services/networking/strongswan-swanctl/param-constructors.nix3
-rw-r--r--nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix90
-rw-r--r--nixos/modules/services/networking/wireguard.nix18
-rw-r--r--nixos/modules/services/networking/wpa_supplicant.nix2
-rw-r--r--nixos/modules/services/networking/yggdrasil.nix16
-rw-r--r--nixos/modules/services/networking/znc/default.nix21
-rw-r--r--nixos/modules/services/networking/znc/options.nix3
-rw-r--r--nixos/modules/services/security/privacyidea.nix8
-rw-r--r--nixos/modules/services/security/step-ca.nix4
-rw-r--r--nixos/modules/services/security/tor.nix16
-rw-r--r--nixos/modules/services/security/vault.nix4
-rw-r--r--nixos/modules/services/security/vaultwarden/default.nix2
-rw-r--r--nixos/modules/services/system/dbus.nix14
-rw-r--r--nixos/modules/services/system/earlyoom.nix16
-rw-r--r--nixos/modules/services/torrent/transmission.nix58
-rw-r--r--nixos/modules/services/web-apps/bookstack.nix4
-rw-r--r--nixos/modules/services/web-apps/dokuwiki.nix10
-rw-r--r--nixos/modules/services/web-apps/hedgedoc.nix5
-rw-r--r--nixos/modules/services/web-apps/keycloak.nix39
-rw-r--r--nixos/modules/services/web-apps/mastodon.nix36
-rw-r--r--nixos/modules/services/web-apps/mediawiki.nix2
-rw-r--r--nixos/modules/services/web-apps/nextcloud.nix26
-rw-r--r--nixos/modules/services/web-apps/node-red.nix5
-rw-r--r--nixos/modules/services/web-apps/snipe-it.nix4
-rw-r--r--nixos/modules/services/web-apps/trilium.nix2
-rw-r--r--nixos/modules/services/web-apps/virtlyst.nix73
-rw-r--r--nixos/modules/services/web-apps/wiki-js.nix5
-rw-r--r--nixos/modules/services/web-apps/wordpress.nix4
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/vhost-options.nix8
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix8
-rw-r--r--nixos/modules/services/web-servers/uwsgi.nix3
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix5
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix4
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix4
-rw-r--r--nixos/modules/services/x11/window-managers/fvwm2.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/xmonad.nix4
-rw-r--r--nixos/modules/system/activation/top-level.nix2
-rw-r--r--nixos/modules/system/boot/initrd-network.nix13
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix12
-rw-r--r--nixos/modules/system/boot/luksroot.nix6
-rw-r--r--nixos/modules/system/boot/networkd.nix15
-rw-r--r--nixos/modules/system/boot/stage-1.nix2
-rw-r--r--nixos/modules/system/boot/systemd/initrd.nix14
-rw-r--r--nixos/modules/system/boot/systemd/logind.nix9
-rw-r--r--nixos/modules/system/boot/systemd/tmpfiles.nix10
-rw-r--r--nixos/modules/tasks/auto-upgrade.nix6
-rw-r--r--nixos/modules/tasks/network-interfaces.nix2
-rw-r--r--nixos/modules/tasks/scsi-link-power-management.nix4
-rw-r--r--nixos/modules/virtualisation/nixos-containers.nix12
-rw-r--r--nixos/modules/virtualisation/podman/default.nix2
-rw-r--r--nixos/modules/virtualisation/podman/network-socket.nix2
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix6
-rw-r--r--nixos/release-combined.nix2
-rw-r--r--nixos/tests/couchdb.nix2
-rw-r--r--nixos/tests/docker-tools.nix4
-rw-r--r--nixos/tests/documize.nix6
-rw-r--r--nixos/tests/nginx-auth.nix8
-rw-r--r--nixos/tests/privacyidea.nix2
-rw-r--r--nixos/tests/prometheus-exporters.nix4
-rw-r--r--nixos/tests/sympa.nix2
-rw-r--r--nixos/tests/systemd-nspawn.nix6
-rw-r--r--nixos/tests/xmpp/xmpp-sendmessage.nix2
180 files changed, 1076 insertions, 1234 deletions
diff --git a/nixos/doc/manual/configuration/gpu-accel.chapter.md b/nixos/doc/manual/configuration/gpu-accel.chapter.md
index 08b6af5d98aea..835cbad554859 100644
--- a/nixos/doc/manual/configuration/gpu-accel.chapter.md
+++ b/nixos/doc/manual/configuration/gpu-accel.chapter.md
@@ -169,7 +169,7 @@ configuration, GPU devices have world-read/write permissions
 (`/dev/dri/renderD*`) or are tagged as `uaccess` (`/dev/dri/card*`). The
 access control lists of devices with the `uaccess` tag will be updated
 automatically when a user logs in through `systemd-logind`. For example,
-if the user *jane* is logged in, the access control list should look as
+if the user *alice* is logged in, the access control list should look as
 follows:
 
 ```ShellSession
@@ -178,7 +178,7 @@ $ getfacl /dev/dri/card0
 # owner: root
 # group: video
 user::rw-
-user:jane:rw-
+user:alice:rw-
 group::rw-
 mask::rw-
 other::---
diff --git a/nixos/doc/manual/development/option-declarations.section.md b/nixos/doc/manual/development/option-declarations.section.md
index 79914f2cb6ca9..8bf73a66456ba 100644
--- a/nixos/doc/manual/development/option-declarations.section.md
+++ b/nixos/doc/manual/development/option-declarations.section.md
@@ -127,14 +127,14 @@ lib.mkOption {
 ```nix
 lib.mkPackageOption pkgs "GHC" {
   default = [ "ghc" ];
-  example = "pkgs.haskell.package.ghc923.ghc.withPackages (hkgs: [ hkgs.primes ])";
+  example = "pkgs.haskell.packages.ghc924.ghc.withPackages (hkgs: [ hkgs.primes ])";
 }
 # is like
 lib.mkOption {
   type = lib.types.package;
   default = pkgs.ghc;
   defaultText = lib.literalExpression "pkgs.ghc";
-  example = lib.literalExpression "pkgs.haskell.package.ghc923.ghc.withPackages (hkgs: [ hkgs.primes ])";
+  example = lib.literalExpression "pkgs.haskell.packages.ghc924.ghc.withPackages (hkgs: [ hkgs.primes ])";
   description = "The GHC package to use.";
 }
 ```
diff --git a/nixos/doc/manual/from_md/configuration/gpu-accel.chapter.xml b/nixos/doc/manual/from_md/configuration/gpu-accel.chapter.xml
index 8e780c5dee95d..cc559a1933d92 100644
--- a/nixos/doc/manual/from_md/configuration/gpu-accel.chapter.xml
+++ b/nixos/doc/manual/from_md/configuration/gpu-accel.chapter.xml
@@ -194,7 +194,7 @@ environment.variables.VK_ICD_FILENAMES =
         devices with the <literal>uaccess</literal> tag will be updated
         automatically when a user logs in through
         <literal>systemd-logind</literal>. For example, if the user
-        <emphasis>jane</emphasis> is logged in, the access control list
+        <emphasis>alice</emphasis> is logged in, the access control list
         should look as follows:
       </para>
       <programlisting>
@@ -203,7 +203,7 @@ $ getfacl /dev/dri/card0
 # owner: root
 # group: video
 user::rw-
-user:jane:rw-
+user:alice:rw-
 group::rw-
 mask::rw-
 other::---
diff --git a/nixos/doc/manual/from_md/development/option-declarations.section.xml b/nixos/doc/manual/from_md/development/option-declarations.section.xml
index 03ec48f35fd78..d7c7f7716bead 100644
--- a/nixos/doc/manual/from_md/development/option-declarations.section.xml
+++ b/nixos/doc/manual/from_md/development/option-declarations.section.xml
@@ -193,14 +193,14 @@ lib.mkOption {
         <programlisting language="bash">
 lib.mkPackageOption pkgs &quot;GHC&quot; {
   default = [ &quot;ghc&quot; ];
-  example = &quot;pkgs.haskell.package.ghc923.ghc.withPackages (hkgs: [ hkgs.primes ])&quot;;
+  example = &quot;pkgs.haskell.packages.ghc924.ghc.withPackages (hkgs: [ hkgs.primes ])&quot;;
 }
 # is like
 lib.mkOption {
   type = lib.types.package;
   default = pkgs.ghc;
   defaultText = lib.literalExpression &quot;pkgs.ghc&quot;;
-  example = lib.literalExpression &quot;pkgs.haskell.package.ghc923.ghc.withPackages (hkgs: [ hkgs.primes ])&quot;;
+  example = lib.literalExpression &quot;pkgs.haskell.packages.ghc924.ghc.withPackages (hkgs: [ hkgs.primes ])&quot;;
   description = &quot;The GHC package to use.&quot;;
 }
 </programlisting>
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
index 882eea3c4a4a7..2e3dfea8cb6ed 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
@@ -281,6 +281,12 @@
       </listitem>
       <listitem>
         <para>
+          virtlyst package and <literal>services.virtlyst</literal>
+          module removed, due to lack of maintainers.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           The <literal>services.graphite.api</literal> and
           <literal>services.graphite.beacon</literal> NixOS options, and
           the <literal>python3.pkgs.graphite_api</literal>,
diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md
index a2757d67e89c9..6bc7d1917cae8 100644
--- a/nixos/doc/manual/release-notes/rl-2211.section.md
+++ b/nixos/doc/manual/release-notes/rl-2211.section.md
@@ -107,6 +107,8 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - xow package removed along with the `hardware.xow` module, due to the project being deprecated in favor of `xone`,  which is available via the `hardware.xone` module.
 
+- virtlyst package and `services.virtlyst` module removed, due to lack of maintainers.
+
 - The `services.graphite.api` and `services.graphite.beacon` NixOS options, and
   the `python3.pkgs.graphite_api`, `python3.pkgs.graphite_beacon` and
   `python3.pkgs.influxgraph` packages, have been removed due to lack of upstream
diff --git a/nixos/lib/make-options-doc/default.nix b/nixos/lib/make-options-doc/default.nix
index e039bc4a9b73d..6649fc41d41aa 100644
--- a/nixos/lib/make-options-doc/default.nix
+++ b/nixos/lib/make-options-doc/default.nix
@@ -99,14 +99,6 @@ let
 
   optionsNix = builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList);
 
-  pythonMD =
-    let
-      self = (pkgs.python3Minimal.override {
-        inherit self;
-        includeSiteCustomize = true;
-        });
-      in self.withPackages (p: [ p.mistune_2_0 ]);
-
 in rec {
   inherit optionsNix;
 
@@ -124,20 +116,17 @@ in rec {
 
   optionsJSON = pkgs.runCommand "options.json"
     { meta.description = "List of NixOS options in JSON format";
-      buildInputs = [ pkgs.brotli pythonMD ];
+      buildInputs = [
+        pkgs.brotli
+        (let
+          self = (pkgs.python3Minimal.override {
+            inherit self;
+            includeSiteCustomize = true;
+           });
+         in self.withPackages (p: [ p.mistune_2_0 ]))
+      ];
       options = builtins.toFile "options.json"
         (builtins.unsafeDiscardStringContext (builtins.toJSON optionsNix));
-      # convert markdown to docbook in its own derivation to cache the
-      # conversion results. the conversion is surprisingly expensive.
-      baseJSON =
-        if baseOptionsJSON != null
-        then
-          pkgs.runCommand "base-json-md-converted" {
-            buildInputs = [ pythonMD ];
-          } ''
-            python ${./mergeJSON.py} ${baseOptionsJSON} <(echo '{}') > $out
-          ''
-        else null;
     }
     ''
       # Export list of options in different format.
@@ -154,7 +143,7 @@ in rec {
           else ''
             python ${./mergeJSON.py} \
               ${lib.optionalString warningsAreErrors "--warnings-are-errors"} \
-              $baseJSON $options \
+              ${baseOptionsJSON} $options \
               > $dst/options.json
           ''
       }
diff --git a/nixos/lib/make-options-doc/mergeJSON.py b/nixos/lib/make-options-doc/mergeJSON.py
index e95352f4fe6f4..d7dc6ca30074e 100644
--- a/nixos/lib/make-options-doc/mergeJSON.py
+++ b/nixos/lib/make-options-doc/mergeJSON.py
@@ -3,6 +3,11 @@ import json
 import sys
 from typing import Any, Dict, List
 
+# for MD conversion
+import mistune
+import re
+from xml.sax.saxutils import escape, quoteattr
+
 JSON = Dict[str, Any]
 
 class Key:
@@ -41,137 +46,135 @@ def unpivot(options: Dict[Key, Option]) -> Dict[str, JSON]:
         result[opt.name] = opt.value
     return result
 
-# converts in-place!
-def convertMD(options: Dict[str, Any]) -> str:
-    import mistune
-    import re
-    from xml.sax.saxutils import escape, quoteattr
-
-    admonitions = {
-        '.warning': 'warning',
-        '.important': 'important',
-        '.note': 'note'
-    }
-    class Renderer(mistune.renderers.BaseRenderer):
-        def __init__(self, path):
-            self.path = path
-        def _get_method(self, name):
-            try:
-                return super(Renderer, self)._get_method(name)
-            except AttributeError:
-                def not_supported(*args, **kwargs):
-                    raise NotImplementedError("md node not supported yet", self.path, name, args, **kwargs)
-                return not_supported
-
-        def text(self, text):
-            return escape(text)
-        def paragraph(self, text):
-            return text + "\n\n"
-        def newline(self):
-            return "<literallayout>\n</literallayout>"
-        def codespan(self, text):
-            return f"<literal>{escape(text)}</literal>"
-        def block_code(self, text, info=None):
-            info = f" language={quoteattr(info)}" if info is not None else ""
-            return f"<programlisting{info}>\n{escape(text)}</programlisting>"
-        def link(self, link, text=None, title=None):
-            if link[0:1] == '#':
-                attr = "linkend"
-                link = quoteattr(link[1:])
-            else:
-                # try to faithfully reproduce links that were of the form <link href="..."/>
-                # in docbook format
-                if text == link:
-                    text = ""
-                attr = "xlink:href"
-                link = quoteattr(link)
-            return f"<link {attr}={link}>{text}</link>"
-        def list(self, text, ordered, level, start=None):
-            if ordered:
-                raise NotImplementedError("ordered lists not supported yet")
-            return f"<itemizedlist>\n{text}\n</itemizedlist>"
-        def list_item(self, text, level):
-            return f"<listitem><para>{text}</para></listitem>\n"
-        def block_text(self, text):
-            return text
-        def emphasis(self, text):
-            return f"<emphasis>{text}</emphasis>"
-        def strong(self, text):
-            return f"<emphasis role=\"strong\">{text}</emphasis>"
-        def admonition(self, text, kind):
-            if kind not in admonitions:
-                raise NotImplementedError(f"admonition {kind} not supported yet")
-            tag = admonitions[kind]
-            # we don't keep whitespace here because usually we'll contain only
-            # a single paragraph and the original docbook string is no longer
-            # available to restore the trailer.
-            return f"<{tag}><para>{text.rstrip()}</para></{tag}>"
-        def block_quote(self, text):
-            return f"<blockquote><para>{text}</para></blockquote>"
-        def command(self, text):
-            return f"<command>{escape(text)}</command>"
-        def option(self, text):
-            return f"<option>{escape(text)}</option>"
-        def file(self, text):
-            return f"<filename>{escape(text)}</filename>"
-        def manpage(self, page, section):
-            title = f"<refentrytitle>{escape(page)}</refentrytitle>"
-            vol = f"<manvolnum>{escape(section)}</manvolnum>"
-            return f"<citerefentry>{title}{vol}</citerefentry>"
-
-        def finalize(self, data):
-            return "".join(data)
-
-    plugins = []
-
+admonitions = {
+    '.warning': 'warning',
+    '.important': 'important',
+    '.note': 'note'
+}
+class Renderer(mistune.renderers.BaseRenderer):
+    def _get_method(self, name):
+        try:
+            return super(Renderer, self)._get_method(name)
+        except AttributeError:
+            def not_supported(*args, **kwargs):
+                raise NotImplementedError("md node not supported yet", name, args, **kwargs)
+            return not_supported
+
+    def text(self, text):
+        return escape(text)
+    def paragraph(self, text):
+        return text + "\n\n"
+    def newline(self):
+        return "<literallayout>\n</literallayout>"
+    def codespan(self, text):
+        return f"<literal>{escape(text)}</literal>"
+    def block_code(self, text, info=None):
+        info = f" language={quoteattr(info)}" if info is not None else ""
+        return f"<programlisting{info}>\n{escape(text)}</programlisting>"
+    def link(self, link, text=None, title=None):
+        tag = "link"
+        if link[0:1] == '#':
+            if text == "":
+                tag = "xref"
+            attr = "linkend"
+            link = quoteattr(link[1:])
+        else:
+            # try to faithfully reproduce links that were of the form <link href="..."/>
+            # in docbook format
+            if text == link:
+                text = ""
+            attr = "xlink:href"
+            link = quoteattr(link)
+        return f"<{tag} {attr}={link}>{text}</{tag}>"
+    def list(self, text, ordered, level, start=None):
+        if ordered:
+            raise NotImplementedError("ordered lists not supported yet")
+        return f"<itemizedlist>\n{text}\n</itemizedlist>"
+    def list_item(self, text, level):
+        return f"<listitem><para>{text}</para></listitem>\n"
+    def block_text(self, text):
+        return text
+    def emphasis(self, text):
+        return f"<emphasis>{text}</emphasis>"
+    def strong(self, text):
+        return f"<emphasis role=\"strong\">{text}</emphasis>"
+    def admonition(self, text, kind):
+        if kind not in admonitions:
+            raise NotImplementedError(f"admonition {kind} not supported yet")
+        tag = admonitions[kind]
+        # we don't keep whitespace here because usually we'll contain only
+        # a single paragraph and the original docbook string is no longer
+        # available to restore the trailer.
+        return f"<{tag}><para>{text.rstrip()}</para></{tag}>"
+    def block_quote(self, text):
+        return f"<blockquote><para>{text}</para></blockquote>"
+    def command(self, text):
+        return f"<command>{escape(text)}</command>"
+    def option(self, text):
+        return f"<option>{escape(text)}</option>"
+    def file(self, text):
+        return f"<filename>{escape(text)}</filename>"
+    def manpage(self, page, section):
+        title = f"<refentrytitle>{escape(page)}</refentrytitle>"
+        vol = f"<manvolnum>{escape(section)}</manvolnum>"
+        return f"<citerefentry>{title}{vol}</citerefentry>"
+
+    def finalize(self, data):
+        return "".join(data)
+
+def p_command(md):
     COMMAND_PATTERN = r'\{command\}`(.*?)`'
-    def command(md):
-        def parse(self, m, state):
-            return ('command', m.group(1))
-        md.inline.register_rule('command', COMMAND_PATTERN, parse)
-        md.inline.rules.append('command')
-    plugins.append(command)
+    def parse(self, m, state):
+        return ('command', m.group(1))
+    md.inline.register_rule('command', COMMAND_PATTERN, parse)
+    md.inline.rules.append('command')
 
+def p_file(md):
     FILE_PATTERN = r'\{file\}`(.*?)`'
-    def file(md):
-        def parse(self, m, state):
-            return ('file', m.group(1))
-        md.inline.register_rule('file', FILE_PATTERN, parse)
-        md.inline.rules.append('file')
-    plugins.append(file)
+    def parse(self, m, state):
+        return ('file', m.group(1))
+    md.inline.register_rule('file', FILE_PATTERN, parse)
+    md.inline.rules.append('file')
 
+def p_option(md):
     OPTION_PATTERN = r'\{option\}`(.*?)`'
-    def option(md):
-        def parse(self, m, state):
-            return ('option', m.group(1))
-        md.inline.register_rule('option', OPTION_PATTERN, parse)
-        md.inline.rules.append('option')
-    plugins.append(option)
+    def parse(self, m, state):
+        return ('option', m.group(1))
+    md.inline.register_rule('option', OPTION_PATTERN, parse)
+    md.inline.rules.append('option')
 
+def p_manpage(md):
     MANPAGE_PATTERN = r'\{manpage\}`(.*?)\((.+?)\)`'
-    def manpage(md):
-        def parse(self, m, state):
-            return ('manpage', m.group(1), m.group(2))
-        md.inline.register_rule('manpage', MANPAGE_PATTERN, parse)
-        md.inline.rules.append('manpage')
-    plugins.append(manpage)
+    def parse(self, m, state):
+        return ('manpage', m.group(1), m.group(2))
+    md.inline.register_rule('manpage', MANPAGE_PATTERN, parse)
+    md.inline.rules.append('manpage')
 
+def p_admonition(md):
     ADMONITION_PATTERN = re.compile(r'^::: \{([^\n]*?)\}\n(.*?)^:::\n', flags=re.MULTILINE|re.DOTALL)
-    def admonition(md):
-        def parse(self, m, state):
-            return {
-                'type': 'admonition',
-                'children': self.parse(m.group(2), state),
-                'params': [ m.group(1) ],
-            }
-        md.block.register_rule('admonition', ADMONITION_PATTERN, parse)
-        md.block.rules.append('admonition')
-    plugins.append(admonition)
+    def parse(self, m, state):
+        return {
+            'type': 'admonition',
+            'children': self.parse(m.group(2), state),
+            'params': [ m.group(1) ],
+        }
+    md.block.register_rule('admonition', ADMONITION_PATTERN, parse)
+    md.block.rules.append('admonition')
+
+md = mistune.create_markdown(renderer=Renderer(), plugins=[
+    p_command, p_file, p_option, p_manpage, p_admonition
+])
 
+# converts in-place!
+def convertMD(options: Dict[str, Any]) -> str:
     def convertString(path: str, text: str) -> str:
-        rendered = mistune.markdown(text, renderer=Renderer(path), plugins=plugins)
-        # keep trailing spaces so we can diff the generated XML to check for conversion bugs.
-        return rendered.rstrip() + text[len(text.rstrip()):]
+        try:
+            rendered = md(text)
+            # keep trailing spaces so we can diff the generated XML to check for conversion bugs.
+            return rendered.rstrip() + text[len(text.rstrip()):]
+        except:
+            print(f"error in {path}")
+            raise
 
     def optionIs(option: Dict[str, Any], key: str, typ: str) -> bool:
         if key not in option: return False
diff --git a/nixos/maintainers/scripts/lxd/lxd-image-inner.nix b/nixos/maintainers/scripts/lxd/lxd-image-inner.nix
index 74634fd1671c1..ead3d4e994014 100644
--- a/nixos/maintainers/scripts/lxd/lxd-image-inner.nix
+++ b/nixos/maintainers/scripts/lxd/lxd-image-inner.nix
@@ -55,7 +55,7 @@ with lib;
   # services.xserver.libinput.enable = true;
 
   # Define a user account. Don't forget to set a password with ‘passwd’.
-  # users.users.jane = {
+  # users.users.alice = {
   #   isNormalUser = true;
   #   extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
   # };
diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix
index 80ef515fbfe20..f73f10f0f3691 100644
--- a/nixos/modules/config/i18n.nix
+++ b/nixos/modules/config/i18n.nix
@@ -71,12 +71,11 @@ with lib;
             ))
         '';
         example = ["en_US.UTF-8/UTF-8" "nl_NL.UTF-8/UTF-8" "nl_NL/ISO-8859-1"];
-        description = ''
+        description = lib.mdDoc ''
           List of locales that the system should support.  The value
-          <literal>"all"</literal> means that all locales supported by
+          `"all"` means that all locales supported by
           Glibc will be installed.  A full list of supported locales
-          can be found at <link
-          xlink:href="https://sourceware.org/git/?p=glibc.git;a=blob;f=localedata/SUPPORTED"/>.
+          can be found at <https://sourceware.org/git/?p=glibc.git;a=blob;f=localedata/SUPPORTED>.
         '';
       };
 
diff --git a/nixos/modules/config/resolvconf.nix b/nixos/modules/config/resolvconf.nix
index cdc40d2c810bf..76605a063a47a 100644
--- a/nixos/modules/config/resolvconf.nix
+++ b/nixos/modules/config/resolvconf.nix
@@ -83,9 +83,9 @@ in
       dnsExtensionMechanism = mkOption {
         type = types.bool;
         default = true;
-        description = ''
-          Enable the <code>edns0</code> option in <filename>resolv.conf</filename>. With
-          that option set, <code>glibc</code> supports use of the extension mechanisms for
+        description = lib.mdDoc ''
+          Enable the `edns0` option in {file}`resolv.conf`. With
+          that option set, `glibc` supports use of the extension mechanisms for
           DNS (EDNS) specified in RFC 2671. The most popular user of that feature is DNSSEC,
           which does not work without it.
         '';
diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix
index 660b2e1fa4bfb..2fda71749c09e 100644
--- a/nixos/modules/config/shells-environment.nix
+++ b/nixos/modules/config/shells-environment.nix
@@ -109,11 +109,11 @@ in
 
     environment.shellAliases = mkOption {
       example = { l = null; ll = "ls -l"; };
-      description = ''
+      description = lib.mdDoc ''
         An attribute set that maps aliases (the top level attribute names in
         this option) to command strings or directly to build outputs. The
         aliases are added to all users' shells.
-        Aliases mapped to <code>null</code> are ignored.
+        Aliases mapped to `null` are ignored.
       '';
       type = with types; attrsOf (nullOr (either str path));
     };
diff --git a/nixos/modules/config/system-environment.nix b/nixos/modules/config/system-environment.nix
index d2a66b8d932df..1e05ab7d0f2b7 100644
--- a/nixos/modules/config/system-environment.nix
+++ b/nixos/modules/config/system-environment.nix
@@ -16,7 +16,7 @@ in
 
     environment.sessionVariables = mkOption {
       default = {};
-      description = ''
+      description = lib.mdDoc ''
         A set of environment variables used in the global environment.
         These variables will be set by PAM early in the login process.
 
@@ -25,12 +25,12 @@ in
         colon characters.
 
         Note, due to limitations in the PAM format values may not
-        contain the <literal>"</literal> character.
+        contain the `"` character.
 
         Also, these variables are merged into
-        <xref linkend="opt-environment.variables"/> and it is
+        [](#opt-environment.variables) and it is
         therefore not possible to use PAM style variables such as
-        <code>@{HOME}</code>.
+        `@{HOME}`.
       '';
       type = with types; attrsOf (either str (listOf str));
       apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
@@ -58,7 +58,7 @@ in
         Also, these variables are merged into
         <xref linkend="opt-environment.profileRelativeEnvVars"/> and it is
         therefore not possible to use PAM style variables such as
-        <code>@{HOME}</code>.
+        <literal>@{HOME}</literal>.
       '';
     };
 
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 466e3f6138a50..915687d1799a0 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -100,17 +100,17 @@ let
       isNormalUser = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Indicates whether this is an account for a “real” user. This
-          automatically sets <option>group</option> to
-          <literal>users</literal>, <option>createHome</option> to
-          <literal>true</literal>, <option>home</option> to
-          <filename>/home/<replaceable>username</replaceable></filename>,
-          <option>useDefaultShell</option> to <literal>true</literal>,
-          and <option>isSystemUser</option> to
-          <literal>false</literal>.
-          Exactly one of <literal>isNormalUser</literal> and
-          <literal>isSystemUser</literal> must be true.
+          automatically sets {option}`group` to
+          `users`, {option}`createHome` to
+          `true`, {option}`home` to
+          {file}`/home/«username»`,
+          {option}`useDefaultShell` to `true`,
+          and {option}`isSystemUser` to
+          `false`.
+          Exactly one of `isNormalUser` and
+          `isSystemUser` must be true.
         '';
       };
 
@@ -151,13 +151,12 @@ let
       pamMount = mkOption {
         type = with types; attrsOf str;
         default = {};
-        description = ''
+        description = lib.mdDoc ''
           Attributes for user's entry in
-          <filename>pam_mount.conf.xml</filename>.
-          Useful attributes might include <code>path</code>,
-          <code>options</code>, <code>fstype</code>, and <code>server</code>.
-          See <link
-          xlink:href="http://pam-mount.sourceforge.net/pam_mount.conf.5.html" />
+          {file}`pam_mount.conf.xml`.
+          Useful attributes might include `path`,
+          `options`, `fstype`, and `server`.
+          See <http://pam-mount.sourceforge.net/pam_mount.conf.5.html>
           for more information.
         '';
       };
@@ -167,12 +166,12 @@ let
         default = pkgs.shadow;
         defaultText = literalExpression "pkgs.shadow";
         example = literalExpression "pkgs.bashInteractive";
-        description = ''
+        description = lib.mdDoc ''
           The path to the user's shell. Can use shell derivations,
-          like <literal>pkgs.bashInteractive</literal>. Don’t
+          like `pkgs.bashInteractive`. Don’t
           forget to enable your shell in
-          <literal>programs</literal> if necessary,
-          like <code>programs.zsh.enable = true;</code>.
+          `programs` if necessary,
+          like `programs.zsh.enable = true;`.
         '';
       };
 
diff --git a/nixos/modules/config/xdg/portal.nix b/nixos/modules/config/xdg/portal.nix
index 1e6ddd7c4a26b..689abf267f090 100644
--- a/nixos/modules/config/xdg/portal.nix
+++ b/nixos/modules/config/xdg/portal.nix
@@ -33,7 +33,7 @@ in
 
   options.xdg.portal = {
     enable =
-      mkEnableOption "<link xlink:href='https://github.com/flatpak/xdg-desktop-portal'>xdg desktop integration</link>" // {
+      mkEnableOption ''<link xlink:href="https://github.com/flatpak/xdg-desktop-portal">xdg desktop integration</link>'' // {
         default = false;
       };
 
diff --git a/nixos/modules/hardware/logitech.nix b/nixos/modules/hardware/logitech.nix
index 2e3a71c041585..70ca59a7dd3f7 100644
--- a/nixos/modules/hardware/logitech.nix
+++ b/nixos/modules/hardware/logitech.nix
@@ -32,10 +32,9 @@ in
       devices = mkOption {
         type = types.listOf types.str;
         default = [ "0a07" "c222" "c225" "c227" "c251" ];
-        description = ''
+        description = lib.mdDoc ''
           List of USB device ids supported by g15daemon.
-          </para>
-          <para>
+
           You most likely do not need to change this.
         '';
       };
diff --git a/nixos/modules/hardware/tuxedo-keyboard.nix b/nixos/modules/hardware/tuxedo-keyboard.nix
index 97af7c61f3c9a..7bcabde48900c 100644
--- a/nixos/modules/hardware/tuxedo-keyboard.nix
+++ b/nixos/modules/hardware/tuxedo-keyboard.nix
@@ -13,7 +13,7 @@ in
 
           To configure the driver, pass the options to the <option>boot.kernelParams</option> configuration.
           There are several parameters you can change. It's best to check at the source code description which options are supported.
-          You can find all the supported parameters at: <link xlink:href="https://github.com/tuxedocomputers/tuxedo-keyboard#kernelparam" />
+          You can find all the supported parameters at: <link xlink:href="https://github.com/tuxedocomputers/tuxedo-keyboard#kernelparam"/>
 
           In order to use the <literal>custom</literal> lighting with the maximumg brightness and a color of <literal>0xff0a0a</literal> one would put pass <option>boot.kernelParams</option> like this:
 
diff --git a/nixos/modules/hardware/video/uvcvideo/default.nix b/nixos/modules/hardware/video/uvcvideo/default.nix
index bb59e2f2ed2b0..6cfb8cc6ad29e 100644
--- a/nixos/modules/hardware/video/uvcvideo/default.nix
+++ b/nixos/modules/hardware/video/uvcvideo/default.nix
@@ -34,15 +34,15 @@ in
       packages = mkOption {
         type = types.listOf types.path;
         example = literalExpression "[ pkgs.tiscamera ]";
-        description = ''
-          List of packages containing <command>uvcvideo</command> dynamic controls
+        description = lib.mdDoc ''
+          List of packages containing {command}`uvcvideo` dynamic controls
           rules. All files found in
-          <filename><replaceable>pkg</replaceable>/share/uvcdynctrl/data</filename>
+          {file}`«pkg»/share/uvcdynctrl/data`
           will be included.
 
-          Note that these will serve as input to the <command>libwebcam</command>
-          package which through its own <command>udev</command> rule will register
-          the dynamic controls from specified packages to the <command>uvcvideo</command>
+          Note that these will serve as input to the {command}`libwebcam`
+          package which through its own {command}`udev` rule will register
+          the dynamic controls from specified packages to the {command}`uvcvideo`
           driver.
         '';
         apply = map getBin;
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index 9309fe70a8618..cefe252e2e9ab 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -618,7 +618,7 @@ in
         This will be directly appended (without whitespace) to the NixOS version
         string, like for example if it is set to <literal>XXX</literal>:
 
-        <para><literal>NixOS 99.99-pre666XXX</literal></para>
+        <literal>NixOS 99.99-pre666XXX</literal>
       '';
     };
 
diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix
index 4490ad84e1447..e46a2df8fa6a3 100644
--- a/nixos/modules/installer/tools/tools.nix
+++ b/nixos/modules/installer/tools/tools.nix
@@ -175,7 +175,7 @@ in
         # services.xserver.libinput.enable = true;
 
         # Define a user account. Don't forget to set a password with ‘passwd’.
-        # users.users.jane = {
+        # users.users.alice = {
         #   isNormalUser = true;
         #   extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
         #   packages = with pkgs; [
diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix
index e991ff42028d7..bb21e31ec9790 100644
--- a/nixos/modules/misc/nixpkgs.nix
+++ b/nixos/modules/misc/nixpkgs.nix
@@ -119,11 +119,11 @@ in
       example = literalExpression "import <nixpkgs> {}";
       description = ''
         If set, the pkgs argument to all NixOS modules is the value of
-        this option, extended with <code>nixpkgs.overlays</code>, if
-        that is also set. Either <code>nixpkgs.crossSystem</code> or
-        <code>nixpkgs.localSystem</code> will be used in an assertion
+        this option, extended with <literal>nixpkgs.overlays</literal>, if
+        that is also set. Either <literal>nixpkgs.crossSystem</literal> or
+        <literal>nixpkgs.localSystem</literal> will be used in an assertion
         to check that the NixOS and Nixpkgs architectures match. Any
-        other options in <code>nixpkgs.*</code>, notably <code>config</code>,
+        other options in <literal>nixpkgs.*</literal>, notably <literal>config</literal>,
         will be ignored.
 
         If unset, the pkgs argument to all NixOS modules is determined
@@ -132,18 +132,18 @@ in
         The default value imports the Nixpkgs source files
         relative to the location of this NixOS module, because
         NixOS and Nixpkgs are distributed together for consistency,
-        so the <code>nixos</code> in the default value is in fact a
-        relative path. The <code>config</code>, <code>overlays</code>,
-        <code>localSystem</code>, and <code>crossSystem</code> come
+        so the <literal>nixos</literal> in the default value is in fact a
+        relative path. The <literal>config</literal>, <literal>overlays</literal>,
+        <literal>localSystem</literal>, and <literal>crossSystem</literal> come
         from this option's siblings.
 
         This option can be used by applications like NixOps to increase
         the performance of evaluation, or to create packages that depend
         on a container that should be built with the exact same evaluation
         of Nixpkgs, for example. Applications like this should set
-        their default value using <code>lib.mkDefault</code>, so
+        their default value using <literal>lib.mkDefault</literal>, so
         user-provided configuration can override it without using
-        <code>lib</code>.
+        <literal>lib</literal>.
 
         Note that using a distinct version of Nixpkgs with NixOS may
         be an unexpected source of problems. Use this option with care.
@@ -162,7 +162,7 @@ in
         details, see the Nixpkgs documentation.)  It allows you to set
         package configuration options.
 
-        Ignored when <code>nixpkgs.pkgs</code> is set.
+        Ignored when <literal>nixpkgs.pkgs</literal> is set.
       '';
     };
 
@@ -188,9 +188,9 @@ in
         The first argument should be used for finding dependencies, and
         the second should be used for overriding recipes.
 
-        If <code>nixpkgs.pkgs</code> is set, overlays specified here
+        If <literal>nixpkgs.pkgs</literal> is set, overlays specified here
         will be applied after the overlays that were already present
-        in <code>nixpkgs.pkgs</code>.
+        in <literal>nixpkgs.pkgs</literal>.
       '';
     };
 
@@ -205,9 +205,9 @@ in
       description = ''
         Specifies the platform where the NixOS configuration will run.
 
-        To cross-compile, set also <code>nixpkgs.buildPlatform</code>.
+        To cross-compile, set also <literal>nixpkgs.buildPlatform</literal>.
 
-        Ignored when <code>nixpkgs.pkgs</code> is set.
+        Ignored when <literal>nixpkgs.pkgs</literal> is set.
       '';
     };
 
@@ -230,7 +230,7 @@ in
         or if you're building machines, you can set this to match your
         development system and/or build farm.
 
-        Ignored when <code>nixpkgs.pkgs</code> is set.
+        Ignored when <literal>nixpkgs.pkgs</literal> is set.
       '';
     };
 
@@ -253,7 +253,7 @@ in
         use the old options.
 
         Specifies the platform on which NixOS should be built. When
-        <code>nixpkgs.crossSystem</code> is unset, it also specifies
+        <literal>nixpkgs.crossSystem</literal> is unset, it also specifies
         the platform <emphasis>for</emphasis> which NixOS should be
         built.  If this option is unset, it defaults to the platform
         type of the machine where evaluation happens. Specifying this
@@ -261,7 +261,7 @@ in
         deployment, or when building virtual machines. See its
         description in the Nixpkgs manual for more details.
 
-        Ignored when <code>nixpkgs.pkgs</code> or <code>hostPlatform</code> is set.
+        Ignored when <literal>nixpkgs.pkgs</literal> or <literal>hostPlatform</literal> is set.
       '';
     };
 
@@ -279,13 +279,13 @@ in
 
         Specifies the platform for which NixOS should be
         built. Specify this only if it is different from
-        <code>nixpkgs.localSystem</code>, the platform
+        <literal>nixpkgs.localSystem</literal>, the platform
         <emphasis>on</emphasis> which NixOS should be built. In other
         words, specify this to cross-compile NixOS. Otherwise it
         should be set as null, the default. See its description in the
         Nixpkgs manual for more details.
 
-        Ignored when <code>nixpkgs.pkgs</code> or <code>hostPlatform</code> is set.
+        Ignored when <literal>nixpkgs.pkgs</literal> or <literal>hostPlatform</literal> is set.
       '';
     };
 
@@ -316,7 +316,7 @@ in
         with a recently generated <literal>hardware-configuration.nix</literal>.
 
         Specifies the Nix platform type on which NixOS should be built.
-        It is better to specify <code>nixpkgs.localSystem</code> instead.
+        It is better to specify <literal>nixpkgs.localSystem</literal> instead.
         <programlisting>
         {
           nixpkgs.system = ..;
@@ -328,9 +328,9 @@ in
           nixpkgs.localSystem.system = ..;
         }
         </programlisting>
-        See <code>nixpkgs.localSystem</code> for more information.
+        See <literal>nixpkgs.localSystem</literal> for more information.
 
-        Ignored when <code>nixpkgs.pkgs</code>, <code>nixpkgs.localSystem</code> or <code>nixpkgs.hostPlatform</code> is set.
+        Ignored when <literal>nixpkgs.pkgs</literal>, <literal>nixpkgs.localSystem</literal> or <literal>nixpkgs.hostPlatform</literal> is set.
       '';
     };
   };
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 616f357663cac..2ae463190fb5b 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -1107,7 +1107,6 @@
   ./services/web-apps/shiori.nix
   ./services/web-apps/snipe-it.nix
   ./services/web-apps/vikunja.nix
-  ./services/web-apps/virtlyst.nix
   ./services/web-apps/wiki-js.nix
   ./services/web-apps/whitebophir.nix
   ./services/web-apps/wordpress.nix
diff --git a/nixos/modules/profiles/all-hardware.nix b/nixos/modules/profiles/all-hardware.nix
index af1e3d32a0a29..5fa64a6c52e9f 100644
--- a/nixos/modules/profiles/all-hardware.nix
+++ b/nixos/modules/profiles/all-hardware.nix
@@ -109,6 +109,9 @@ in
       # USB drivers
       "xhci-pci-renesas"
 
+      # Reset controllers
+      "reset-raspberrypi" # Triggers USB chip firmware load.
+
       # Misc "weak" dependencies
       "analogix-dp"
       "analogix-anx6345" # For DP or eDP (e.g. integrated display)
diff --git a/nixos/modules/programs/adb.nix b/nixos/modules/programs/adb.nix
index 9e9e37f92a87d..e5b0abd9fcfed 100644
--- a/nixos/modules/programs/adb.nix
+++ b/nixos/modules/programs/adb.nix
@@ -11,10 +11,10 @@ with lib;
       enable = mkOption {
         default = false;
         type = types.bool;
-        description = ''
+        description = lib.mdDoc ''
           Whether to configure system to use Android Debug Bridge (adb).
           To grant access to a user, it must be part of adbusers group:
-          <code>users.users.alice.extraGroups = ["adbusers"];</code>
+          `users.users.alice.extraGroups = ["adbusers"];`
         '';
       };
     };
diff --git a/nixos/modules/programs/firejail.nix b/nixos/modules/programs/firejail.nix
index 76b42168c198a..417eff91d3c7c 100644
--- a/nixos/modules/programs/firejail.nix
+++ b/nixos/modules/programs/firejail.nix
@@ -69,13 +69,12 @@ in {
           };
         }
       '';
-      description = ''
+      description = lib.mdDoc ''
         Wrap the binaries in firejail and place them in the global path.
-        </para>
-        <para>
+
         You will get file collisions if you put the actual application binary in
         the global environment (such as by adding the application package to
-        <code>environment.systemPackages</code>), and applications started via
+        `environment.systemPackages`), and applications started via
         .desktop files are not wrapped if they specify the absolute path to the
         binary.
       '';
diff --git a/nixos/modules/programs/gphoto2.nix b/nixos/modules/programs/gphoto2.nix
index 93923ff3133cb..f31b1863963d9 100644
--- a/nixos/modules/programs/gphoto2.nix
+++ b/nixos/modules/programs/gphoto2.nix
@@ -11,11 +11,11 @@ with lib;
       enable = mkOption {
         default = false;
         type = types.bool;
-        description = ''
+        description = lib.mdDoc ''
           Whether to configure system to use gphoto2.
           To grant digital camera access to a user, the user must
           be part of the camera group:
-          <code>users.users.alice.extraGroups = ["camera"];</code>
+          `users.users.alice.extraGroups = ["camera"];`
         '';
       };
     };
diff --git a/nixos/modules/programs/kdeconnect.nix b/nixos/modules/programs/kdeconnect.nix
index aa4302404ad47..1f326c9e92190 100644
--- a/nixos/modules/programs/kdeconnect.nix
+++ b/nixos/modules/programs/kdeconnect.nix
@@ -8,7 +8,7 @@ with lib;
       Note that it will open the TCP and UDP port from
       1714 to 1764 as they are needed for it to function properly.
       You can use the <option>package</option> to use
-      <code>gnomeExtensions.gsconnect</code> as an alternative
+      <literal>gnomeExtensions.gsconnect</literal> as an alternative
       implementation if you use Gnome.
     '';
     package = mkOption {
diff --git a/nixos/modules/programs/neovim.nix b/nixos/modules/programs/neovim.nix
index b1dbcd1813099..85963159a7250 100644
--- a/nixos/modules/programs/neovim.nix
+++ b/nixos/modules/programs/neovim.nix
@@ -72,9 +72,9 @@ in {
           };
         }
       '';
-      description = ''
+      description = lib.mdDoc ''
         Generate your init file from your list of plugins and custom commands.
-        Neovim will then be wrapped to load <command>nvim -u /nix/store/<replaceable>hash</replaceable>-vimrc</command>
+        Neovim will then be wrapped to load {command}`nvim -u /nix/store/«hash»-vimrc`
       '';
     };
 
diff --git a/nixos/modules/programs/nncp.nix b/nixos/modules/programs/nncp.nix
index f40e888dad8c0..a58748d2fe62b 100644
--- a/nixos/modules/programs/nncp.nix
+++ b/nixos/modules/programs/nncp.nix
@@ -33,24 +33,24 @@ in {
     secrets = mkOption {
       type = with types; listOf str;
       example = [ "/run/keys/nncp.hjson" ];
-      description = ''
+      description = lib.mdDoc ''
         A list of paths to NNCP configuration files that should not be
         in the Nix store. These files are layered on top of the values at
-        <xref linkend="opt-programs.nncp.settings"/>.
+        [](#opt-programs.nncp.settings).
       '';
     };
 
     settings = mkOption {
       type = settingsFormat.type;
-      description = ''
+      description = lib.mdDoc ''
         NNCP configuration, see
-        <link xlink:href="http://www.nncpgo.org/Configuration.html"/>.
+        <http://www.nncpgo.org/Configuration.html>.
         At runtime these settings will be overlayed by the contents of
-        <xref linkend="opt-programs.nncp.secrets"/> into the file
-        <literal>${nncpCfgFile}</literal>. Node keypairs go in
-        <literal>secrets</literal>, do not specify them in
-        <literal>settings</literal> as they will be leaked into
-        <literal>/nix/store</literal>!
+        [](#opt-programs.nncp.secrets) into the file
+        `${nncpCfgFile}`. Node keypairs go in
+        `secrets`, do not specify them in
+        `settings` as they will be leaked into
+        `/nix/store`!
       '';
       default = { };
     };
diff --git a/nixos/modules/programs/noisetorch.nix b/nixos/modules/programs/noisetorch.nix
index c69b2581296f0..d5e004da73eb6 100644
--- a/nixos/modules/programs/noisetorch.nix
+++ b/nixos/modules/programs/noisetorch.nix
@@ -3,7 +3,8 @@
 with lib;
 
 let cfg = config.programs.noisetorch;
-in {
+in
+{
   options.programs.noisetorch = {
     enable = mkEnableOption "noisetorch + setcap wrapper";
 
@@ -24,5 +25,6 @@ in {
       capabilities = "cap_sys_resource=+ep";
       source = "${cfg.package}/bin/noisetorch";
     };
+    environment.systemPackages = [ cfg.package ];
   };
 }
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
index e0da6ef3b3ad3..9c4a95ef22c62 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -95,7 +95,7 @@ in
         default = "";
         description = ''
           Extra configuration text prepended to <filename>ssh_config</filename>. Other generated
-          options will be added after a <code>Host *</code> pattern.
+          options will be added after a <literal>Host *</literal> pattern.
           See <citerefentry><refentrytitle>ssh_config</refentrytitle><manvolnum>5</manvolnum></citerefentry>
           for help.
         '';
diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix
index decae1b4d2da2..af2b261d3c5f9 100644
--- a/nixos/modules/programs/sway.nix
+++ b/nixos/modules/programs/sway.nix
@@ -39,7 +39,7 @@ in {
       Sway, the i3-compatible tiling Wayland compositor. You can manually launch
       Sway by executing "exec sway" on a TTY. Copy /etc/sway/config to
       ~/.config/sway/config to modify the default configuration. See
-      <link xlink:href="https://github.com/swaywm/sway/wiki" /> and
+      <link xlink:href="https://github.com/swaywm/sway/wiki"/> and
       "man 5 sway" for more information'';
 
     wrapperFeatures = mkOption {
diff --git a/nixos/modules/programs/turbovnc.nix b/nixos/modules/programs/turbovnc.nix
index e6f8836aa367f..a0e4a36cfd995 100644
--- a/nixos/modules/programs/turbovnc.nix
+++ b/nixos/modules/programs/turbovnc.nix
@@ -15,14 +15,14 @@ in
       ensureHeadlessSoftwareOpenGL = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to set up NixOS such that TurboVNC's built-in software OpenGL
           implementation works.
 
-          This will enable <option>hardware.opengl.enable</option> so that OpenGL
+          This will enable {option}`hardware.opengl.enable` so that OpenGL
           programs can find Mesa's llvmpipe drivers.
 
-          Setting this option to <code>false</code> does not mean that software
+          Setting this option to `false` does not mean that software
           OpenGL won't work; it may still work depending on your system
           configuration.
 
diff --git a/nixos/modules/security/acme/default.nix b/nixos/modules/security/acme/default.nix
index 54b44dcab62be..a1d8c533304ac 100644
--- a/nixos/modules/security/acme/default.nix
+++ b/nixos/modules/security/acme/default.nix
@@ -504,8 +504,8 @@ let
       reloadServices = mkOption {
         type = types.listOf types.str;
         inherit (defaultAndText "reloadServices" []) default defaultText;
-        description = ''
-          The list of systemd services to call <code>systemctl try-reload-or-restart</code>
+        description = lib.mdDoc ''
+          The list of systemd services to call `systemctl try-reload-or-restart`
           on.
         '';
       };
@@ -581,8 +581,8 @@ let
           Turns on the OCSP Must-Staple TLS extension.
           Make sure you know what you're doing! See:
           <itemizedlist>
-            <listitem><para><link xlink:href="https://blog.apnic.net/2019/01/15/is-the-web-ready-for-ocsp-must-staple/" /></para></listitem>
-            <listitem><para><link xlink:href="https://blog.hboeck.de/archives/886-The-Problem-with-OCSP-Stapling-and-Must-Staple-and-why-Certificate-Revocation-is-still-broken.html" /></para></listitem>
+            <listitem><para><link xlink:href="https://blog.apnic.net/2019/01/15/is-the-web-ready-for-ocsp-must-staple/"/></para></listitem>
+            <listitem><para><link xlink:href="https://blog.hboeck.de/archives/886-The-Problem-with-OCSP-Stapling-and-Must-Staple-and-why-Certificate-Revocation-is-still-broken.html"/></para></listitem>
           </itemizedlist>
         '';
       };
diff --git a/nixos/modules/security/dhparams.nix b/nixos/modules/security/dhparams.nix
index 720936e68d72a..b3fce7e83aff6 100644
--- a/nixos/modules/security/dhparams.nix
+++ b/nixos/modules/security/dhparams.nix
@@ -61,7 +61,7 @@ in {
 
           The value is the size (in bits) of the DH params to generate. The
           generated DH params path can be found in
-          <literal>config.security.dhparams.params.<replaceable>name</replaceable>.path</literal>.
+          <literal>config.security.dhparams.params.«name».path</literal>.
 
           <note><para>The name of the DH params is taken as being the name of
           the service it serves and the params will be generated before the
diff --git a/nixos/modules/security/doas.nix b/nixos/modules/security/doas.nix
index d4b51b406e288..4d15ed9a80259 100644
--- a/nixos/modules/security/doas.nix
+++ b/nixos/modules/security/doas.nix
@@ -62,19 +62,19 @@ in
     wheelNeedsPassword = mkOption {
       type = with types; bool;
       default = true;
-      description = ''
-        Whether users of the <code>wheel</code> group must provide a password to
-        run commands as super user via <command>doas</command>.
+      description = lib.mdDoc ''
+        Whether users of the `wheel` group must provide a password to
+        run commands as super user via {command}`doas`.
       '';
     };
 
     extraRules = mkOption {
       default = [];
-      description = ''
+      description = lib.mdDoc ''
         Define specific rules to be set in the
-        <filename>/etc/doas.conf</filename> file. More specific rules should
+        {file}`/etc/doas.conf` file. More specific rules should
         come after more general ones in order to yield the expected behavior.
-        You can use <code>mkBefore</code> and/or <code>mkAfter</code> to ensure
+        You can use `mkBefore` and/or `mkAfter` to ensure
         this is the case when configuration options are merged.
       '';
       example = literalExpression ''
@@ -113,8 +113,8 @@ in
             noPass = mkOption {
               type = with types; bool;
               default = false;
-              description = ''
-                If <code>true</code>, the user is not required to enter a
+              description = lib.mdDoc ''
+                If `true`, the user is not required to enter a
                 password.
               '';
             };
@@ -122,18 +122,18 @@ in
             noLog = mkOption {
               type = with types; bool;
               default = false;
-              description = ''
-                If <code>true</code>, successful executions will not be logged
+              description = lib.mdDoc ''
+                If `true`, successful executions will not be logged
                 to
-                <citerefentry><refentrytitle>syslogd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+                {manpage}`syslogd(8)`.
               '';
             };
 
             persist = mkOption {
               type = with types; bool;
               default = false;
-              description = ''
-                If <code>true</code>, do not ask for a password again for some
+              description = lib.mdDoc ''
+                If `true`, do not ask for a password again for some
                 time after the user successfully authenticates.
               '';
             };
@@ -141,10 +141,10 @@ in
             keepEnv = mkOption {
               type = with types; bool;
               default = false;
-              description = ''
-                If <code>true</code>, environment variables other than those
+              description = lib.mdDoc ''
+                If `true`, environment variables other than those
                 listed in
-                <citerefentry><refentrytitle>doas</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                {manpage}`doas(1)`
                 are kept when creating the environment for the new process.
               '';
             };
@@ -152,18 +152,18 @@ in
             setEnv = mkOption {
               type = with types; listOf str;
               default = [];
-              description = ''
+              description = lib.mdDoc ''
                 Keep or set the specified variables. Variables may also be
                 removed with a leading '-' or set using
-                <code>variable=value</code>. If the first character of
-                <code>value</code> is a '$', the value to be set is taken from
+                `variable=value`. If the first character of
+                `value` is a '$', the value to be set is taken from
                 the existing environment variable of the indicated name. This
                 option is processed after the default environment has been
                 created.
 
-                NOTE: All rules have <code>setenv { SSH_AUTH_SOCK }</code> by
-                default. To prevent <code>SSH_AUTH_SOCK</code> from being
-                inherited, add <code>"-SSH_AUTH_SOCK"</code> anywhere in this
+                NOTE: All rules have `setenv { SSH_AUTH_SOCK }` by
+                default. To prevent `SSH_AUTH_SOCK` from being
+                inherited, add `"-SSH_AUTH_SOCK"` anywhere in this
                 list.
               '';
             };
@@ -183,23 +183,23 @@ in
             runAs = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Which user or group the specified command is allowed to run as.
-                When set to <code>null</code> (the default), all users are
+                When set to `null` (the default), all users are
                 allowed.
 
                 A user can be specified using just the username:
-                <code>"foo"</code>. It is also possible to only allow running as
-                a specific group with <code>":bar"</code>.
+                `"foo"`. It is also possible to only allow running as
+                a specific group with `":bar"`.
               '';
             };
 
             cmd = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 The command the user is allowed to run. When set to
-                <code>null</code> (the default), all commands are allowed.
+                `null` (the default), all commands are allowed.
 
                 NOTE: It is best practice to specify absolute paths. If a
                 relative path is specified, only a restricted PATH will be
@@ -210,9 +210,9 @@ in
             args = mkOption {
               type = with types; nullOr (listOf str);
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Arguments that must be provided to the command. When set to
-                <code>[]</code>, the command must be run without any arguments.
+                `[]`, the command must be run without any arguments.
               '';
             };
           };
diff --git a/nixos/modules/security/misc.nix b/nixos/modules/security/misc.nix
index 3c83ff8d77397..6833452a570e1 100644
--- a/nixos/modules/security/misc.nix
+++ b/nixos/modules/security/misc.nix
@@ -52,7 +52,7 @@ with lib;
     security.allowSimultaneousMultithreading = mkOption {
       type = types.bool;
       default = true;
-      description = ''
+      description = lib.mdDoc ''
         Whether to allow SMT/hyperthreading.  Disabling SMT means that only
         physical CPU cores will be usable at runtime, potentially at
         significant performance cost.
@@ -62,7 +62,7 @@ with lib;
         e.g., shared caches).  This attack vector is unproven.
 
         Disabling SMT is a supplement to the L1 data cache flushing mitigation
-        (see <xref linkend="opt-security.virtualisation.flushL1DataCache"/>)
+        (see [](#opt-security.virtualisation.flushL1DataCache))
         versus malicious VM guests (SMT could "bring back" previously flushed
         data).
       '';
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 7903d333411bd..2d0f256897844 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -807,14 +807,14 @@ in
         default = config.krb5.enable;
         defaultText = literalExpression "config.krb5.enable";
         type = types.bool;
-        description = ''
-          Enables Kerberos PAM modules (<literal>pam-krb5</literal>,
-          <literal>pam-ccreds</literal>).
+        description = lib.mdDoc ''
+          Enables Kerberos PAM modules (`pam-krb5`,
+          `pam-ccreds`).
 
           If set, users can authenticate with their Kerberos password.
           This requires a valid Kerberos configuration
-          (<literal>config.krb5.enable</literal> should be set to
-          <literal>true</literal>).
+          (`config.krb5.enable` should be set to
+          `true`).
 
           Note that the Kerberos PAM modules are not necessary when using SSS
           to handle Kerberos authentication.
@@ -826,13 +826,12 @@ in
       enable = mkOption {
         default = false;
         type = types.bool;
-        description = ''
-          Enables P11 PAM (<literal>pam_p11</literal>) module.
+        description = lib.mdDoc ''
+          Enables P11 PAM (`pam_p11`) module.
 
           If set, users can log in with SSH keys and PKCS#11 tokens.
 
-          More information can be found <link
-          xlink:href="https://github.com/OpenSC/pam_p11">here</link>.
+          More information can be found [here](https://github.com/OpenSC/pam_p11).
         '';
       };
 
@@ -859,77 +858,71 @@ in
       enable = mkOption {
         default = false;
         type = types.bool;
-        description = ''
-          Enables U2F PAM (<literal>pam-u2f</literal>) module.
+        description = lib.mdDoc ''
+          Enables U2F PAM (`pam-u2f`) module.
 
           If set, users listed in
-          <filename>$XDG_CONFIG_HOME/Yubico/u2f_keys</filename> (or
-          <filename>$HOME/.config/Yubico/u2f_keys</filename> if XDG variable is
+          {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
+          {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
           not set) are able to log in with the associated U2F key. The path can
-          be changed using <option>security.pam.u2f.authFile</option> option.
+          be changed using {option}`security.pam.u2f.authFile` option.
 
           File format is:
-          <literal>username:first_keyHandle,first_public_key: second_keyHandle,second_public_key</literal>
-          This file can be generated using <command>pamu2fcfg</command> command.
+          `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
+          This file can be generated using {command}`pamu2fcfg` command.
 
-          More information can be found <link
-          xlink:href="https://developers.yubico.com/pam-u2f/">here</link>.
+          More information can be found [here](https://developers.yubico.com/pam-u2f/).
         '';
       };
 
       authFile = mkOption {
         default = null;
         type = with types; nullOr path;
-        description = ''
-          By default <literal>pam-u2f</literal> module reads the keys from
-          <filename>$XDG_CONFIG_HOME/Yubico/u2f_keys</filename> (or
-          <filename>$HOME/.config/Yubico/u2f_keys</filename> if XDG variable is
+        description = lib.mdDoc ''
+          By default `pam-u2f` module reads the keys from
+          {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
+          {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
           not set).
 
           If you want to change auth file locations or centralize database (for
-          example use <filename>/etc/u2f-mappings</filename>) you can set this
+          example use {file}`/etc/u2f-mappings`) you can set this
           option.
 
           File format is:
-          <literal>username:first_keyHandle,first_public_key: second_keyHandle,second_public_key</literal>
-          This file can be generated using <command>pamu2fcfg</command> command.
+          `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
+          This file can be generated using {command}`pamu2fcfg` command.
 
-          More information can be found <link
-          xlink:href="https://developers.yubico.com/pam-u2f/">here</link>.
+          More information can be found [here](https://developers.yubico.com/pam-u2f/).
         '';
       };
 
       appId = mkOption {
         default = null;
         type = with types; nullOr str;
-        description = ''
-            By default <literal>pam-u2f</literal> module sets the application
-            ID to <literal>pam://$HOSTNAME</literal>.
+        description = lib.mdDoc ''
+            By default `pam-u2f` module sets the application
+            ID to `pam://$HOSTNAME`.
 
-            When using <command>pamu2fcfg</command>, you can specify your
-            application ID with the <literal>-i</literal> flag.
+            When using {command}`pamu2fcfg`, you can specify your
+            application ID with the `-i` flag.
 
-            More information can be found <link
-            xlink:href="https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html">
-            here</link>
+            More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
         '';
       };
 
       origin = mkOption {
         default = null;
         type = with types; nullOr str;
-        description = ''
-            By default <literal>pam-u2f</literal> module sets the origin
-            to <literal>pam://$HOSTNAME</literal>.
+        description = lib.mdDoc ''
+            By default `pam-u2f` module sets the origin
+            to `pam://$HOSTNAME`.
             Setting origin to an host independent value will allow you to
             reuse credentials across machines
 
-            When using <command>pamu2fcfg</command>, you can specify your
-            application ID with the <literal>-o</literal> flag.
+            When using {command}`pamu2fcfg`, you can specify your
+            application ID with the `-o` flag.
 
-            More information can be found <link
-            xlink:href="https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html">
-            here</link>
+            More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
         '';
       };
 
@@ -985,18 +978,17 @@ in
       enable = mkOption {
         default = false;
         type = types.bool;
-        description = ''
-          Enables Uber's USSH PAM (<literal>pam-ussh</literal>) module.
+        description = lib.mdDoc ''
+          Enables Uber's USSH PAM (`pam-ussh`) module.
 
-          This is similar to <literal>pam-ssh-agent</literal>, except that
+          This is similar to `pam-ssh-agent`, except that
           the presence of a CA-signed SSH key with a valid principal is checked
           instead.
 
           Note that this module must both be enabled using this option and on a
-          per-PAM-service level as well (using <literal>usshAuth</literal>).
+          per-PAM-service level as well (using `usshAuth`).
 
-          More information can be found <link
-          xlink:href="https://github.com/uber/pam-ussh">here</link>.
+          More information can be found [here](https://github.com/uber/pam-ussh).
         '';
       };
 
@@ -1075,17 +1067,16 @@ in
       enable = mkOption {
         default = false;
         type = types.bool;
-        description = ''
-          Enables Yubico PAM (<literal>yubico-pam</literal>) module.
+        description = lib.mdDoc ''
+          Enables Yubico PAM (`yubico-pam`) module.
 
           If set, users listed in
-          <filename>~/.yubico/authorized_yubikeys</filename>
+          {file}`~/.yubico/authorized_yubikeys`
           are able to log in with the associated Yubikey tokens.
 
           The file must have only one line:
-          <literal>username:yubikey_token_id1:yubikey_token_id2</literal>
-          More information can be found <link
-          xlink:href="https://developers.yubico.com/yubico-pam/">here</link>.
+          `username:yubikey_token_id1:yubikey_token_id2`
+          More information can be found [here](https://developers.yubico.com/yubico-pam/).
         '';
       };
       control = mkOption {
@@ -1120,7 +1111,7 @@ in
       mode = mkOption {
         default = "client";
         type = types.enum [ "client" "challenge-response" ];
-        description = ''
+        description = lib.mdDoc ''
           Mode of operation.
 
           Use "client" for online validation with a YubiKey validation service such as
@@ -1130,18 +1121,16 @@ in
           Challenge-Response configurations. See the man-page ykpamcfg(1) for further
           details on how to configure offline Challenge-Response validation.
 
-          More information can be found <link
-          xlink:href="https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html">here</link>.
+          More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html).
         '';
       };
       challengeResponsePath = mkOption {
         default = null;
         type = types.nullOr types.path;
-        description = ''
+        description = lib.mdDoc ''
           If not null, set the path used by yubico pam module where the challenge expected response is stored.
 
-          More information can be found <link
-          xlink:href="https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html">here</link>.
+          More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html).
         '';
       };
     };
diff --git a/nixos/modules/security/pam_mount.nix b/nixos/modules/security/pam_mount.nix
index e159a73b66a46..11cc13a8cbeb2 100644
--- a/nixos/modules/security/pam_mount.nix
+++ b/nixos/modules/security/pam_mount.nix
@@ -31,10 +31,9 @@ in
       extraVolumes = mkOption {
         type = types.listOf types.str;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           List of volume definitions for pam_mount.
-          For more information, visit <link
-          xlink:href="http://pam-mount.sourceforge.net/pam_mount.conf.5.html" />.
+          For more information, visit <http://pam-mount.sourceforge.net/pam_mount.conf.5.html>.
         '';
       };
 
@@ -64,22 +63,20 @@ in
         type = types.int;
         default = 0;
         example = 1;
-        description = ''
+        description = lib.mdDoc ''
           Sets the Debug-Level. 0 disables debugging, 1 enables pam_mount tracing,
           and 2 additionally enables tracing in mount.crypt. The default is 0.
-          For more information, visit <link
-          xlink:href="http://pam-mount.sourceforge.net/pam_mount.conf.5.html" />.
+          For more information, visit <http://pam-mount.sourceforge.net/pam_mount.conf.5.html>.
         '';
       };
 
       logoutWait = mkOption {
         type = types.int;
         default = 0;
-        description = ''
+        description = lib.mdDoc ''
           Amount of microseconds to wait until killing remaining processes after
           final logout.
-          For more information, visit <link
-          xlink:href="http://pam-mount.sourceforge.net/pam_mount.conf.5.html" />.
+          For more information, visit <http://pam-mount.sourceforge.net/pam_mount.conf.5.html>.
         '';
       };
 
diff --git a/nixos/modules/security/pam_usb.nix b/nixos/modules/security/pam_usb.nix
index 51d81e823f867..4275c26c6bdaa 100644
--- a/nixos/modules/security/pam_usb.nix
+++ b/nixos/modules/security/pam_usb.nix
@@ -17,10 +17,9 @@ in
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Enable USB login for all login systems that support it.  For
-          more information, visit <link
-          xlink:href="https://github.com/aluzzardi/pam_usb/wiki/Getting-Started#setting-up-devices-and-users" />.
+          more information, visit <https://github.com/aluzzardi/pam_usb/wiki/Getting-Started#setting-up-devices-and-users>.
         '';
       };
 
diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix
index 2e30a8915d865..faa99a31a6d66 100644
--- a/nixos/modules/security/sudo.nix
+++ b/nixos/modules/security/sudo.nix
@@ -55,19 +55,19 @@ in
       type = types.bool;
       default = true;
       description =
-        ''
-          Whether users of the <code>wheel</code> group must
-          provide a password to run commands as super user via <command>sudo</command>.
+        lib.mdDoc ''
+          Whether users of the `wheel` group must
+          provide a password to run commands as super user via {command}`sudo`.
         '';
       };
 
     security.sudo.execWheelOnly = mkOption {
       type = types.bool;
       default = false;
-      description = ''
-        Only allow members of the <code>wheel</code> group to execute sudo by
+      description = lib.mdDoc ''
+        Only allow members of the `wheel` group to execute sudo by
         setting the executable's permissions accordingly.
-        This prevents users that are not members of <code>wheel</code> from
+        This prevents users that are not members of `wheel` from
         exploiting vulnerabilities in sudo such as CVE-2021-3156.
       '';
     };
@@ -139,12 +139,12 @@ in
           runAs = mkOption {
             type = with types; str;
             default = "ALL:ALL";
-            description = ''
+            description = lib.mdDoc ''
               Under which user/group the specified command is allowed to run.
 
-              A user can be specified using just the username: <code>"foo"</code>.
-              It is also possible to specify a user/group combination using <code>"foo:bar"</code>
-              or to only allow running as a specific group with <code>":bar"</code>.
+              A user can be specified using just the username: `"foo"`.
+              It is also possible to specify a user/group combination using `"foo:bar"`
+              or to only allow running as a specific group with `":bar"`.
             '';
           };
 
@@ -159,7 +159,7 @@ in
                   type = with types; str;
                   description = ''
                     A command being either just a path to a binary to allow any arguments,
-                    the full command with arguments pre-set or with <code>""</code> used as the argument,
+                    the full command with arguments pre-set or with <literal>""</literal> used as the argument,
                     not allowing arguments to the command at all.
                   '';
                 };
diff --git a/nixos/modules/services/backup/duplicity.nix b/nixos/modules/services/backup/duplicity.nix
index 8c41059555693..765afd43d638b 100644
--- a/nixos/modules/services/backup/duplicity.nix
+++ b/nixos/modules/services/backup/duplicity.nix
@@ -63,9 +63,9 @@ in
         <citerefentry><refentrytitle>systemd.exec</refentrytitle>
         <manvolnum>5</manvolnum></citerefentry>. For example:
         <programlisting>
-        PASSPHRASE=<replaceable>...</replaceable>
-        AWS_ACCESS_KEY_ID=<replaceable>...</replaceable>
-        AWS_SECRET_ACCESS_KEY=<replaceable>...</replaceable>
+        PASSPHRASE=«...»
+        AWS_ACCESS_KEY_ID=«...»
+        AWS_SECRET_ACCESS_KEY=«...»
         </programlisting>
       '';
     };
diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix
index 76d7f093f21c0..56958bf949d6f 100644
--- a/nixos/modules/services/backup/restic.nix
+++ b/nixos/modules/services/backup/restic.nix
@@ -227,7 +227,7 @@ in
           type = types.package;
           default = pkgs.restic;
           defaultText = literalExpression "pkgs.restic";
-          description = ''
+          description = lib.mdDoc ''
             Restic package to use.
           '';
         };
diff --git a/nixos/modules/services/backup/syncoid.nix b/nixos/modules/services/backup/syncoid.nix
index e53528fb66fce..cbfbc59bf5b2c 100644
--- a/nixos/modules/services/backup/syncoid.nix
+++ b/nixos/modules/services/backup/syncoid.nix
@@ -192,10 +192,10 @@ in
           target = mkOption {
             type = types.str;
             example = "user@server:pool/dataset";
-            description = ''
+            description = lib.mdDoc ''
               Target ZFS dataset. Can be either local
-              (<replaceable>pool/dataset</replaceable>) or remote
-              (<replaceable>user@server:pool/dataset</replaceable>).
+              («pool/dataset») or remote
+              («user@server:pool/dataset»).
             '';
           };
 
diff --git a/nixos/modules/services/backup/zrepl.nix b/nixos/modules/services/backup/zrepl.nix
index e3a9009126455..ea858a8b77db3 100644
--- a/nixos/modules/services/backup/zrepl.nix
+++ b/nixos/modules/services/backup/zrepl.nix
@@ -22,9 +22,8 @@ in
 
       settings = mkOption {
         default = { };
-        description = ''
-          Configuration for zrepl. See <link
-          xlink:href="https://zrepl.github.io/configuration.html"/>
+        description = lib.mdDoc ''
+          Configuration for zrepl. See <https://zrepl.github.io/configuration.html>
           for more information.
         '';
         type = types.submodule {
diff --git a/nixos/modules/services/continuous-integration/github-runner.nix b/nixos/modules/services/continuous-integration/github-runner.nix
index 2da18bbdb3961..5400338236872 100644
--- a/nixos/modules/services/continuous-integration/github-runner.nix
+++ b/nixos/modules/services/continuous-integration/github-runner.nix
@@ -18,12 +18,11 @@ in
     enable = mkOption {
       default = false;
       example = true;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable GitHub Actions runner.
 
         Note: GitHub recommends using self-hosted runners with private repositories only. Learn more here:
-        <link xlink:href="https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners"
-        >About self-hosted runners</link>.
+        [About self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners).
       '';
       type = lib.types.bool;
     };
diff --git a/nixos/modules/services/continuous-integration/gitlab-runner.nix b/nixos/modules/services/continuous-integration/gitlab-runner.nix
index 03d3d2d16e3b0..9f076e2d7a23e 100644
--- a/nixos/modules/services/continuous-integration/gitlab-runner.nix
+++ b/nixos/modules/services/continuous-integration/gitlab-runner.nix
@@ -113,15 +113,15 @@ in
     configFile = mkOption {
       type = types.nullOr types.path;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Configuration file for gitlab-runner.
 
-        <option>configFile</option> takes precedence over <option>services</option>.
-        <option>checkInterval</option> and <option>concurrent</option> will be ignored too.
+        {option}`configFile` takes precedence over {option}`services`.
+        {option}`checkInterval` and {option}`concurrent` will be ignored too.
 
-        This option is deprecated, please use <option>services</option> instead.
-        You can use <option>registrationConfigFile</option> and
-        <option>registrationFlags</option>
+        This option is deprecated, please use {option}`services` instead.
+        You can use {option}`registrationConfigFile` and
+        {option}`registrationFlags`
         for settings not covered by this module.
       '';
     };
@@ -130,16 +130,16 @@ in
         freeformType = (pkgs.formats.json { }).type;
       };
       default = { };
-      description = ''
+      description = lib.mdDoc ''
         Global gitlab-runner configuration. See
-        <link xlink:href="https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-global-section"/>
+        <https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-global-section>
         for supported values.
       '';
     };
     gracefulTermination = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Finish all remaining jobs before stopping.
         If not set gitlab-runner will stop immediatly without waiting
         for jobs to finish, which will lead to failed builds.
@@ -149,7 +149,7 @@ in
       type = types.str;
       default = "infinity";
       example = "5min 20s";
-      description = ''
+      description = lib.mdDoc ''
         Time to wait until a graceful shutdown is turned into a forceful one.
       '';
     };
@@ -158,17 +158,17 @@ in
       default = pkgs.gitlab-runner;
       defaultText = literalExpression "pkgs.gitlab-runner";
       example = literalExpression "pkgs.gitlab-runner_1_11";
-      description = "Gitlab Runner package to use.";
+      description = lib.mdDoc "Gitlab Runner package to use.";
     };
     extraPackages = mkOption {
       type = types.listOf types.package;
       default = [ ];
-      description = ''
+      description = lib.mdDoc ''
         Extra packages to add to PATH for the gitlab-runner process.
       '';
     };
     services = mkOption {
-      description = "GitLab Runner services.";
+      description = lib.mdDoc "GitLab Runner services.";
       default = { };
       example = literalExpression ''
         {
@@ -250,17 +250,17 @@ in
         options = {
           registrationConfigFile = mkOption {
             type = types.path;
-            description = ''
+            description = lib.mdDoc ''
               Absolute path to a file with environment variables
               used for gitlab-runner registration.
               A list of all supported environment variables can be found in
-              <literal>gitlab-runner register --help</literal>.
+              `gitlab-runner register --help`.
 
               Ones that you probably want to set is
 
-              <literal>CI_SERVER_URL=&lt;CI server URL&gt;</literal>
+              `CI_SERVER_URL=<CI server URL>`
 
-              <literal>REGISTRATION_TOKEN=&lt;registration secret&gt;</literal>
+              `REGISTRATION_TOKEN=<registration secret>`
 
               WARNING: make sure to use quoted absolute path,
               or it is going to be copied to Nix Store.
@@ -270,10 +270,10 @@ in
             type = types.listOf types.str;
             default = [ ];
             example = [ "--docker-helper-image my/gitlab-runner-helper" ];
-            description = ''
+            description = lib.mdDoc ''
               Extra command-line flags passed to
-              <literal>gitlab-runner register</literal>.
-              Execute <literal>gitlab-runner register --help</literal>
+              `gitlab-runner register`.
+              Execute `gitlab-runner register --help`
               for a list of supported flags.
             '';
           };
@@ -281,32 +281,32 @@ in
             type = types.attrsOf types.str;
             default = { };
             example = { NAME = "value"; };
-            description = ''
+            description = lib.mdDoc ''
               Custom environment variables injected to build environment.
-              For secrets you can use <option>registrationConfigFile</option>
-              with <literal>RUNNER_ENV</literal> variable set.
+              For secrets you can use {option}`registrationConfigFile`
+              with `RUNNER_ENV` variable set.
             '';
           };
           description = mkOption {
             type = types.nullOr types.str;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Name/description of the runner.
             '';
           };
           executor = mkOption {
             type = types.str;
             default = "docker";
-            description = ''
+            description = lib.mdDoc ''
               Select executor, eg. shell, docker, etc.
-              See <link xlink:href="https://docs.gitlab.com/runner/executors/README.html">runner documentation</link> for more information.
+              See [runner documentation](https://docs.gitlab.com/runner/executors/README.html) for more information.
             '';
           };
           buildsDir = mkOption {
             type = types.nullOr types.path;
             default = null;
             example = "/var/lib/gitlab-runner/builds";
-            description = ''
+            description = lib.mdDoc ''
               Absolute path to a directory where builds will be stored
               in context of selected executor (Locally, Docker, SSH).
             '';
@@ -315,14 +315,14 @@ in
             type = types.nullOr types.str;
             default = null;
             example = "http://gitlab.example.local";
-            description = ''
+            description = lib.mdDoc ''
               Overwrite the URL for the GitLab instance. Used if the Runner can’t connect to GitLab on the URL GitLab exposes itself.
             '';
           };
           dockerImage = mkOption {
             type = types.nullOr types.str;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Docker image to be used.
             '';
           };
@@ -330,7 +330,7 @@ in
             type = types.listOf types.str;
             default = [ ];
             example = [ "/var/run/docker.sock:/var/run/docker.sock" ];
-            description = ''
+            description = lib.mdDoc ''
               Bind-mount a volume and create it
               if it doesn't exist prior to mounting.
             '';
@@ -338,14 +338,14 @@ in
           dockerDisableCache = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Disable all container caching.
             '';
           };
           dockerPrivileged = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Give extended privileges to container.
             '';
           };
@@ -353,7 +353,7 @@ in
             type = types.listOf types.str;
             default = [ ];
             example = [ "other-host:127.0.0.1" ];
-            description = ''
+            description = lib.mdDoc ''
               Add a custom host-to-IP mapping.
             '';
           };
@@ -361,7 +361,7 @@ in
             type = types.listOf types.str;
             default = [ ];
             example = [ "ruby:*" "python:*" "php:*" "my.registry.tld:5000/*:*" ];
-            description = ''
+            description = lib.mdDoc ''
               Whitelist allowed images.
             '';
           };
@@ -369,21 +369,21 @@ in
             type = types.listOf types.str;
             default = [ ];
             example = [ "postgres:9" "redis:*" "mysql:*" ];
-            description = ''
+            description = lib.mdDoc ''
               Whitelist allowed services.
             '';
           };
           preCloneScript = mkOption {
             type = types.nullOr types.path;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Runner-specific command script executed before code is pulled.
             '';
           };
           preBuildScript = mkOption {
             type = types.nullOr types.path;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Runner-specific command script executed after code is pulled,
               just before build executes.
             '';
@@ -391,7 +391,7 @@ in
           postBuildScript = mkOption {
             type = types.nullOr types.path;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Runner-specific command script executed after code is pulled
               and just after build executes.
             '';
@@ -399,22 +399,22 @@ in
           tagList = mkOption {
             type = types.listOf types.str;
             default = [ ];
-            description = ''
+            description = lib.mdDoc ''
               Tag list.
             '';
           };
           runUntagged = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Register to run untagged builds; defaults to
-              <literal>true</literal> when <option>tagList</option> is empty.
+              `true` when {option}`tagList` is empty.
             '';
           };
           limit = mkOption {
             type = types.int;
             default = 0;
-            description = ''
+            description = lib.mdDoc ''
               Limit how many jobs can be handled concurrently by this service.
               0 (default) simply means don't limit.
             '';
@@ -422,14 +422,14 @@ in
           requestConcurrency = mkOption {
             type = types.int;
             default = 0;
-            description = ''
+            description = lib.mdDoc ''
               Limit number of concurrent requests for new jobs from GitLab.
             '';
           };
           maximumTimeout = mkOption {
             type = types.int;
             default = 0;
-            description = ''
+            description = lib.mdDoc ''
               What is the maximum timeout (in seconds) that will be set for
               job when using this Runner. 0 (default) simply means don't limit.
             '';
@@ -437,7 +437,7 @@ in
           protected = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               When set to true Runner will only run on pipelines
               triggered on protected branches.
             '';
@@ -445,9 +445,9 @@ in
           debugTraceDisabled = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               When set to true Runner will disable the possibility of
-              using the <literal>CI_DEBUG_TRACE</literal> feature.
+              using the `CI_DEBUG_TRACE` feature.
             '';
           };
         };
diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix
index f4cdf690bb3aa..7159ec287fc86 100644
--- a/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -320,7 +320,7 @@ in
           ${optionalString haveLocalDB ''
             if ! [ -e ${baseDir}/.db-created ]; then
               runuser -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createuser hydra
-              runuser -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createdb -O hydra hydra
+              runuser -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createdb -- -O hydra hydra
               touch ${baseDir}/.db-created
             fi
             echo "create extension if not exists pg_trgm" | runuser -u ${config.services.postgresql.superUser} -- ${config.services.postgresql.package}/bin/psql hydra
diff --git a/nixos/modules/services/databases/firebird.nix b/nixos/modules/services/databases/firebird.nix
index 3a7ebd6bbd096..4aaf4ca12aa62 100644
--- a/nixos/modules/services/databases/firebird.nix
+++ b/nixos/modules/services/databases/firebird.nix
@@ -47,9 +47,9 @@ in
         defaultText = literalExpression "pkgs.firebird";
         type = types.package;
         example = literalExpression "pkgs.firebird_3";
-        description = ''
-          Which Firebird package to be installed: <code>pkgs.firebird_3</code>
-          For SuperServer use override: <code>pkgs.firebird_3.override { superServer = true; };</code>
+        description = lib.mdDoc ''
+          Which Firebird package to be installed: `pkgs.firebird_3`
+          For SuperServer use override: `pkgs.firebird_3.override { superServer = true; };`
         '';
       };
 
diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix
index b7a55900c122f..1a096d2a88a45 100644
--- a/nixos/modules/services/databases/mysql.nix
+++ b/nixos/modules/services/databases/mysql.nix
@@ -201,7 +201,7 @@ in
             ensurePermissions = mkOption {
               type = types.attrsOf types.str;
               default = {};
-              description = ''
+              description = lib.mdDoc ''
                 Permissions to ensure for the user, specified as attribute set.
                 The attribute names specify the database and tables to grant the permissions for,
                 separated by a dot. You may use wildcards here.
@@ -210,8 +210,8 @@ in
 
                 For more information on how to specify the target
                 and on which privileges exist, see the
-                <link xlink:href="https://mariadb.com/kb/en/library/grant/">GRANT syntax</link>.
-                The attributes are used as <code>GRANT ''${attrName} ON ''${attrValue}</code>.
+                [GRANT syntax](https://mariadb.com/kb/en/library/grant/).
+                The attributes are used as `GRANT ''${attrName} ON ''${attrValue}`.
               '';
               example = literalExpression ''
                 {
diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix
index dbbb79f01ebb5..d1be4034ddacb 100644
--- a/nixos/modules/services/databases/neo4j.nix
+++ b/nixos/modules/services/databases/neo4j.nix
@@ -139,15 +139,14 @@ in {
     constrainLoadCsv = mkOption {
       type = types.bool;
       default = true;
-      description = ''
+      description = lib.mdDoc ''
         Sets the root directory for file URLs used with the Cypher
-        <literal>LOAD CSV</literal> clause to be that defined by
-        <option>directories.imports</option>. It restricts
+        `LOAD CSV` clause to be that defined by
+        {option}`directories.imports`. It restricts
         access to only those files within that directory and its
         subdirectories.
-        </para>
-        <para>
-        Setting this option to <literal>false</literal> introduces
+
+        Setting this option to `false` introduces
         possible security problems.
       '';
     };
@@ -155,15 +154,14 @@ in {
     defaultListenAddress = mkOption {
       type = types.str;
       default = "127.0.0.1";
-      description = ''
+      description = lib.mdDoc ''
         Default network interface to listen for incoming connections. To
         listen for connections on all interfaces, use "0.0.0.0".
-        </para>
-        <para>
+
         Specifies the default IP address and address part of connector
-        specific <option>listenAddress</option> options. To bind specific
+        specific {option}`listenAddress` options. To bind specific
         connectors to a specific network interfaces, specify the entire
-        <option>listenAddress</option> option for that connector.
+        {option}`listenAddress` option for that connector.
       '';
     };
 
@@ -227,20 +225,18 @@ in {
       sslPolicy = mkOption {
         type = types.str;
         default = "legacy";
-        description = ''
+        description = lib.mdDoc ''
           Neo4j SSL policy for BOLT traffic.
-          </para>
-          <para>
+
           The legacy policy is a special policy which is not defined in
           the policy configuration section, but rather derives from
-          <option>directories.certificates</option> and
-          associated files (by default: <filename>neo4j.key</filename> and
-          <filename>neo4j.cert</filename>). Its use will be deprecated.
-          </para>
-          <para>
+          {option}`directories.certificates` and
+          associated files (by default: {file}`neo4j.key` and
+          {file}`neo4j.cert`). Its use will be deprecated.
+
           Note: This connector must be configured to support/require
           SSL/TLS for the legacy policy to actually be utilized. See
-          <option>bolt.tlsLevel</option>.
+          {option}`bolt.tlsLevel`.
         '';
       };
 
@@ -258,21 +254,19 @@ in {
         type = types.path;
         default = "${cfg.directories.home}/certificates";
         defaultText = literalExpression ''"''${config.${opt.directories.home}}/certificates"'';
-        description = ''
+        description = lib.mdDoc ''
           Directory for storing certificates to be used by Neo4j for
           TLS connections.
-          </para>
-          <para>
+
           When setting this directory to something other than its default,
           ensure the directory's existence, and that read/write permissions are
-          given to the Neo4j daemon user <literal>neo4j</literal>.
-          </para>
-          <para>
+          given to the Neo4j daemon user `neo4j`.
+
           Note that changing this directory from its default will prevent
           the directory structure required for each SSL policy from being
           automatically generated. A policy's directory structure as defined by
-          its <option>baseDirectory</option>,<option>revokedDir</option> and
-          <option>trustedDir</option> must then be setup manually. The
+          its {option}`baseDirectory`,{option}`revokedDir` and
+          {option}`trustedDir` must then be setup manually. The
           existence of these directories is mandatory, as well as the presence
           of the certificate file and the private key. Ensure the correct
           permissions are set on these directories and files.
@@ -283,14 +277,13 @@ in {
         type = types.path;
         default = "${cfg.directories.home}/data";
         defaultText = literalExpression ''"''${config.${opt.directories.home}}/data"'';
-        description = ''
+        description = lib.mdDoc ''
           Path of the data directory. You must not configure more than one
           Neo4j installation to use the same data directory.
-          </para>
-          <para>
+
           When setting this directory to something other than its default,
           ensure the directory's existence, and that read/write permissions are
-          given to the Neo4j daemon user <literal>neo4j</literal>.
+          given to the Neo4j daemon user `neo4j`.
         '';
       };
 
@@ -309,16 +302,15 @@ in {
         type = types.path;
         default = "${cfg.directories.home}/import";
         defaultText = literalExpression ''"''${config.${opt.directories.home}}/import"'';
-        description = ''
+        description = lib.mdDoc ''
           The root directory for file URLs used with the Cypher
-          <literal>LOAD CSV</literal> clause. Only meaningful when
-          <option>constrainLoadCvs</option> is set to
-          <literal>true</literal>.
-          </para>
-          <para>
+          `LOAD CSV` clause. Only meaningful when
+          {option}`constrainLoadCvs` is set to
+          `true`.
+
           When setting this directory to something other than its default,
           ensure the directory's existence, and that read permission is
-          given to the Neo4j daemon user <literal>neo4j</literal>.
+          given to the Neo4j daemon user `neo4j`.
         '';
       };
 
@@ -326,15 +318,14 @@ in {
         type = types.path;
         default = "${cfg.directories.home}/plugins";
         defaultText = literalExpression ''"''${config.${opt.directories.home}}/plugins"'';
-        description = ''
+        description = lib.mdDoc ''
           Path of the database plugin directory. Compiled Java JAR files that
           contain database procedures will be loaded if they are placed in
           this directory.
-          </para>
-          <para>
+
           When setting this directory to something other than its default,
           ensure the directory's existence, and that read permission is
-          given to the Neo4j daemon user <literal>neo4j</literal>.
+          given to the Neo4j daemon user `neo4j`.
         '';
       };
     };
@@ -386,15 +377,14 @@ in {
       sslPolicy = mkOption {
         type = types.str;
         default = "legacy";
-        description = ''
+        description = lib.mdDoc ''
           Neo4j SSL policy for HTTPS traffic.
-          </para>
-          <para>
+
           The legacy policy is a special policy which is not defined in the
           policy configuration section, but rather derives from
-          <option>directories.certificates</option> and
-          associated files (by default: <filename>neo4j.key</filename> and
-          <filename>neo4j.cert</filename>). Its use will be deprecated.
+          {option}`directories.certificates` and
+          associated files (by default: {file}`neo4j.key` and
+          {file}`neo4j.cert`). Its use will be deprecated.
         '';
       };
     };
@@ -417,18 +407,16 @@ in {
           allowKeyGeneration = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Allows the generation of a private key and associated self-signed
               certificate. Only performed when both objects cannot be found for
               this policy. It is recommended to turn this off again after keys
               have been generated.
-              </para>
-              <para>
+
               The public certificate is required to be duplicated to the
               directory holding trusted certificates as defined by the
-              <option>trustedDir</option> option.
-              </para>
-              <para>
+              {option}`trustedDir` option.
+
               Keys should in general be generated and distributed offline by a
               trusted certificate authority and not by utilizing this mode.
             '';
@@ -438,17 +426,16 @@ in {
             type = types.path;
             default = "${cfg.directories.certificates}/${name}";
             defaultText = literalExpression ''"''${config.${opt.directories.certificates}}/''${name}"'';
-            description = ''
+            description = lib.mdDoc ''
               The mandatory base directory for cryptographic objects of this
               policy. This path is only automatically generated when this
-              option as well as <option>directories.certificates</option> are
+              option as well as {option}`directories.certificates` are
               left at their default. Ensure read/write permissions are given
-              to the Neo4j daemon user <literal>neo4j</literal>.
-              </para>
-              <para>
+              to the Neo4j daemon user `neo4j`.
+
               It is also possible to override each individual
               configuration with absolute paths. See the
-              <option>privateKey</option> and <option>publicCertificate</option>
+              {option}`privateKey` and {option}`publicCertificate`
               policy options.
             '';
           };
@@ -483,16 +470,15 @@ in {
           publicCertificate = mkOption {
             type = types.str;
             default = "public.crt";
-            description = ''
+            description = lib.mdDoc ''
               The name of public X.509 certificate (chain) file in PEM format
-              for this policy to be found in the <option>baseDirectory</option>,
+              for this policy to be found in the {option}`baseDirectory`,
               or the absolute path to the certificate file. It is mandatory
               that a certificate can be found or generated.
-              </para>
-              <para>
+
               The public certificate is required to be duplicated to the
               directory holding trusted certificates as defined by the
-              <option>trustedDir</option> option.
+              {option}`trustedDir` option.
             '';
           };
 
@@ -536,19 +522,18 @@ in {
             type = types.path;
             default = "${config.baseDirectory}/trusted";
             defaultText = literalExpression ''"''${config.${options.baseDirectory}}/trusted"'';
-            description = ''
+            description = lib.mdDoc ''
               Path to directory of X.509 certificates in PEM format for
               trusted parties. Must be an absolute path. The existence of this
               directory is mandatory and will need to be created manually when:
               setting this option to something other than its default; setting
-              either this policy's <option>baseDirectory</option> or
-              <option>directories.certificates</option> to something other than
+              either this policy's {option}`baseDirectory` or
+              {option}`directories.certificates` to something other than
               their default. Ensure read/write permissions are given to the
-              Neo4j daemon user <literal>neo4j</literal>.
-              </para>
-              <para>
+              Neo4j daemon user `neo4j`.
+
               The public certificate as defined by
-              <option>publicCertificate</option> is required to be duplicated
+              {option}`publicCertificate` is required to be duplicated
               to this directory.
             '';
           };
diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix
index 94fc155000e24..7a59de372f24b 100644
--- a/nixos/modules/services/databases/openldap.nix
+++ b/nixos/modules/services/databases/openldap.nix
@@ -88,7 +88,7 @@ in {
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = "Whether to enable the ldap server.";
+        description = lib.mdDoc "Whether to enable the ldap server.";
       };
 
       package = mkOption {
@@ -173,9 +173,9 @@ in {
       configDir = mkOption {
         type = types.nullOr types.path;
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           Use this config directory instead of generating one from the
-          <literal>settings</literal> option. Overrides all NixOS settings.
+          `settings` option. Overrides all NixOS settings.
         '';
         example = "/var/lib/openldap/slapd.d";
       };
@@ -183,9 +183,9 @@ in {
       mutableConfig = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to allow writable on-line configuration. If
-          <literal>true</literal>, the NixOS settings will only be used to
+          `true`, the NixOS settings will only be used to
           initialize the OpenLDAP configuration if it does not exist, and are
           subsequently ignored.
         '';
diff --git a/nixos/modules/services/databases/pgmanage.nix b/nixos/modules/services/databases/pgmanage.nix
index f50e7244ee115..9ce2265a4deed 100644
--- a/nixos/modules/services/databases/pgmanage.nix
+++ b/nixos/modules/services/databases/pgmanage.nix
@@ -62,12 +62,12 @@ in {
         nuc-server  = "hostaddr=192.168.0.100 port=5432 dbname=postgres";
         mini-server = "hostaddr=127.0.0.1 port=5432 dbname=postgres sslmode=require";
       };
-      description = ''
+      description = lib.mdDoc ''
         pgmanage requires at least one PostgreSQL server be defined.
-        </para><para>
+
         Detailed information about PostgreSQL connection strings is available at:
-        <link xlink:href="http://www.postgresql.org/docs/current/static/libpq-connect.html"/>
-        </para><para>
+        <http://www.postgresql.org/docs/current/static/libpq-connect.html>
+
         Note that you should not specify your user name or password. That
         information will be entered on the login screen. If you specify a
         username or password, it will be removed by pgmanage before attempting to
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index e27f4518dfada..d0135647d6afc 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -81,8 +81,7 @@ in
         default = "";
         description = ''
           Defines how users authenticate themselves to the server. See the
-          <link xlink:href="https://www.postgresql.org/docs/current/auth-pg-hba-conf.html">
-          PostgreSQL documentation for pg_hba.conf</link>
+          <link xlink:href="https://www.postgresql.org/docs/current/auth-pg-hba-conf.html">PostgreSQL documentation for pg_hba.conf</link>
           for details on the expected format of this option. By default,
           peer based authentication will be used for users connecting
           via the Unix socket, and md5 password authentication will be
@@ -150,7 +149,7 @@ in
             ensurePermissions = mkOption {
               type = types.attrsOf types.str;
               default = {};
-              description = ''
+              description = lib.mdDoc ''
                 Permissions to ensure for the user, specified as an attribute set.
                 The attribute names specify the database and tables to grant the permissions for.
                 The attribute values specify the permissions to grant. You may specify one or
@@ -158,8 +157,8 @@ in
 
                 For more information on how to specify the target
                 and on which privileges exist, see the
-                <link xlink:href="https://www.postgresql.org/docs/current/sql-grant.html">GRANT syntax</link>.
-                The attributes are used as <code>GRANT ''${attrValue} ON ''${attrName}</code>.
+                [GRANT syntax](https://www.postgresql.org/docs/current/sql-grant.html).
+                The attributes are used as `GRANT ''${attrValue} ON ''${attrName}`.
               '';
               example = literalExpression ''
                 {
diff --git a/nixos/modules/services/databases/victoriametrics.nix b/nixos/modules/services/databases/victoriametrics.nix
index 28a6ccfd5e20c..f87a5862f6410 100644
--- a/nixos/modules/services/databases/victoriametrics.nix
+++ b/nixos/modules/services/databases/victoriametrics.nix
@@ -28,10 +28,10 @@ let cfg = config.services.victoriametrics; in
     extraOptions = mkOption {
       type = types.listOf types.str;
       default = [];
-      description = ''
-        Extra options to pass to VictoriaMetrics. See the README: <link
-        xlink:href="https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/README.md" />
-        or <command>victoriametrics -help</command> for more
+      description = lib.mdDoc ''
+        Extra options to pass to VictoriaMetrics. See the README:
+        <https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/README.md>
+        or {command}`victoriametrics -help` for more
         information.
       '';
     };
diff --git a/nixos/modules/services/development/zammad.nix b/nixos/modules/services/development/zammad.nix
index 503f54aee2c70..e81eef3c0a51b 100644
--- a/nixos/modules/services/development/zammad.nix
+++ b/nixos/modules/services/development/zammad.nix
@@ -139,7 +139,7 @@ in
           '';
           description = ''
             The <filename>database.yml</filename> configuration file as key value set.
-            See <link xlink:href='TODO' />
+            See <link xlink:href="TODO"/>
             for list of configuration parameters.
           '';
         };
diff --git a/nixos/modules/services/games/asf.nix b/nixos/modules/services/games/asf.nix
index 37247e195a78c..b7892900376fa 100644
--- a/nixos/modules/services/games/asf.nix
+++ b/nixos/modules/services/games/asf.nix
@@ -136,7 +136,9 @@ in
           };
           settings = mkOption {
             type = types.attrs;
-            description = "Additional settings that are documented <link xlink:href=\"https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Configuration#bot-config\">here</link>.";
+            description = lib.mdDoc ''
+              Additional settings that are documented [here](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Configuration#bot-config).
+            '';
             default = { };
           };
         };
diff --git a/nixos/modules/services/games/crossfire-server.nix b/nixos/modules/services/games/crossfire-server.nix
index 4b9813245fb76..a0dc1e6c564c3 100644
--- a/nixos/modules/services/games/crossfire-server.nix
+++ b/nixos/modules/services/games/crossfire-server.nix
@@ -76,7 +76,7 @@ in {
         {
           dm_file = '''
             admin:secret_password:localhost
-            jane:xyzzy:*
+            alice:xyzzy:*
           ''';
           ban_file = '''
             # Bob is a jerk
diff --git a/nixos/modules/services/games/deliantra-server.nix b/nixos/modules/services/games/deliantra-server.nix
index 1a0618601240e..17bdf2aef7766 100644
--- a/nixos/modules/services/games/deliantra-server.nix
+++ b/nixos/modules/services/games/deliantra-server.nix
@@ -73,7 +73,7 @@ in {
         {
           dm_file = '''
             admin:secret_password:localhost
-            jane:xyzzy:*
+            alice:xyzzy:*
           ''';
           motd = "Welcome to Deliantra!";
           settings = '''
diff --git a/nixos/modules/services/hardware/kanata.nix b/nixos/modules/services/hardware/kanata.nix
index f8250afa4a000..c7cd3c9d2eb95 100644
--- a/nixos/modules/services/hardware/kanata.nix
+++ b/nixos/modules/services/hardware/kanata.nix
@@ -10,7 +10,7 @@ let
       device = mkOption {
         type = types.str;
         example = "/dev/input/by-id/usb-0000_0000-event-kbd";
-        description = "Path to the keyboard device.";
+        description = lib.mdDoc "Path to the keyboard device.";
       };
       config = mkOption {
         type = types.lines;
@@ -33,18 +33,18 @@ let
             ;; tap within 100ms for capslk, hold more than 100ms for lctl
             cap (tap-hold 100 100 caps lctl))
         '';
-        description = ''
+        description = lib.mdDoc ''
           Configuration other than defcfg.
-          See <link xlink:href="https://github.com/jtroo/kanata"/> for more information.
+          See <https://github.com/jtroo/kanata> for more information.
         '';
       };
       extraDefCfg = mkOption {
         type = types.lines;
         default = "";
         example = "danger-enable-cmd yes";
-        description = ''
+        description = lib.mdDoc ''
           Configuration of defcfg other than linux-dev.
-          See <link xlink:href="https://github.com/jtroo/kanata"/> for more information.
+          See <https://github.com/jtroo/kanata> for more information.
         '';
       };
     };
@@ -131,7 +131,7 @@ in
       default = pkgs.kanata;
       defaultText = lib.literalExpression "pkgs.kanata";
       example = lib.literalExpression "pkgs.kanata-with-cmd";
-      description = ''
+      description = lib.mdDoc ''
         kanata package to use.
         If you enable danger-enable-cmd, pkgs.kanata-with-cmd should be used.
       '';
@@ -139,7 +139,7 @@ in
     keyboards = mkOption {
       type = types.attrsOf (types.submodule keyboard);
       default = { };
-      description = "Keyboard configurations.";
+      description = lib.mdDoc "Keyboard configurations.";
     };
   };
 
diff --git a/nixos/modules/services/hardware/lcd.nix b/nixos/modules/services/hardware/lcd.nix
index ec4b27bd84828..c817225c1f210 100644
--- a/nixos/modules/services/hardware/lcd.nix
+++ b/nixos/modules/services/hardware/lcd.nix
@@ -63,8 +63,7 @@ in with lib; {
           default = false;
           description = ''
             Set group-write permissions on a USB device.
-            </para>
-            <para>
+
             A USB connected LCD panel will most likely require having its
             permissions modified for lcdd to write to it. Enabling this option
             sets group-write permissions on the device identified by
@@ -72,13 +71,11 @@ in with lib; {
             <option>services.hardware.lcd.usbPid</option>. In order to find the
             values, you can run the <command>lsusb</command> command. Example
             output:
-            </para>
-            <para>
+
             <literal>
             Bus 005 Device 002: ID 0403:c630 Future Technology Devices International, Ltd lcd2usb interface
             </literal>
-            </para>
-            <para>
+
             In this case the vendor id is 0403 and the product id is c630.
           '';
         };
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 514763e409a1a..1723cb508485d 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -209,11 +209,11 @@ in
       packages = mkOption {
         type = types.listOf types.path;
         default = [];
-        description = ''
-          List of packages containing <command>udev</command> rules.
+        description = lib.mdDoc ''
+          List of packages containing {command}`udev` rules.
           All files found in
-          <filename><replaceable>pkg</replaceable>/etc/udev/rules.d</filename> and
-          <filename><replaceable>pkg</replaceable>/lib/udev/rules.d</filename>
+          {file}`«pkg»/etc/udev/rules.d` and
+          {file}`«pkg»/lib/udev/rules.d`
           will be included.
         '';
         apply = map getBin;
@@ -281,16 +281,15 @@ in
     networking.usePredictableInterfaceNames = mkOption {
       default = true;
       type = types.bool;
-      description = ''
-        Whether to assign <link
-        xlink:href='http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames'>predictable
-        names to network interfaces</link>.  If enabled, interfaces
+      description = lib.mdDoc ''
+        Whether to assign [predictable names to network interfaces](http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames).
+        If enabled, interfaces
         are assigned names that contain topology information
-        (e.g. <literal>wlp3s0</literal>) and thus should be stable
+        (e.g. `wlp3s0`) and thus should be stable
         across reboots.  If disabled, names depend on the order in
         which interfaces are discovered by the kernel, which may
         change randomly across reboots; for instance, you may find
-        <literal>eth0</literal> and <literal>eth1</literal> flipping
+        `eth0` and `eth1` flipping
         unpredictably.
       '';
     };
@@ -306,8 +305,8 @@ in
 
           List of packages containing <command>udev</command> rules that will be copied to stage 1.
           All files found in
-          <filename><replaceable>pkg</replaceable>/etc/udev/rules.d</filename> and
-          <filename><replaceable>pkg</replaceable>/lib/udev/rules.d</filename>
+          <filename>«pkg»/etc/udev/rules.d</filename> and
+          <filename>«pkg»/lib/udev/rules.d</filename>
           will be included.
         '';
       };
diff --git a/nixos/modules/services/home-automation/home-assistant.nix b/nixos/modules/services/home-automation/home-assistant.nix
index 6324965c621cf..2b81283836313 100644
--- a/nixos/modules/services/home-automation/home-assistant.nix
+++ b/nixos/modules/services/home-automation/home-assistant.nix
@@ -411,12 +411,12 @@ in {
       ;
       serviceConfig = let
         # List of capabilities to equip home-assistant with, depending on configured components
-        capabilities = [
+        capabilities = lib.unique ([
           # Empty string first, so we will never accidentally have an empty capability bounding set
           # https://github.com/NixOS/nixpkgs/issues/120617#issuecomment-830685115
           ""
-        ] ++ (unique (optionals (useComponent "bluetooth_tracker" || useComponent "bluetooth_le_tracker") [
-          # Required for interaction with hci devices and bluetooth sockets
+        ] ++ lib.optionals (builtins.any useComponent [ "bluetooth" "bluetooth_le_tracker" "bluetooth_tracker" "eq3btsmart" "fjaraskupan" "govee_ble" "homekit_controller" "inkbird" "moat" "sensorpush" "switchbot" "xiaomi_ble" ]) [
+          # Required for interaction with hci devices and bluetooth sockets, identified by bluetooth-adapters dependency
           # https://www.home-assistant.io/integrations/bluetooth_le_tracker/#rootless-setup-on-core-installs
           "CAP_NET_ADMIN"
           "CAP_NET_RAW"
@@ -429,7 +429,7 @@ in {
           "CAP_NET_ADMIN"
           "CAP_NET_BIND_SERVICE"
           "CAP_NET_RAW"
-        ]));
+        ]);
         componentsUsingBluetooth = [
           # Components that require the AF_BLUETOOTH address family
           "bluetooth_tracker"
diff --git a/nixos/modules/services/logging/filebeat.nix b/nixos/modules/services/logging/filebeat.nix
index ec8df0a7b87d2..3dc9df372ac5e 100644
--- a/nixos/modules/services/logging/filebeat.nix
+++ b/nixos/modules/services/logging/filebeat.nix
@@ -31,20 +31,20 @@ in
       };
 
       inputs = mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Inputs specify how Filebeat locates and processes input data.
 
-          This is like <literal>services.filebeat.settings.filebeat.inputs</literal>,
+          This is like `services.filebeat.settings.filebeat.inputs`,
           but structured as an attribute set. This has the benefit
           that multiple NixOS modules can contribute settings to a
           single filebeat input.
 
           An input type can be specified multiple times by choosing a
-          different <literal>&lt;name></literal> for each, but setting
-          <xref linkend="opt-services.filebeat.inputs._name_.type"/>
+          different `<name>` for each, but setting
+          [](#opt-services.filebeat.inputs._name_.type)
           to the same value.
 
-          See <link xlink:href="https://www.elastic.co/guide/en/beats/filebeat/current/configuration-filebeat-options.html"/>.
+          See <https://www.elastic.co/guide/en/beats/filebeat/current/configuration-filebeat-options.html>.
         '';
         default = {};
         type = types.attrsOf (types.submodule ({ name, ... }: {
@@ -77,24 +77,24 @@ in
       };
 
       modules = mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Filebeat modules provide a quick way to get started
           processing common log formats. They contain default
           configurations, Elasticsearch ingest pipeline definitions,
           and Kibana dashboards to help you implement and deploy a log
           monitoring solution.
 
-          This is like <literal>services.filebeat.settings.filebeat.modules</literal>,
+          This is like `services.filebeat.settings.filebeat.modules`,
           but structured as an attribute set. This has the benefit
           that multiple NixOS modules can contribute settings to a
           single filebeat module.
 
           A module can be specified multiple times by choosing a
-          different <literal>&lt;name></literal> for each, but setting
-          <xref linkend="opt-services.filebeat.modules._name_.module"/>
+          different `<name>` for each, but setting
+          [](#opt-services.filebeat.modules._name_.module)
           to the same value.
 
-          See <link xlink:href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html"/>.
+          See <https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html>.
         '';
         default = {};
         type = types.attrsOf (types.submodule ({ name, ... }: {
@@ -161,8 +161,7 @@ in
                 internal = true;
                 description = ''
                   Inputs specify how Filebeat locates and processes
-                  input data. Use <xref
-                  linkend="opt-services.filebeat.inputs"/> instead.
+                  input data. Use <xref linkend="opt-services.filebeat.inputs"/> instead.
 
                   See <link xlink:href="https://www.elastic.co/guide/en/beats/filebeat/current/configuration-filebeat-options.html"/>.
                 '';
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
index a6eb08ac5eac4..53230cc51e59e 100644
--- a/nixos/modules/services/logging/logrotate.nix
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -276,9 +276,9 @@ in
         defaultText = ''
           A configuration file automatically generated by NixOS.
         '';
-        description = ''
+        description = lib.mdDoc ''
           Override the configuration file used by MySQL. By default,
-          NixOS generates one automatically from <xref linkend="opt-services.logrotate.settings"/>.
+          NixOS generates one automatically from [](#opt-services.logrotate.settings).
         '';
         example = literalExpression ''
           pkgs.writeText "logrotate.conf" '''
@@ -346,11 +346,11 @@ in
       extraConfig = mkOption {
         default = "";
         type = types.lines;
-        description = ''
+        description = lib.mdDoc ''
           Extra contents to append to the logrotate configuration file. Refer to
-          <link xlink:href="https://linux.die.net/man/8/logrotate"/> for details.
+          <https://linux.die.net/man/8/logrotate> for details.
           This setting has been deprecated in favor of
-          <link linkend="opt-services.logrotate.settings">logrotate settings</link>.
+          [logrotate settings](#opt-services.logrotate.settings).
         '';
       };
     };
diff --git a/nixos/modules/services/mail/mailman.nix b/nixos/modules/services/mail/mailman.nix
index eb24f73c1da82..c76d40a68c3c6 100644
--- a/nixos/modules/services/mail/mailman.nix
+++ b/nixos/modules/services/mail/mailman.nix
@@ -112,9 +112,9 @@ in {
         bindPasswordFile = mkOption {
           type = types.str;
           example = "/run/secrets/ldap-bind";
-          description = ''
+          description = lib.mdDoc ''
             Path to the file containing the bind password of the servie account
-            defined by <xref linkend="opt-services.mailman.ldap.bindDn" />.
+            defined by [](#opt-services.mailman.ldap.bindDn).
           '';
         };
         superUserGroup = mkOption {
diff --git a/nixos/modules/services/mail/nullmailer.nix b/nixos/modules/services/mail/nullmailer.nix
index 59329667f7ad0..336c76c985085 100644
--- a/nixos/modules/services/mail/nullmailer.nix
+++ b/nixos/modules/services/mail/nullmailer.nix
@@ -38,11 +38,11 @@ with lib;
       remotesFile = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = ''
-          Path to the <code>remotes</code> control file. This file contains a
+        description = lib.mdDoc ''
+          Path to the `remotes` control file. This file contains a
           list of remote servers to which to send each message.
 
-          See <code>man 8 nullmailer-send</code> for syntax and available
+          See `man 8 nullmailer-send` for syntax and available
           options.
         '';
       };
@@ -153,17 +153,17 @@ with lib;
         remotes = mkOption {
           type = types.nullOr types.str;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             A list of remote servers to which to send each message. Each line
             contains a remote host name or address followed by an optional
             protocol string, separated by white space.
 
-            See <code>man 8 nullmailer-send</code> for syntax and available
+            See `man 8 nullmailer-send` for syntax and available
             options.
 
             WARNING: This is stored world-readable in the nix store. If you need
             to specify any secret credentials here, consider using the
-            <code>remotesFile</code> option instead.
+            `remotesFile` option instead.
           '';
         };
 
diff --git a/nixos/modules/services/mail/postfixadmin.nix b/nixos/modules/services/mail/postfixadmin.nix
index 27b5c60ec072f..b86428770cb21 100644
--- a/nixos/modules/services/mail/postfixadmin.nix
+++ b/nixos/modules/services/mail/postfixadmin.nix
@@ -13,12 +13,12 @@ in
     enable = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable postfixadmin.
 
         Also enables nginx virtual host management.
-        Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.&lt;name&gt;</literal>.
-        See <xref linkend="opt-services.nginx.virtualHosts"/> for further information.
+        Further nginx configuration can be done by adapting `services.nginx.virtualHosts.<name>`.
+        See [](#opt-services.nginx.virtualHosts) for further information.
       '';
     };
 
diff --git a/nixos/modules/services/mail/public-inbox.nix b/nixos/modules/services/mail/public-inbox.nix
index bb835881ba0a0..a81dd1cdb37bf 100644
--- a/nixos/modules/services/mail/public-inbox.nix
+++ b/nixos/modules/services/mail/public-inbox.nix
@@ -23,10 +23,10 @@ let
     port = mkOption {
       type = with types; nullOr (either str port);
       default = defaultPort;
-      description = ''
+      description = lib.mdDoc ''
         Listening port.
         Beware that public-inbox uses well-known ports number to decide whether to enable TLS or not.
-        Set to null and use <code>systemd.sockets.public-inbox-${proto}d.listenStreams</code>
+        Set to null and use `systemd.sockets.public-inbox-${proto}d.listenStreams`
         if you need a more advanced listening.
       '';
     };
@@ -239,11 +239,11 @@ in
         type = with types; nullOr (either str port);
         default = 80;
         example = "/run/public-inbox-httpd.sock";
-        description = ''
+        description = lib.mdDoc ''
           Listening port or systemd's ListenStream= entry
           to be used as a reverse proxy, eg. in nginx:
-          <code>locations."/inbox".proxyPass = "http://unix:''${config.services.public-inbox.http.port}:/inbox";</code>
-          Set to null and use <code>systemd.sockets.public-inbox-httpd.listenStreams</code>
+          `locations."/inbox".proxyPass = "http://unix:''${config.services.public-inbox.http.port}:/inbox";`
+          Set to null and use `systemd.sockets.public-inbox-httpd.listenStreams`
           if you need a more advanced listening.
         '';
       };
diff --git a/nixos/modules/services/mail/roundcube.nix b/nixos/modules/services/mail/roundcube.nix
index 3b6c06d19e862..d8adf53e48a94 100644
--- a/nixos/modules/services/mail/roundcube.nix
+++ b/nixos/modules/services/mail/roundcube.nix
@@ -14,12 +14,12 @@ in
     enable = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable roundcube.
 
         Also enables nginx virtual host management.
-        Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.&lt;name&gt;</literal>.
-        See <xref linkend="opt-services.nginx.virtualHosts"/> for further information.
+        Further nginx configuration can be done by adapting `services.nginx.virtualHosts.<name>`.
+        See [](#opt-services.nginx.virtualHosts) for further information.
       '';
     };
 
@@ -99,11 +99,11 @@ in
     maxAttachmentSize = mkOption {
       type = types.int;
       default = 18;
-      description = ''
+      description = lib.mdDoc ''
         The maximum attachment size in MB.
 
         Note: Since roundcube only uses 70% of max upload values configured in php
-        30% is added automatically to <xref linkend="opt-services.roundcube.maxAttachmentSize"/>.
+        30% is added automatically to [](#opt-services.roundcube.maxAttachmentSize).
       '';
       apply = configuredMaxAttachmentSize: "${toString (configuredMaxAttachmentSize * 1.3)}M";
     };
diff --git a/nixos/modules/services/mail/sympa.nix b/nixos/modules/services/mail/sympa.nix
index 1d46b090cd844..0014701d58313 100644
--- a/nixos/modules/services/mail/sympa.nix
+++ b/nixos/modules/services/mail/sympa.nix
@@ -86,9 +86,9 @@ in
       type = str;
       default = "en_US";
       example = "cs";
-      description = ''
+      description = lib.mdDoc ''
         Default Sympa language.
-        See <link xlink:href='https://github.com/sympa-community/sympa/tree/sympa-6.2/po/sympa' />
+        See <https://github.com/sympa-community/sympa/tree/sympa-6.2/po/sympa>
         for available options.
       '';
     };
@@ -136,9 +136,9 @@ in
             example = {
               default_max_list_members = 3;
             };
-            description = ''
-              The <filename>robot.conf</filename> configuration file as key value set.
-              See <link xlink:href='https://sympa-community.github.io/gpldoc/man/sympa.conf.5.html' />
+            description = lib.mdDoc ''
+              The {file}`robot.conf` configuration file as key value set.
+              See <https://sympa-community.github.io/gpldoc/man/sympa.conf.5.html>
               for list of configuration parameters.
             '';
           };
@@ -242,7 +242,7 @@ in
         description = ''
           The webserver used for the Sympa web interface. Set it to `none` if you want to configure it yourself.
           Further nginx configuration can be done by adapting
-          <option>services.nginx.virtualHosts.<replaceable>name</replaceable></option>.
+          <option>services.nginx.virtualHosts.«name»</option>.
         '';
       };
 
@@ -285,9 +285,9 @@ in
           viewlogs_page_size = 50;
         }
       '';
-      description = ''
-        The <filename>sympa.conf</filename> configuration file as key value set.
-        See <link xlink:href='https://sympa-community.github.io/gpldoc/man/sympa.conf.5.html' />
+      description = lib.mdDoc ''
+        The {file}`sympa.conf` configuration file as key value set.
+        See <https://sympa-community.github.io/gpldoc/man/sympa.conf.5.html>
         for list of configuration parameters.
       '';
     };
diff --git a/nixos/modules/services/matrix/appservice-discord.nix b/nixos/modules/services/matrix/appservice-discord.nix
index fa55b3c5de70e..c72a2123a923a 100644
--- a/nixos/modules/services/matrix/appservice-discord.nix
+++ b/nixos/modules/services/matrix/appservice-discord.nix
@@ -40,23 +40,16 @@ in {
             };
           }
         '';
-        description = ''
-          <filename>config.yaml</filename> configuration as a Nix attribute set.
-          </para>
+        description = lib.mdDoc ''
+          {file}`config.yaml` configuration as a Nix attribute set.
 
-          <para>
           Configuration options should match those described in
-          <link xlink:href="https://github.com/Half-Shot/matrix-appservice-discord/blob/master/config/config.sample.yaml">
-          config.sample.yaml</link>.
-          </para>
+          [config.sample.yaml](https://github.com/Half-Shot/matrix-appservice-discord/blob/master/config/config.sample.yaml).
 
-          <para>
-          <option>config.bridge.domain</option> and <option>config.bridge.homeserverUrl</option>
+          {option}`config.bridge.domain` and {option}`config.bridge.homeserverUrl`
           should be set to match the public host name of the Matrix homeserver for webhooks and avatars to work.
-          </para>
 
-          <para>
-          Secret tokens should be specified using <option>environmentFile</option>
+          Secret tokens should be specified using {option}`environmentFile`
           instead of this world-readable attribute set.
         '';
       };
diff --git a/nixos/modules/services/matrix/mautrix-facebook.nix b/nixos/modules/services/matrix/mautrix-facebook.nix
index 55067abaa52a2..dfdf6e250215a 100644
--- a/nixos/modules/services/matrix/mautrix-facebook.nix
+++ b/nixos/modules/services/matrix/mautrix-facebook.nix
@@ -75,15 +75,12 @@ in {
             };
           }
         '';
-        description = ''
-          <filename>config.yaml</filename> configuration as a Nix attribute set.
+        description = lib.mdDoc ''
+          {file}`config.yaml` configuration as a Nix attribute set.
           Configuration options should match those described in
-          <link xlink:href="https://github.com/mautrix/facebook/blob/master/mautrix_facebook/example-config.yaml">
-          example-config.yaml</link>.
-          </para>
+          [example-config.yaml](https://github.com/mautrix/facebook/blob/master/mautrix_facebook/example-config.yaml).
 
-          <para>
-          Secret tokens should be specified using <option>environmentFile</option>
+          Secret tokens should be specified using {option}`environmentFile`
           instead of this world-readable attribute set.
         '';
       };
diff --git a/nixos/modules/services/matrix/mautrix-telegram.nix b/nixos/modules/services/matrix/mautrix-telegram.nix
index c6527be5263cb..196100a531ad7 100644
--- a/nixos/modules/services/matrix/mautrix-telegram.nix
+++ b/nixos/modules/services/matrix/mautrix-telegram.nix
@@ -78,15 +78,12 @@ in {
             };
           }
         '';
-        description = ''
-          <filename>config.yaml</filename> configuration as a Nix attribute set.
+        description = lib.mdDoc ''
+          {file}`config.yaml` configuration as a Nix attribute set.
           Configuration options should match those described in
-          <link xlink:href="https://github.com/tulir/mautrix-telegram/blob/master/example-config.yaml">
-          example-config.yaml</link>.
-          </para>
+          [example-config.yaml](https://github.com/tulir/mautrix-telegram/blob/master/example-config.yaml).
 
-          <para>
-          Secret tokens should be specified using <option>environmentFile</option>
+          Secret tokens should be specified using {option}`environmentFile`
           instead of this world-readable attribute set.
         '';
       };
diff --git a/nixos/modules/services/misc/autorandr.nix b/nixos/modules/services/misc/autorandr.nix
index 11dc915c2afa4..036bb4f41bef5 100644
--- a/nixos/modules/services/misc/autorandr.nix
+++ b/nixos/modules/services/misc/autorandr.nix
@@ -27,9 +27,9 @@ let
     options = {
       fingerprint = mkOption {
         type = types.attrsOf types.str;
-        description = ''
+        description = lib.mdDoc ''
           Output name to EDID mapping.
-          Use <code>autorandr --fingerprint</code> to get current setup values.
+          Use `autorandr --fingerprint` to get current setup values.
         '';
         default = { };
       };
@@ -154,7 +154,7 @@ let
         });
         description = ''
           Output scale configuration.
-          </para><para>
+
           Either configure by pixels or a scaling factor. When using pixel method the
           <citerefentry>
             <refentrytitle>xrandr</refentrytitle>
@@ -165,7 +165,7 @@ let
           will be used; when using factor method the option
           <parameter class="command">--scale</parameter>
           will be used.
-          </para><para>
+
           This option is a shortcut version of the transform option and they are mutually
           exclusive.
         '';
diff --git a/nixos/modules/services/misc/bees.nix b/nixos/modules/services/misc/bees.nix
index 1b4923150266b..37f90c682221a 100644
--- a/nixos/modules/services/misc/bees.nix
+++ b/nixos/modules/services/misc/bees.nix
@@ -11,14 +11,13 @@ let
   fsOptions = with types; {
     options.spec = mkOption {
       type = str;
-      description = ''
+      description = lib.mdDoc ''
         Description of how to identify the filesystem to be duplicated by this
         instance of bees. Note that deduplication crosses subvolumes; one must
         not configure multiple instances for subvolumes of the same filesystem
         (or block devices which are part of the same filesystem), but only for
         completely independent btrfs filesystems.
-        </para>
-        <para>
+
         This must be in a format usable by findmnt; that could be a key=value
         pair, or a bare path to a mount point.
         Using bare paths will allow systemd to start the beesd service only
@@ -29,14 +28,12 @@ let
     options.hashTableSizeMB = mkOption {
       type = types.addCheck types.int (n: mod n 16 == 0);
       default = 1024; # 1GB; default from upstream beesd script
-      description = ''
+      description = lib.mdDoc ''
         Hash table size in MB; must be a multiple of 16.
-        </para>
-        <para>
+
         A larger ratio of index size to storage size means smaller blocks of
         duplicate content are recognized.
-        </para>
-        <para>
+
         If you have 1TB of data, a 4GB hash table (which is to say, a value of
         4096) will permit 4KB extents (the smallest possible size) to be
         recognized, whereas a value of 1024 -- creating a 1GB hash table --
diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix
index d589ad780c1b0..3343e94778a2b 100644
--- a/nixos/modules/services/misc/etcd.nix
+++ b/nixos/modules/services/misc/etcd.nix
@@ -125,9 +125,9 @@ in {
     };
 
     extraConf = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         Etcd extra configuration. See
-        <link xlink:href='https://github.com/coreos/etcd/blob/master/Documentation/op-guide/configuration.md#configuration-flags' />
+        <https://github.com/coreos/etcd/blob/master/Documentation/op-guide/configuration.md#configuration-flags>
       '';
       type = types.attrsOf types.str;
       default = {};
diff --git a/nixos/modules/services/misc/etebase-server.nix b/nixos/modules/services/misc/etebase-server.nix
index 24be9e8e2692b..1359c265c8f12 100644
--- a/nixos/modules/services/misc/etebase-server.nix
+++ b/nixos/modules/services/misc/etebase-server.nix
@@ -135,8 +135,8 @@ in
         default = {};
         description = ''
           Configuration for <package>etebase-server</package>. Refer to
-          <link xlink:href="https://github.com/etesync/server/blob/master/etebase-server.ini.example" />
-          and <link xlink:href="https://github.com/etesync/server/wiki" />
+          <link xlink:href="https://github.com/etesync/server/blob/master/etebase-server.ini.example"/>
+          and <link xlink:href="https://github.com/etesync/server/wiki"/>
           for details on supported values.
         '';
         example = {
diff --git a/nixos/modules/services/misc/geoipupdate.nix b/nixos/modules/services/misc/geoipupdate.nix
index 20bbba0aad9ae..98d470412142b 100644
--- a/nixos/modules/services/misc/geoipupdate.nix
+++ b/nixos/modules/services/misc/geoipupdate.nix
@@ -40,7 +40,7 @@ in
         description = ''
           <productname>geoipupdate</productname> configuration
           options. See
-          <link xlink:href="https://github.com/maxmind/geoipupdate/blob/main/doc/GeoIP.conf.md" />
+          <link xlink:href="https://github.com/maxmind/geoipupdate/blob/main/doc/GeoIP.conf.md"/>
           for a full list of available options.
 
           Settings containing secret data should be set to an
@@ -92,8 +92,7 @@ in
 
                 Always handled as a secret whether the value is
                 wrapped in a <literal>{ _secret = ...; }</literal>
-                attrset or not (refer to <xref
-                linkend="opt-services.geoipupdate.settings" /> for
+                attrset or not (refer to <xref linkend="opt-services.geoipupdate.settings"/> for
                 details).
               '';
               apply = x: if isAttrs x then x else { _secret = x; };
diff --git a/nixos/modules/services/misc/gitit.nix b/nixos/modules/services/misc/gitit.nix
index 87dd97166b8eb..223fa76d9106b 100644
--- a/nixos/modules/services/misc/gitit.nix
+++ b/nixos/modules/services/misc/gitit.nix
@@ -689,14 +689,14 @@ in
           ''
           if [ ! -d _darcs ]
           then
-            ${pkgs.darcs}/bin/darcs initialize
+            darcs initialize
             echo "${gm}" > _darcs/prefs/email
           ''
           else if repositoryType == "mercurial" then
           ''
           if [ ! -d .hg ]
           then
-            ${pkgs.mercurial}/bin/hg init
+            hg init
             cat >> .hg/hgrc <<NAMED
 [ui]
 username = gitit ${gm}
@@ -706,9 +706,9 @@ NAMED
           ''
           if [ ! -d  .git ]
           then
-            ${pkgs.git}/bin/git init
-            ${pkgs.git}/bin/git config user.email "${gm}"
-            ${pkgs.git}/bin/git config user.name "gitit"
+            git init
+            git config user.email "${gm}"
+            git config user.name "gitit"
           ''}
           chown ${uid}:${gid} -R ${repositoryPath}
           fi
diff --git a/nixos/modules/services/misc/klipper.nix b/nixos/modules/services/misc/klipper.nix
index 52913369bbcdd..b34ca6f8c5d2a 100644
--- a/nixos/modules/services/misc/klipper.nix
+++ b/nixos/modules/services/misc/klipper.nix
@@ -71,7 +71,7 @@ in
       };
 
       firmwares = mkOption {
-        description = "Firmwares klipper should manage";
+        description = lib.mdDoc "Firmwares klipper should manage";
         default = { };
         type = with types; attrsOf
           (submodule {
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index c76aaaa559bf4..93ff5fcfb8634 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -636,12 +636,10 @@ in
             <manvolnum>5</manvolnum>
           </citerefentry> for avalaible options.
           The value declared here will be translated directly to the key-value pairs Nix expects.
-          </para>
-          <para>
+
           You can use <command>nix-instantiate --eval --strict '&lt;nixpkgs/nixos&gt;' -A config.nix.settings</command>
           to view the current value. By default it is empty.
-          </para>
-          <para>
+
           Nix configurations defined under <option>nix.*</option> will be translated and applied to this
           option. In addition, configuration specified in <option>nix.extraOptions</option> which will be appended
           verbatim to the resulting config file.
diff --git a/nixos/modules/services/misc/persistent-evdev.nix b/nixos/modules/services/misc/persistent-evdev.nix
index 401d20010b12a..fd6e298ef651f 100644
--- a/nixos/modules/services/misc/persistent-evdev.nix
+++ b/nixos/modules/services/misc/persistent-evdev.nix
@@ -22,8 +22,8 @@ in
         Physical devices should already exist in <filename class="devicefile">/dev/input/by-id/</filename>.
         Proxy devices will be automatically given a <literal>uinput-</literal> prefix.
 
-        See the <link xlink:href="https://github.com/aiberia/persistent-evdev#example-usage-with-libvirt">
-        project page</link> for example configuration of virtual devices with libvirt
+        See the <link xlink:href="https://github.com/aiberia/persistent-evdev#example-usage-with-libvirt">project page</link>
+        for example configuration of virtual devices with libvirt
         and remember to add <literal>uinput-*</literal> devices to the qemu
         <literal>cgroup_device_acl</literal> list (see <xref linkend="opt-virtualisation.libvirtd.qemu.verbatimConfig"/>).
       '';
diff --git a/nixos/modules/services/misc/sourcehut/default.nix b/nixos/modules/services/misc/sourcehut/default.nix
index 3ff2837900eca..de04797a800c6 100644
--- a/nixos/modules/services/misc/sourcehut/default.nix
+++ b/nixos/modules/services/misc/sourcehut/default.nix
@@ -180,7 +180,7 @@ in
           network-key = mkOption {
             description = ''
               An absolute file path (which should be outside the Nix-store)
-              to a secret key to encrypt internal messages with. Use <code>srht-keygen network</code> to
+              to a secret key to encrypt internal messages with. Use <literal>srht-keygen network</literal> to
               generate this key. It must be consistent between all services and nodes.
             '';
             type = types.path;
@@ -209,7 +209,7 @@ in
           service-key = mkOption {
             description = ''
               An absolute file path (which should be outside the Nix-store)
-              to a key used for encrypting session cookies. Use <code>srht-keygen service</code> to
+              to a key used for encrypting session cookies. Use <literal>srht-keygen service</literal> to
               generate the service key. This must be shared between each node of the same
               service (e.g. git1.sr.ht and git2.sr.ht), but different services may use
               different keys. If you configure all of your services with the same
@@ -252,8 +252,8 @@ in
 
               Your PGP key information (DO NOT mix up pub and priv here)
               You must remove the password from your secret key, if present.
-              You can do this with <code>gpg --edit-key [key-id]</code>,
-              then use the <code>passwd</code> command and do not enter a new password.
+              You can do this with <literal>gpg --edit-key [key-id]</literal>,
+              then use the <literal>passwd</literal> command and do not enter a new password.
             '';
           };
           pgp-pubkey = mkOption {
@@ -294,7 +294,7 @@ in
               This should be consistent for all *.sr.ht sites,
               as this key will be used to verify signatures
               from other sites in your network.
-              Use the <code>srht-keygen webhook</code> command to generate a key.
+              Use the <literal>srht-keygen webhook</literal> command to generate a key.
             '';
             type = types.path;
             apply = s: "<" + toString s;
diff --git a/nixos/modules/services/misc/sssd.nix b/nixos/modules/services/misc/sssd.nix
index 3f6b96258f16c..70afbe0433ae0 100644
--- a/nixos/modules/services/misc/sssd.nix
+++ b/nixos/modules/services/misc/sssd.nix
@@ -42,7 +42,7 @@ in {
       kcm = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to use SSS as a Kerberos Cache Manager (KCM).
           Kerberos will be configured to cache credentials in SSS.
         '';
diff --git a/nixos/modules/services/misc/zoneminder.nix b/nixos/modules/services/misc/zoneminder.nix
index ab24372037e62..ef3f6c1a0fd95 100644
--- a/nixos/modules/services/misc/zoneminder.nix
+++ b/nixos/modules/services/misc/zoneminder.nix
@@ -68,7 +68,7 @@ in {
     services.zoneminder = with lib; {
       enable = lib.mkEnableOption ''
         ZoneMinder
-        </para><para>
+
         If you intend to run the database locally, you should set
         `config.services.zoneminder.database.createLocally` to true. Otherwise,
         when set to `false` (the default), you will have to create the database
@@ -82,8 +82,6 @@ in {
         default = "nginx";
         description = ''
           The webserver to configure for the PHP frontend.
-          </para>
-          <para>
 
           Set it to `none` if you want to configure it yourself. PRs are welcome
           for support for other web servers.
diff --git a/nixos/modules/services/monitoring/cadvisor.nix b/nixos/modules/services/monitoring/cadvisor.nix
index c844b1599dd46..d5e4403101621 100644
--- a/nixos/modules/services/monitoring/cadvisor.nix
+++ b/nixos/modules/services/monitoring/cadvisor.nix
@@ -66,16 +66,16 @@ in {
 
       storageDriverPasswordFile = mkOption {
         type = types.str;
-        description = ''
+        description = lib.mdDoc ''
           File that contains the cadvisor storage driver password.
 
-          <option>storageDriverPasswordFile</option> takes precedence over <option>storageDriverPassword</option>
+          {option}`storageDriverPasswordFile` takes precedence over {option}`storageDriverPassword`
 
-          Warning: when <option>storageDriverPassword</option> is non-empty this defaults to a file in the
-          world-readable Nix store that contains the value of <option>storageDriverPassword</option>.
+          Warning: when {option}`storageDriverPassword` is non-empty this defaults to a file in the
+          world-readable Nix store that contains the value of {option}`storageDriverPassword`.
 
           It's recommended to override this with a path not in the Nix store.
-          Tip: use <link xlink:href='https://nixos.org/nixops/manual/#idm140737318306400'>nixops key management</link>
+          Tip: use [nixops key management](https://nixos.org/nixops/manual/#idm140737318306400)
         '';
       };
 
@@ -88,10 +88,10 @@ in {
       extraOptions = mkOption {
         type = types.listOf types.str;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           Additional cadvisor options.
 
-          See <link xlink:href='https://github.com/google/cadvisor/blob/master/docs/runtime_options.md'/> for available options.
+          See <https://github.com/google/cadvisor/blob/master/docs/runtime_options.md> for available options.
         '';
       };
     };
diff --git a/nixos/modules/services/monitoring/grafana-image-renderer.nix b/nixos/modules/services/monitoring/grafana-image-renderer.nix
index 97488f2653a5b..4820b19469875 100644
--- a/nixos/modules/services/monitoring/grafana-image-renderer.nix
+++ b/nixos/modules/services/monitoring/grafana-image-renderer.nix
@@ -92,7 +92,7 @@ in {
       description = ''
         Configuration attributes for <package>grafana-image-renderer</package>.
 
-        See <link xlink:href="https://github.com/grafana/grafana-image-renderer/blob/ce1f81438e5f69c7fd7c73ce08bab624c4c92e25/default.json" />
+        See <link xlink:href="https://github.com/grafana/grafana-image-renderer/blob/ce1f81438e5f69c7fd7c73ce08bab624c4c92e25/default.json"/>
         for supported values.
       '';
     };
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index 73b509202df66..8edb2ca099749 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -251,9 +251,9 @@ in {
 
       extraConfig = mkOption {
         default = {};
-        description = ''
+        description = lib.mdDoc ''
           Extra seyren configuration. See
-          <link xlink:href='https://github.com/scobal/seyren#config' />
+          <https://github.com/scobal/seyren#config>
         '';
         type = types.attrsOf types.str;
         example = literalExpression ''
diff --git a/nixos/modules/services/monitoring/metricbeat.nix b/nixos/modules/services/monitoring/metricbeat.nix
index 0968d25c2ad2d..14066da1be81d 100644
--- a/nixos/modules/services/monitoring/metricbeat.nix
+++ b/nixos/modules/services/monitoring/metricbeat.nix
@@ -32,17 +32,17 @@ in
       };
 
       modules = mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Metricbeat modules are responsible for reading metrics from the various sources.
 
-          This is like <literal>services.metricbeat.settings.metricbeat.modules</literal>,
+          This is like `services.metricbeat.settings.metricbeat.modules`,
           but structured as an attribute set. This has the benefit that multiple
           NixOS modules can contribute settings to a single metricbeat module.
 
-          A module can be specified multiple times by choosing a different <literal>&lt;name></literal>
-          for each, but setting <xref linkend="opt-services.metricbeat.modules._name_.module"/> to the same value.
+          A module can be specified multiple times by choosing a different `<name>`
+          for each, but setting [](#opt-services.metricbeat.modules._name_.module) to the same value.
 
-          See <link xlink:href="https://www.elastic.co/guide/en/beats/metricbeat/current/metricbeat-modules.html"/>.
+          See <https://www.elastic.co/guide/en/beats/metricbeat/current/metricbeat-modules.html>.
         '';
         default = {};
         type = types.attrsOf (types.submodule ({ name, ... }: {
diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix
index c77ae7b3b6eb2..9461bd3f35b8a 100644
--- a/nixos/modules/services/monitoring/munin.nix
+++ b/nixos/modules/services/monitoring/munin.nix
@@ -138,29 +138,29 @@ in
       enable = mkOption {
         default = false;
         type = types.bool;
-        description = ''
+        description = lib.mdDoc ''
           Enable Munin Node agent. Munin node listens on 0.0.0.0 and
           by default accepts connections only from 127.0.0.1 for security reasons.
 
-          See <link xlink:href='http://guide.munin-monitoring.org/en/latest/architecture/index.html' />.
+          See <http://guide.munin-monitoring.org/en/latest/architecture/index.html>.
         '';
       };
 
       extraConfig = mkOption {
         default = "";
         type = types.lines;
-        description = ''
-          <filename>munin-node.conf</filename> extra configuration. See
-          <link xlink:href='http://guide.munin-monitoring.org/en/latest/reference/munin-node.conf.html' />
+        description = lib.mdDoc ''
+          {file}`munin-node.conf` extra configuration. See
+          <http://guide.munin-monitoring.org/en/latest/reference/munin-node.conf.html>
         '';
       };
 
       extraPluginConfig = mkOption {
         default = "";
         type = types.lines;
-        description = ''
-          <filename>plugin-conf.d</filename> extra plugin configuration. See
-          <link xlink:href='http://guide.munin-monitoring.org/en/latest/plugin/use.html' />
+        description = lib.mdDoc ''
+          {file}`plugin-conf.d` extra plugin configuration. See
+          <http://guide.munin-monitoring.org/en/latest/plugin/use.html>
         '';
         example = ''
           [fail2ban_*]
@@ -266,11 +266,11 @@ in
       extraGlobalConfig = mkOption {
         default = "";
         type = types.lines;
-        description = ''
-          <filename>munin.conf</filename> extra global configuration.
-          See <link xlink:href='http://guide.munin-monitoring.org/en/latest/reference/munin.conf.html' />.
+        description = lib.mdDoc ''
+          {file}`munin.conf` extra global configuration.
+          See <http://guide.munin-monitoring.org/en/latest/reference/munin.conf.html>.
           Useful to setup notifications, see
-          <link xlink:href='http://guide.munin-monitoring.org/en/latest/tutorial/alert.html' />
+          <http://guide.munin-monitoring.org/en/latest/tutorial/alert.html>
         '';
         example = ''
           contact.email.command mail -s "Munin notification for ''${var:host}" someone@example.com
@@ -280,10 +280,10 @@ in
       hosts = mkOption {
         default = "";
         type = types.lines;
-        description = ''
+        description = lib.mdDoc ''
           Definitions of hosts of nodes to collect data from. Needs at least one
           host for cron to succeed. See
-          <link xlink:href='http://guide.munin-monitoring.org/en/latest/reference/munin.conf.html' />
+          <http://guide.munin-monitoring.org/en/latest/reference/munin.conf.html>
         '';
         example = literalExpression ''
           '''
diff --git a/nixos/modules/services/monitoring/nagios.nix b/nixos/modules/services/monitoring/nagios.nix
index 69173ce4e44ed..a17797f682f8b 100644
--- a/nixos/modules/services/monitoring/nagios.nix
+++ b/nixos/modules/services/monitoring/nagios.nix
@@ -88,7 +88,7 @@ in
 
   options = {
     services.nagios = {
-      enable = mkEnableOption "<link xlink:href='http://www.nagios.org/'>Nagios</link> to monitor your system or network.";
+      enable = mkEnableOption ''<link xlink:href="http://www.nagios.org/">Nagios</link> to monitor your system or network.'';
 
       objectDefs = mkOption {
         description = "
diff --git a/nixos/modules/services/monitoring/netdata.nix b/nixos/modules/services/monitoring/netdata.nix
index 4fd07a4ba1432..e20eaf3b14400 100644
--- a/nixos/modules/services/monitoring/netdata.nix
+++ b/nixos/modules/services/monitoring/netdata.nix
@@ -114,14 +114,14 @@ in {
         example = literalExpression ''
           [ "/path/to/plugins.d" ]
         '';
-        description = ''
+        description = lib.mdDoc ''
           Extra paths to add to the netdata global "plugins directory"
           option.  Useful for when you want to include your own
           collection scripts.
-          </para><para>
+
           Details about writing a custom netdata plugin are available at:
-          <link xlink:href="https://docs.netdata.cloud/collectors/plugins.d/"/>
-          </para><para>
+          <https://docs.netdata.cloud/collectors/plugins.d/>
+
           Cannot be combined with configText.
         '';
       };
diff --git a/nixos/modules/services/monitoring/parsedmarc.nix b/nixos/modules/services/monitoring/parsedmarc.nix
index 736718c25359c..b0858184b5fc4 100644
--- a/nixos/modules/services/monitoring/parsedmarc.nix
+++ b/nixos/modules/services/monitoring/parsedmarc.nix
@@ -29,11 +29,11 @@ in
         enable = lib.mkOption {
           type = lib.types.bool;
           default = false;
-          description = ''
+          description = lib.mdDoc ''
             Whether Postfix and Dovecot should be set up to receive
             mail locally. parsedmarc will be configured to watch the
             local inbox as the automatically created user specified in
-            <xref linkend="opt-services.parsedmarc.provision.localMail.recipientName" />
+            [](#opt-services.parsedmarc.provision.localMail.recipientName)
           '';
         };
 
@@ -68,15 +68,13 @@ in
       geoIp = lib.mkOption {
         type = lib.types.bool;
         default = true;
-        description = ''
-          Whether to enable and configure the <link
-          linkend="opt-services.geoipupdate.enable">geoipupdate</link>
+        description = lib.mdDoc ''
+          Whether to enable and configure the [geoipupdate](#opt-services.geoipupdate.enable)
           service to automatically fetch GeoIP databases. Not crucial,
           but recommended for full functionality.
 
-          To finish the setup, you need to manually set the <xref
-          linkend="opt-services.geoipupdate.settings.AccountID" /> and
-          <xref linkend="opt-services.geoipupdate.settings.LicenseKey" />
+          To finish the setup, you need to manually set the [](#opt-services.geoipupdate.settings.AccountID) and
+          [](#opt-services.geoipupdate.settings.LicenseKey)
           options.
         '';
       };
@@ -97,11 +95,11 @@ in
             config.${opt.provision.elasticsearch} && config.${options.services.grafana.enable}
           '';
           apply = x: x && cfg.provision.elasticsearch;
-          description = ''
+          description = lib.mdDoc ''
             Whether the automatically provisioned Elasticsearch
             instance should be added as a grafana datasource. Has no
             effect unless
-            <xref linkend="opt-services.parsedmarc.provision.elasticsearch" />
+            [](#opt-services.parsedmarc.provision.elasticsearch)
             is also enabled.
           '';
         };
@@ -208,13 +206,12 @@ in
             password = lib.mkOption {
               type = with lib.types; nullOr (either path (attrsOf path));
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 The IMAP server password.
 
                 Always handled as a secret whether the value is
-                wrapped in a <literal>{ _secret = ...; }</literal>
-                attrset or not (refer to <xref
-                linkend="opt-services.parsedmarc.settings" /> for
+                wrapped in a `{ _secret = ...; }`
+                attrset or not (refer to [](#opt-services.parsedmarc.settings) for
                 details).
               '';
               apply = x: if isAttrs x || x == null then x else { _secret = x; };
@@ -273,13 +270,12 @@ in
             password = lib.mkOption {
               type = with lib.types; nullOr (either path (attrsOf path));
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 The SMTP server password.
 
                 Always handled as a secret whether the value is
-                wrapped in a <literal>{ _secret = ...; }</literal>
-                attrset or not (refer to <xref
-                linkend="opt-services.parsedmarc.settings" /> for
+                wrapped in a `{ _secret = ...; }`
+                attrset or not (refer to [](#opt-services.parsedmarc.settings) for
                 details).
               '';
               apply = x: if isAttrs x || x == null then x else { _secret = x; };
@@ -326,14 +322,13 @@ in
             password = lib.mkOption {
               type = with lib.types; nullOr (either path (attrsOf path));
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 The password to use when connecting to Elasticsearch,
                 if required.
 
                 Always handled as a secret whether the value is
-                wrapped in a <literal>{ _secret = ...; }</literal>
-                attrset or not (refer to <xref
-                linkend="opt-services.parsedmarc.settings" /> for
+                wrapped in a `{ _secret = ...; }`
+                attrset or not (refer to [](#opt-services.parsedmarc.settings) for
                 details).
               '';
               apply = x: if isAttrs x || x == null then x else { _secret = x; };
diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix
index db4286b66a5d3..3bc61fba158f3 100644
--- a/nixos/modules/services/monitoring/prometheus/default.nix
+++ b/nixos/modules/services/monitoring/prometheus/default.nix
@@ -379,9 +379,8 @@ let
       gce_sd_configs = mkOpt (types.listOf promTypes.gce_sd_config) ''
         List of Google Compute Engine service discovery configurations.
 
-        See <link
-        xlink:href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/#gce_sd_config">the
-        relevant Prometheus configuration docs</link> for more detail.
+        See <link xlink:href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/#gce_sd_config">the relevant Prometheus configuration docs</link>
+        for more detail.
       '';
 
       hetzner_sd_configs = mkOpt (types.listOf promTypes.hetzner_sd_config) ''
@@ -807,9 +806,7 @@ let
       filter = mkOpt types.str ''
         Filter can be used optionally to filter the instance list by other
         criteria Syntax of this filter string is described here in the filter
-        query parameter section: <link
-        xlink:href="https://cloud.google.com/compute/docs/reference/latest/instances/list"
-        />.
+        query parameter section: <link xlink:href="https://cloud.google.com/compute/docs/reference/latest/instances/list"/>.
       '';
 
       refresh_interval = mkDefOpt types.str "60s" ''
@@ -825,7 +822,7 @@ let
         The tag separator used to separate concatenated GCE instance network tags.
 
         See the GCP documentation on network tags for more information:
-        <link xlink:href="https://cloud.google.com/vpc/docs/add-remove-network-tags" />
+        <link xlink:href="https://cloud.google.com/vpc/docs/add-remove-network-tags"/>
       '';
     };
   };
@@ -1033,13 +1030,13 @@ let
 
     auth_token = mkOpt types.str ''
       Optional authentication information for token-based authentication:
-      <link xlink:href="https://docs.mesosphere.com/1.11/security/ent/iam-api/#passing-an-authentication-token" />
+      <link xlink:href="https://docs.mesosphere.com/1.11/security/ent/iam-api/#passing-an-authentication-token"/>
       It is mutually exclusive with <literal>auth_token_file</literal> and other authentication mechanisms.
     '';
 
     auth_token_file = mkOpt types.str ''
       Optional authentication information for token-based authentication:
-      <link xlink:href="https://docs.mesosphere.com/1.11/security/ent/iam-api/#passing-an-authentication-token" />
+      <link xlink:href="https://docs.mesosphere.com/1.11/security/ent/iam-api/#passing-an-authentication-token"/>
       It is mutually exclusive with <literal>auth_token</literal> and other authentication mechanisms.
     '';
   };
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix b/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix
index 092ac6fea7d74..4e7aae0b34b59 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix
@@ -33,10 +33,10 @@ in
         work with this exporter:
         <programlisting>
         {
-          <xref linkend="opt-services.prometheus.exporters.dovecot.enable" /> = true;
-          <xref linkend="opt-services.prometheus.exporters.dovecot.socketPath" /> = "/var/run/dovecot2/old-stats";
-          <xref linkend="opt-services.dovecot2.mailPlugins.globally.enable" /> = [ "old_stats" ];
-          <xref linkend="opt-services.dovecot2.extraConfig" /> = '''
+          <xref linkend="opt-services.prometheus.exporters.dovecot.enable"/> = true;
+          <xref linkend="opt-services.prometheus.exporters.dovecot.socketPath"/> = "/var/run/dovecot2/old-stats";
+          <xref linkend="opt-services.dovecot2.mailPlugins.globally.enable"/> = [ "old_stats" ];
+          <xref linkend="opt-services.dovecot2.extraConfig"/> = '''
             service old-stats {
               unix_listener old-stats {
                 user = dovecot-exporter
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/process.nix b/nixos/modules/services/monitoring/prometheus/exporters/process.nix
index 1e9c402fb55bd..666116991b5a9 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/process.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/process.nix
@@ -22,7 +22,7 @@ in
         All settings expressed as an Nix attrset.
 
         Check the official documentation for the corresponding YAML
-        settings that can all be used here: <link xlink:href="https://github.com/ncabatoff/process-exporter" />
+        settings that can all be used here: <link xlink:href="https://github.com/ncabatoff/process-exporter"/>
       '';
     };
   };
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/script.nix b/nixos/modules/services/monitoring/prometheus/exporters/script.nix
index a805a0ad335d2..2a43fbcab3a10 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/script.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/script.nix
@@ -41,7 +41,7 @@ in
         All settings expressed as an Nix attrset.
 
         Check the official documentation for the corresponding YAML
-        settings that can all be used here: <link xlink:href="https://github.com/adhocteam/script_exporter#sample-configuration" />
+        settings that can all be used here: <link xlink:href="https://github.com/adhocteam/script_exporter#sample-configuration"/>
       '';
     };
   };
diff --git a/nixos/modules/services/networking/biboumi.nix b/nixos/modules/services/networking/biboumi.nix
index 7e60330088324..24e0c0328fe68 100644
--- a/nixos/modules/services/networking/biboumi.nix
+++ b/nixos/modules/services/networking/biboumi.nix
@@ -83,13 +83,13 @@ in
           };
           options.password = mkOption {
             type = with types; nullOr str;
-            description = ''
+            description = lib.mdDoc ''
               The password used to authenticate the XMPP component to your XMPP server.
               This password must be configured in the XMPP server,
               associated with the external component on
-              <link linkend="opt-services.biboumi.settings.hostname">hostname</link>.
+              [hostname](#opt-services.biboumi.settings.hostname).
 
-              Set it to null and use <link linkend="opt-services.biboumi.credentialsFile">credentialsFile</link>
+              Set it to null and use [credentialsFile](#opt-services.biboumi.credentialsFile)
               if you do not want this password to go into the Nix store.
             '';
           };
@@ -155,12 +155,12 @@ in
 
       credentialsFile = mkOption {
         type = types.path;
-        description = ''
+        description = lib.mdDoc ''
           Path to a configuration file to be merged with the settings.
           Beware not to surround "=" with spaces when setting biboumi's options in this file.
           Useful to merge a file which is better kept out of the Nix store
           because it contains sensible data like
-          <link linkend="opt-services.biboumi.settings.password">password</link>.
+          [password](#opt-services.biboumi.settings.password).
         '';
         default = "/dev/null";
         example = "/run/keys/biboumi.cfg";
diff --git a/nixos/modules/services/networking/bird-lg.nix b/nixos/modules/services/networking/bird-lg.nix
index db4a4140dd406..1440deb62b441 100644
--- a/nixos/modules/services/networking/bird-lg.nix
+++ b/nixos/modules/services/networking/bird-lg.nix
@@ -136,9 +136,9 @@ in
         extraArgs = mkOption {
           type = types.lines;
           default = "";
-          description = "
-            Extra parameters documented <link xlink:href=\"https://github.com/xddxdd/bird-lg-go#frontend\">here</link>.
-          ";
+          description = lib.mdDoc ''
+            Extra parameters documented [here](https://github.com/xddxdd/bird-lg-go#frontend).
+          '';
         };
       };
 
@@ -183,9 +183,9 @@ in
         extraArgs = mkOption {
           type = types.lines;
           default = "";
-          description = "
-            Extra parameters documented <link xlink:href=\"https://github.com/xddxdd/bird-lg-go#proxy\">here</link>.
-          ";
+          description = lib.mdDoc ''
+            Extra parameters documented [here](https://github.com/xddxdd/bird-lg-go#proxy).
+          '';
         };
       };
     };
diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix
index d409f06022897..7708aaa476f6d 100644
--- a/nixos/modules/services/networking/bird.nix
+++ b/nixos/modules/services/networking/bird.nix
@@ -13,18 +13,18 @@ in
       enable = mkEnableOption "BIRD Internet Routing Daemon";
       config = mkOption {
         type = types.lines;
-        description = ''
+        description = lib.mdDoc ''
           BIRD Internet Routing Daemon configuration file.
-          <link xlink:href='http://bird.network.cz/'/>
+          <http://bird.network.cz/>
         '';
       };
       checkConfig = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether the config should be checked at build time.
           When the config can't be checked during build time, for example when it includes
-          other files, either disable this option or use <code>preCheckConfig</code> to create
+          other files, either disable this option or use `preCheckConfig` to create
           the included files before checking.
         '';
       };
@@ -34,9 +34,9 @@ in
         example = ''
           echo "cost 100;" > include.conf
         '';
-        description = ''
+        description = lib.mdDoc ''
           Commands to execute before the config file check. The file to be checked will be
-          available as <code>bird2.conf</code> in the current directory.
+          available as `bird2.conf` in the current directory.
 
           Files created with this option will not be available at service runtime, only during
           build time checking.
diff --git a/nixos/modules/services/networking/coredns.nix b/nixos/modules/services/networking/coredns.nix
index 9a4140e9d58a8..deaba69e99fa2 100644
--- a/nixos/modules/services/networking/coredns.nix
+++ b/nixos/modules/services/networking/coredns.nix
@@ -17,7 +17,10 @@ in {
         }
       '';
       type = types.lines;
-      description = "Verbatim Corefile to use. See <link xlink:href=\"https://coredns.io/manual/toc/#configuration\"/> for details.";
+      description = lib.mdDoc ''
+        Verbatim Corefile to use.
+        See <https://coredns.io/manual/toc/#configuration> for details.
+      '';
     };
 
     package = mkOption {
diff --git a/nixos/modules/services/networking/ghostunnel.nix b/nixos/modules/services/networking/ghostunnel.nix
index 6cac6a69b0679..79cf80e57bef1 100644
--- a/nixos/modules/services/networking/ghostunnel.nix
+++ b/nixos/modules/services/networking/ghostunnel.nix
@@ -40,37 +40,37 @@ let
           description = ''
             Path to keystore (combined PEM with cert/key, or PKCS12 keystore).
 
-            NB: storepass is not supported because it would expose credentials via <code>/proc/*/cmdline</code>.
+            NB: storepass is not supported because it would expose credentials via <literal>/proc/*/cmdline</literal>.
 
-            Specify this or <code>cert</code> and <code>key</code>.
+            Specify this or <literal>cert</literal> and <literal>key</literal>.
           '';
           type = types.nullOr types.str;
           default = null;
         };
 
         cert = mkOption {
-          description = ''
+          description = lib.mdDoc ''
             Path to certificate (PEM with certificate chain).
 
-            Not required if <code>keystore</code> is set.
+            Not required if `keystore` is set.
           '';
           type = types.nullOr types.str;
           default = null;
         };
 
         key = mkOption {
-          description = ''
+          description = lib.mdDoc ''
             Path to certificate private key (PEM with private key).
 
-            Not required if <code>keystore</code> is set.
+            Not required if `keystore` is set.
           '';
           type = types.nullOr types.str;
           default = null;
         };
 
         cacert = mkOption {
-          description = ''
-            Path to CA bundle file (PEM/X509). Uses system trust store if <code>null</code>.
+          description = lib.mdDoc ''
+            Path to CA bundle file (PEM/X509). Uses system trust store if `null`.
           '';
           type = types.nullOr types.str;
         };
@@ -124,7 +124,7 @@ let
         };
 
         extraArguments = mkOption {
-          description = "Extra arguments to pass to <code>ghostunnel server</code>";
+          description = lib.mdDoc "Extra arguments to pass to `ghostunnel server`";
           type = types.separatedString " ";
           default = "";
         };
diff --git a/nixos/modules/services/networking/hans.nix b/nixos/modules/services/networking/hans.nix
index f74d602be933c..ffb2ee841c64d 100644
--- a/nixos/modules/services/networking/hans.nix
+++ b/nixos/modules/services/networking/hans.nix
@@ -19,12 +19,12 @@ in
     services.hans = {
       clients = mkOption {
         default = {};
-        description = ''
+        description = lib.mdDoc ''
           Each attribute of this option defines a systemd service that
           runs hans. Many or none may be defined.
           The name of each service is
-          <literal>hans-<replaceable>name</replaceable></literal>
-          where <replaceable>name</replaceable> is the name of the
+          `hans-«name»`
+          where «name» is the name of the
           corresponding attribute name.
         '';
         example = literalExpression ''
diff --git a/nixos/modules/services/networking/iodine.nix b/nixos/modules/services/networking/iodine.nix
index c24f118ce898d..ea2fa3ac4be4d 100644
--- a/nixos/modules/services/networking/iodine.nix
+++ b/nixos/modules/services/networking/iodine.nix
@@ -28,12 +28,12 @@ in
     services.iodine = {
       clients = mkOption {
         default = {};
-        description = ''
+        description = lib.mdDoc ''
           Each attribute of this option defines a systemd service that
           runs iodine. Many or none may be defined.
           The name of each service is
-          <literal>iodine-<replaceable>name</replaceable></literal>
-          where <replaceable>name</replaceable> is the name of the
+          `iodine-«name»`
+          where «name» is the name of the
           corresponding attribute name.
         '';
         example = literalExpression ''
diff --git a/nixos/modules/services/networking/kea.nix b/nixos/modules/services/networking/kea.nix
index d9d6e3f42ceb3..d674a97391c92 100644
--- a/nixos/modules/services/networking/kea.nix
+++ b/nixos/modules/services/networking/kea.nix
@@ -54,11 +54,11 @@ in
           configFile = mkOption {
             type = nullOr path;
             default = null;
-            description = ''
-              Kea Control Agent configuration as a path, see <link xlink:href="https://kea.readthedocs.io/en/kea-${package.version}/arm/agent.html"/>.
+            description = lib.mdDoc ''
+              Kea Control Agent configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/agent.html>.
 
-              Takes preference over <link linkend="opt-services.kea.ctrl-agent.settings">settings</link>.
-              Most users should prefer using <link linkend="opt-services.kea.ctrl-agent.settings">settings</link> instead.
+              Takes preference over [settings](#opt-services.kea.ctrl-agent.settings).
+              Most users should prefer using [settings](#opt-services.kea.ctrl-agent.settings) instead.
             '';
           };
 
@@ -93,11 +93,11 @@ in
           configFile = mkOption {
             type = nullOr path;
             default = null;
-            description = ''
-              Kea DHCP4 configuration as a path, see <link xlink:href="https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp4-srv.html"/>.
+            description = lib.mdDoc ''
+              Kea DHCP4 configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp4-srv.html>.
 
-              Takes preference over <link linkend="opt-services.kea.dhcp4.settings">settings</link>.
-              Most users should prefer using <link linkend="opt-services.kea.dhcp4.settings">settings</link> instead.
+              Takes preference over [settings](#opt-services.kea.dhcp4.settings).
+              Most users should prefer using [settings](#opt-services.kea.dhcp4.settings) instead.
             '';
           };
 
@@ -153,11 +153,11 @@ in
           configFile = mkOption {
             type = nullOr path;
             default = null;
-            description = ''
-              Kea DHCP6 configuration as a path, see <link xlink:href="https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp6-srv.html"/>.
+            description = lib.mdDoc ''
+              Kea DHCP6 configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp6-srv.html>.
 
-              Takes preference over <link linkend="opt-services.kea.dhcp6.settings">settings</link>.
-              Most users should prefer using <link linkend="opt-services.kea.dhcp6.settings">settings</link> instead.
+              Takes preference over [settings](#opt-services.kea.dhcp6.settings).
+              Most users should prefer using [settings](#opt-services.kea.dhcp6.settings) instead.
             '';
           };
 
@@ -214,11 +214,11 @@ in
           configFile = mkOption {
             type = nullOr path;
             default = null;
-            description = ''
-              Kea DHCP-DDNS configuration as a path, see <link xlink:href="https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html"/>.
+            description = lib.mdDoc ''
+              Kea DHCP-DDNS configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html>.
 
-              Takes preference over <link linkend="opt-services.kea.dhcp-ddns.settings">settings</link>.
-              Most users should prefer using <link linkend="opt-services.kea.dhcp-ddns.settings">settings</link> instead.
+              Takes preference over [settings](#opt-services.kea.dhcp-ddns.settings).
+              Most users should prefer using [settings](#opt-services.kea.dhcp-ddns.settings) instead.
             '';
           };
 
diff --git a/nixos/modules/services/networking/ncdns.nix b/nixos/modules/services/networking/ncdns.nix
index 3527b9e185757..958231963c68e 100644
--- a/nixos/modules/services/networking/ncdns.nix
+++ b/nixos/modules/services/networking/ncdns.nix
@@ -176,10 +176,10 @@ in
             certstore.nssdbdir = "../../home/alice/.pki/nssdb";
           }
         '';
-        description = ''
+        description = lib.mdDoc ''
           ncdns settings. Use this option to configure ncds
           settings not exposed in a NixOS option or to bypass one.
-          See the example ncdns.conf file at <link xlink:href="https://github.com/namecoin/ncdns/blob/master/_doc/ncdns.conf.example"/>
+          See the example ncdns.conf file at <https://github.com/namecoin/ncdns/blob/master/_doc/ncdns.conf.example>
           for the available options.
         '';
       };
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index 7abdf16b15346..e77fa97d240e5 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -329,8 +329,7 @@ in {
         default = "default";
         description = ''
           Set the DNS (<literal>resolv.conf</literal>) processing mode.
-          </para>
-          <para>
+
           A description of these modes can be found in the main section of
           <link xlink:href="https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html">
             https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html
@@ -388,12 +387,12 @@ in {
       enableStrongSwan = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Enable the StrongSwan plugin.
-          </para><para>
+
           If you enable this option the
-          <literal>networkmanager_strongswan</literal> plugin will be added to
-          the <option>networking.networkmanager.plugins</option> option
+          `networkmanager_strongswan` plugin will be added to
+          the {option}`networking.networkmanager.plugins` option
           so you don't need to to that yourself.
         '';
       };
diff --git a/nixos/modules/services/networking/nntp-proxy.nix b/nixos/modules/services/networking/nntp-proxy.nix
index 618ed0a93f1df..4dd2922e83f12 100644
--- a/nixos/modules/services/networking/nntp-proxy.nix
+++ b/nixos/modules/services/networking/nntp-proxy.nix
@@ -167,9 +167,9 @@ in
             passwordHash = mkOption {
               type = types.str;
               example = "$6$GtzE7FrpE$wwuVgFYU.TZH4Rz.Snjxk9XGua89IeVwPQ/fEUD8eujr40q5Y021yhn0aNcsQ2Ifw.BLclyzvzgegopgKcneL0";
-              description = ''
+              description = lib.mdDoc ''
                 SHA-512 password hash (can be generated by
-                <code>mkpasswd -m sha-512 &lt;password&gt;</code>)
+                `mkpasswd -m sha-512 <password>`)
               '';
             };
 
diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix
index 1102fc85d40a9..cf2afcacc5281 100644
--- a/nixos/modules/services/networking/nsd.nix
+++ b/nixos/modules/services/networking/nsd.nix
@@ -392,8 +392,8 @@ let
       requestXFR = mkOption {
         type = types.listOf types.str;
         default = [];
-        description = ''
-          Format: <code>[AXFR|UDP] &lt;ip-address&gt; &lt;key-name | NOKEY&gt;</code>
+        description = lib.mdDoc ''
+          Format: `[AXFR|UDP] <ip-address> <key-name | NOKEY>`
         '';
       };
 
diff --git a/nixos/modules/services/networking/ntp/ntpd.nix b/nixos/modules/services/networking/ntp/ntpd.nix
index 47922f5e1499b..a9dae2c8667aa 100644
--- a/nixos/modules/services/networking/ntp/ntpd.nix
+++ b/nixos/modules/services/networking/ntp/ntpd.nix
@@ -40,21 +40,19 @@ in
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to synchronise your machine's time using ntpd, as a peer in
           the NTP network.
-          </para>
-          <para>
-          Disables <literal>systemd.timesyncd</literal> if enabled.
+
+          Disables `systemd.timesyncd` if enabled.
         '';
       };
 
       restrictDefault = mkOption {
         type = types.listOf types.str;
-        description = ''
+        description = lib.mdDoc ''
           The restriction flags to be set by default.
-          </para>
-          <para>
+
           The default flags prevent external hosts from using ntpd as a DDoS
           reflector, setting system time, and querying OS/ntpd version. As
           recommended in section 6.5.1.1.3, answer "No" of
@@ -65,10 +63,9 @@ in
 
       restrictSource = mkOption {
         type = types.listOf types.str;
-        description = ''
+        description = lib.mdDoc ''
           The restriction flags to be set on source.
-          </para>
-          <para>
+
           The default flags allow peers to be added by ntpd from configured
           pool(s), but not by other means.
         '';
diff --git a/nixos/modules/services/networking/openconnect.nix b/nixos/modules/services/networking/openconnect.nix
index c5313bb305a2d..469f0a3bc3bb6 100644
--- a/nixos/modules/services/networking/openconnect.nix
+++ b/nixos/modules/services/networking/openconnect.nix
@@ -38,10 +38,10 @@ let
       # set an authentication cookie, because they have to be requested
       # for every new connection and would only work once.
       passwordFile = mkOption {
-        description = ''
+        description = lib.mdDoc ''
           File containing the password to authenticate with. This
-          is passed to <code>openconnect</code> via the
-          <code>--passwd-on-stdin</code> option.
+          is passed to `openconnect` via the
+          `--passwd-on-stdin` option.
         '';
         default = null;
         example = "/var/lib/secrets/openconnect-passwd";
@@ -63,13 +63,13 @@ let
       };
 
       extraOptions = mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Extra config to be appended to the interface config. It should
           contain long-format options as would be accepted on the command
-          line by <code>openconnect</code>
+          line by `openconnect`
           (see https://www.infradead.org/openconnect/manual.html).
-          Non-key-value options like <code>deflate</code> can be used by
-          declaring them as booleans, i. e. <code>deflate = true;</code>.
+          Non-key-value options like `deflate` can be used by
+          declaring them as booleans, i. e. `deflate = true;`.
         '';
         default = { };
         example = {
diff --git a/nixos/modules/services/networking/openvpn.nix b/nixos/modules/services/networking/openvpn.nix
index 752b4d67d47e6..492a0936fdbb6 100644
--- a/nixos/modules/services/networking/openvpn.nix
+++ b/nixos/modules/services/networking/openvpn.nix
@@ -115,12 +115,12 @@ in
         }
       '';
 
-      description = ''
+      description = lib.mdDoc ''
         Each attribute of this option defines a systemd service that
         runs an OpenVPN instance.  These can be OpenVPN servers or
         clients.  The name of each systemd service is
-        <literal>openvpn-<replaceable>name</replaceable>.service</literal>,
-        where <replaceable>name</replaceable> is the corresponding
+        `openvpn-«name».service`,
+        where «name» is the corresponding
         attribute name.
       '';
 
diff --git a/nixos/modules/services/networking/pleroma.nix b/nixos/modules/services/networking/pleroma.nix
index 03868c8cc7694..de9d0821c63af 100644
--- a/nixos/modules/services/networking/pleroma.nix
+++ b/nixos/modules/services/networking/pleroma.nix
@@ -34,7 +34,7 @@ in {
 
       configs = mkOption {
         type = with types; listOf str;
-        description = ''
+        description = lib.mdDoc ''
           Pleroma public configuration.
 
           This list gets appended from left to
@@ -42,9 +42,9 @@ in {
           configuration imperatively, meaning you can override a
           setting by appending a new str to this NixOS option list.
 
-          <emphasis>DO NOT STORE ANY PLEROMA SECRET
-          HERE</emphasis>, use
-          <link linkend="opt-services.pleroma.secretConfigFile">services.pleroma.secretConfigFile</link>
+          *DO NOT STORE ANY PLEROMA SECRET
+          HERE*, use
+          [services.pleroma.secretConfigFile](#opt-services.pleroma.secretConfigFile)
           instead.
 
           This setting is going to be stored in a file part of
diff --git a/nixos/modules/services/networking/seafile.nix b/nixos/modules/services/networking/seafile.nix
index 7cda71458dd1b..d9617952ea59f 100644
--- a/nixos/modules/services/networking/seafile.nix
+++ b/nixos/modules/services/networking/seafile.nix
@@ -133,7 +133,7 @@ in {
       type = types.lines;
       description = ''
         Extra config to append to `seahub_settings.py` file.
-        Refer to <link xlink:href="https://manual.seafile.com/config/seahub_settings_py/" />
+        Refer to <link xlink:href="https://manual.seafile.com/config/seahub_settings_py/"/>
         for all available options.
       '';
     };
diff --git a/nixos/modules/services/networking/smokeping.nix b/nixos/modules/services/networking/smokeping.nix
index 217c16c8f37be..7f1abcc6824fd 100644
--- a/nixos/modules/services/networking/smokeping.nix
+++ b/nixos/modules/services/networking/smokeping.nix
@@ -156,7 +156,7 @@ in
       owner = mkOption {
         type = types.str;
         default = "nobody";
-        example = "Joe Admin";
+        example = "Bob Foobawr";
         description = lib.mdDoc "Real name of the owner of the instance";
       };
       ownerEmail = mkOption {
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index c6386ed6823df..6da83eb7de10a 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -257,12 +257,12 @@ in
       authorizedKeysFiles = mkOption {
         type = types.listOf types.str;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           Specify the rules for which files to read on the host.
 
           This is an advanced option. If you're looking to configure user
-          keys, you can generally use <xref linkend="opt-users.users._name_.openssh.authorizedKeys.keys"/>
-          or <xref linkend="opt-users.users._name_.openssh.authorizedKeys.keyFiles"/>.
+          keys, you can generally use [](#opt-users.users._name_.openssh.authorizedKeys.keys)
+          or [](#opt-users.users._name_.openssh.authorizedKeys.keyFiles).
 
           These are paths relative to the host root file system or home
           directories and they are subject to certain token expansion rules.
@@ -298,14 +298,13 @@ in
           "curve25519-sha256@libssh.org"
           "diffie-hellman-group-exchange-sha256"
         ];
-        description = ''
+        description = lib.mdDoc ''
           Allowed key exchange algorithms
-          </para>
-          <para>
+
           Uses the lower bound recommended in both
-          <link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
+          <https://stribika.github.io/2015/01/04/secure-secure-shell.html>
           and
-          <link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" />
+          <https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67>
         '';
       };
 
@@ -319,14 +318,13 @@ in
           "aes192-ctr"
           "aes128-ctr"
         ];
-        description = ''
+        description = lib.mdDoc ''
           Allowed ciphers
-          </para>
-          <para>
+
           Defaults to recommended settings from both
-          <link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
+          <https://stribika.github.io/2015/01/04/secure-secure-shell.html>
           and
-          <link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" />
+          <https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67>
         '';
       };
 
@@ -340,14 +338,13 @@ in
           "hmac-sha2-256"
           "umac-128@openssh.com"
         ];
-        description = ''
+        description = lib.mdDoc ''
           Allowed MACs
-          </para>
-          <para>
+
           Defaults to recommended settings from both
-          <link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
+          <https://stribika.github.io/2015/01/04/secure-secure-shell.html>
           and
-          <link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" />
+          <https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67>
         '';
       };
 
diff --git a/nixos/modules/services/networking/strongswan-swanctl/param-constructors.nix b/nixos/modules/services/networking/strongswan-swanctl/param-constructors.nix
index dfdfc50d8ae23..d5a8daf98ec6f 100644
--- a/nixos/modules/services/networking/strongswan-swanctl/param-constructors.nix
+++ b/nixos/modules/services/networking/strongswan-swanctl/param-constructors.nix
@@ -59,7 +59,8 @@ rec {
     if strongswanDefault == null
     then description
     else description + ''
-      </para><para>
+
+
       StrongSwan default: <literal><![CDATA[${builtins.toJSON strongswanDefault}]]></literal>
     '';
 
diff --git a/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix b/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix
index cca61b9ce930e..737d0331f1951 100644
--- a/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix
+++ b/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix
@@ -15,14 +15,14 @@ let
     file = mkOptionalStrParam ''
       Absolute path to the certificate to load. Passed as-is to the daemon, so
       it must be readable by it.
-      </para><para>
+
       Configure either this or <option>handle</option>, but not both, in one section.
     '';
 
     handle = mkOptionalHexParam ''
       Hex-encoded CKA_ID or handle of the certificate on a token or TPM,
       respectively.
-      </para><para>
+
       Configure either this or <option>file</option>, but not both, in one section.
     '';
 
@@ -40,7 +40,7 @@ in {
     cacert = mkOptionalStrParam ''
       The certificates may use a relative path from the swanctl
       <literal>x509ca</literal> directory or an absolute path.
-      </para><para>
+
       Configure one of <option>cacert</option>,
       <option>file</option>, or
       <option>handle</option> per section.
@@ -82,11 +82,11 @@ in {
     local_addrs	= mkCommaSepListParam [] ''
       Local address(es) to use for IKE communication. Takes
       single IPv4/IPv6 addresses, DNS names, CIDR subnets or IP address ranges.
-      </para><para>
+
       As initiator, the first non-range/non-subnet is used to initiate the
       connection from. As responder, the local destination address must match at
       least to one of the specified addresses, subnets or ranges.
-      </para><para>
+
       If FQDNs are assigned they are resolved every time a configuration lookup
       is done. If DNS resolution times out, the lookup is delayed for that time.
     '';
@@ -94,11 +94,11 @@ in {
     remote_addrs = mkCommaSepListParam [] ''
       Remote address(es) to use for IKE communication. Takes
       single IPv4/IPv6 addresses, DNS names, CIDR subnets or IP address ranges.
-      </para><para>
+
       As initiator, the first non-range/non-subnet is used to initiate the
       connection to. As responder, the initiator source address must match at
       least to one of the specified addresses, subnets or ranges.
-      </para><para>
+
       If FQDNs are assigned they are resolved every time a configuration lookup
       is done. If DNS resolution times out, the lookup is delayed for that time.
       To initiate a connection, at least one specific address or DNS name must
@@ -110,7 +110,7 @@ in {
       backend is used, which is usually <literal>500</literal>. If port
       <literal>500</literal> is used, automatic IKE port floating to port
       <literal>4500</literal> is used to work around NAT issues.
-      </para><para>
+
       Using a non-default local IKE port requires support from the socket
       backend in use (socket-dynamic).
     '';
@@ -126,13 +126,13 @@ in {
       for IKE an encryption algorithm, an integrity algorithm, a pseudo random
       function and a Diffie-Hellman group. For AEAD algorithms, instead of
       encryption and integrity algorithms, a combined algorithm is used.
-      </para><para>
+
       In IKEv2, multiple algorithms of the same kind can be specified in a
       single proposal, from which one gets selected. In IKEv1, only one
       algorithm per kind is allowed per proposal, more algorithms get implicitly
       stripped. Use multiple proposals to offer different algorithms
       combinations in IKEv1.
-      </para><para>
+
       Algorithm keywords get separated using dashes. Multiple proposals may be
       specified in a list. The special value <literal>default</literal> forms a
       default proposal of supported algorithms considered safe, and is usually a
@@ -159,7 +159,7 @@ in {
       If the default of yes is used, Mode Config works in pull mode, where the
       initiator actively requests a virtual IP. With no, push mode is used,
       where the responder pushes down a virtual IP to the initiating peer.
-      </para><para>
+
       Push mode is currently supported for IKEv1, but not in IKEv2. It is used
       by a few implementations only, pull mode is recommended.
     '';
@@ -174,7 +174,7 @@ in {
       To enforce UDP encapsulation of ESP packets, the IKE daemon can fake the
       NAT detection payloads. This makes the peer believe that NAT takes place
       on the path, forcing it to encapsulate ESP packets in UDP.
-      </para><para>
+
       Usually this is not required, but it can help to work around connectivity
       issues with too restrictive intermediary firewalls.
     '';
@@ -183,7 +183,7 @@ in {
       Enables MOBIKE on IKEv2 connections. MOBIKE is enabled by default on IKEv2
       connections, and allows mobility of clients and multi-homing on servers by
       migrating active IPsec tunnels.
-      </para><para>
+
       Usually keeping MOBIKE enabled is unproblematic, as it is not used if the
       peer does not indicate support for it. However, due to the design of
       MOBIKE, IKEv2 always floats to port 4500 starting from the second
@@ -222,7 +222,7 @@ in {
       <listitem><para>Finally, setting the option to <literal>no</literal> will disable announcing
       support for this feature.</para></listitem>
       </itemizedlist>
-      </para><para>
+
       Note that fragmented IKE messages sent by a peer are always processed
       irrespective of the value of this option (even when set to no).
     '';
@@ -284,7 +284,7 @@ in {
     unique = mkEnumParam ["no" "never" "keep" "replace"] "no" ''
       Connection uniqueness policy to enforce. To avoid multiple connections
       from the same user, a uniqueness policy can be enforced.
-      </para><para>
+
       <itemizedlist>
       <listitem><para>
       The value <literal>never</literal> does never enforce such a policy, even
@@ -306,7 +306,7 @@ in {
       To compare connections for uniqueness, the remote IKE identity is used. If
       EAP or XAuth authentication is involved, the EAP-Identity or XAuth
       username is used to enforce the uniqueness policy instead.
-      </para><para>
+
       On initiators this setting specifies whether an INITIAL_CONTACT notify is
       sent during IKE_AUTH if no existing connection is found with the remote
       peer (determined by the identities of the first authentication
@@ -320,7 +320,7 @@ in {
       possible to actively reauthenticate as responder. The IKEv2
       reauthentication lifetime negotiation can instruct the client to perform
       reauthentication.
-      </para><para>
+
       Reauthentication is disabled by default. Enabling it usually may lead to
       small connection interruptions, as strongSwan uses a break-before-make
       policy with IKEv2 to avoid any conflicts with associated tunnel resources.
@@ -330,7 +330,7 @@ in {
       IKE rekeying refreshes key material using a Diffie-Hellman exchange, but
       does not re-check associated credentials. It is supported in IKEv2 only,
       IKEv1 performs a reauthentication procedure instead.
-      </para><para>
+
       With the default value IKE rekeying is scheduled every 4 hours, minus the
       configured rand_time. If a reauth_time is configured, rekey_time defaults
       to zero, disabling rekeying; explicitly set both to enforce rekeying and
@@ -343,10 +343,10 @@ in {
       perpetually, a maximum hard lifetime may be specified. If the IKE_SA fails
       to rekey or reauthenticate within the specified time, the IKE_SA gets
       closed.
-      </para><para>
+
       In contrast to CHILD_SA rekeying, over_time is relative in time to the
       rekey_time and reauth_time values, as it applies to both.
-      </para><para>
+
       The default is 10% of the longer of <option>rekey_time</option> and
       <option>reauth_time</option>.
     '';
@@ -356,7 +356,7 @@ in {
       rekey/reauth times. To avoid having both peers initiating the rekey/reauth
       procedure simultaneously, a random time gets subtracted from the
       rekey/reauth times.
-      </para><para>
+
       The default is equal to the configured <option>over_time</option>.
     '';
 
@@ -410,7 +410,7 @@ in {
         List of certificate candidates to use for
         authentication. The certificates may use a relative path from the
         swanctl <literal>x509</literal> directory or an absolute path.
-        </para><para>
+
         The certificate used for authentication is selected based on the
         received certificate request payloads. If no appropriate CA can be
         located, the first certificate is used.
@@ -426,7 +426,7 @@ in {
         List of raw public key candidates to use for
         authentication. The public keys may use a relative path from the swanctl
         <literal>pubkey</literal> directory or an absolute path.
-        </para><para>
+
         Even though multiple local public keys could be defined in principle,
         only the first public key in the list is used for authentication.
       '';
@@ -504,7 +504,7 @@ in {
         authentication. This identity may differ from the IKE identity,
         especially when EAP authentication is delegated from the IKE responder
         to an AAA backend.
-        </para><para>
+
         For EAP-(T)TLS, this defines the identity for which the server must
         provide a certificate in the TLS exchange.
       '';
@@ -518,7 +518,7 @@ in {
       defines the rules how authentication is performed for the local
       peer. Multiple rounds may be defined to use IKEv2 RFC 4739 Multiple
       Authentication or IKEv1 XAuth.
-      </para><para>
+
       Each round is defined in a section having <literal>local</literal> as
       prefix, and an optional unique suffix. To define a single authentication
       round, the suffix may be omitted.
@@ -620,7 +620,7 @@ in {
         Authentication to expect from remote. See the <option>local</option>
         section's <option>auth</option> keyword description about the details of
         supported mechanisms.
-        </para><para>
+
         Since 5.4.0, to require a trustchain public key strength for the remote
         side, specify the key type followed by the minimum strength in bits (for
         example <literal>ecdsa-384</literal> or
@@ -641,7 +641,7 @@ in {
         <literal>pubkey</literal> or <literal>rsa</literal> constraints are
         configured RSASSA-PSS signatures will only be accepted if enabled in
         <literal>strongswan.conf</literal>(5).
-        </para><para>
+
         To specify trust chain constraints for EAP-(T)TLS, append a colon to the
         EAP method, followed by the key type/size and hash algorithm as
         discussed above (e.g. <literal>eap-tls:ecdsa-384-sha384</literal>).
@@ -652,7 +652,7 @@ in {
       defines the constraints how the peers must authenticate to use this
       connection. Multiple rounds may be defined to use IKEv2 RFC 4739 Multiple
       Authentication or IKEv1 XAuth.
-      </para><para>
+
       Each round is defined in a section having <literal>remote</literal> as
       prefix, and an optional unique suffix. To define a single authentication
       round, the suffix may be omitted.
@@ -665,13 +665,13 @@ in {
         Diffie-Hellman group. If a DH group is specified, CHILD_SA/Quick Mode
         rekeying and initial negotiation uses a separate Diffie-Hellman exchange
         using the specified group (refer to esp_proposals for details).
-        </para><para>
+
         In IKEv2, multiple algorithms of the same kind can be specified in a
         single proposal, from which one gets selected. In IKEv1, only one
         algorithm per kind is allowed per proposal, more algorithms get
         implicitly stripped. Use multiple proposals to offer different algorithms
         combinations in IKEv1.
-        </para><para>
+
         Algorithm keywords get separated using dashes. Multiple proposals may be
         specified in a list. The special value <literal>default</literal> forms
         a default proposal of supported algorithms considered safe, and is
@@ -686,7 +686,7 @@ in {
         an optional Extended Sequence Number Mode indicator. For AEAD proposals,
         a combined mode algorithm is used instead of the separate
         encryption/integrity algorithms.
-        </para><para>
+
         If a DH group is specified, CHILD_SA/Quick Mode rekeying and initial
         negotiation use a separate Diffie-Hellman exchange using the specified
         group. However, for IKEv2, the keys of the CHILD_SA created implicitly
@@ -695,18 +695,18 @@ in {
         rekeyed or is created with a separate CREATE_CHILD_SA exchange. A
         proposal mismatch might, therefore, not immediately be noticed when the
         SA is established, but may later cause rekeying to fail.
-        </para><para>
+
         Extended Sequence Number support may be indicated with the
         <literal>esn</literal> and <literal>noesn</literal> values, both may be
         included to indicate support for both modes. If omitted,
         <literal>noesn</literal> is assumed.
-        </para><para>
+
         In IKEv2, multiple algorithms of the same kind can be specified in a
         single proposal, from which one gets selected. In IKEv1, only one
         algorithm per kind is allowed per proposal, more algorithms get
         implicitly stripped. Use multiple proposals to offer different algorithms
         combinations in IKEv1.
-        </para><para>
+
         Algorithm keywords get separated using dashes. Multiple proposals may be
         specified as a list. The special value <literal>default</literal> forms
         a default proposal of supported algorithms considered safe, and is
@@ -729,7 +729,7 @@ in {
         selector. The special value <literal>dynamic</literal> may be used
         instead of a subnet definition, which gets replaced by the tunnel outer
         address or the virtual IP, if negotiated. This is the default.
-        </para><para>
+
         A protocol/port selector is surrounded by opening and closing square
         brackets. Between these brackets, a numeric or getservent(3) protocol
         name may be specified. After the optional protocol restriction, an
@@ -738,7 +738,7 @@ in {
         special value <literal>opaque</literal> for RFC 4301 OPAQUE
         selectors. Port ranges may be specified as well, none of the kernel
         backends currently support port ranges, though.
-        </para><para>
+
         When IKEv1 is used only the first selector is interpreted, except if the
         Cisco Unity extension plugin is used. This is due to a limitation of the
         IKEv1 protocol, which only allows a single pair of selectors per
@@ -761,7 +761,7 @@ in {
         specified in the proposal.  To avoid rekey collisions initiated by both
         ends simultaneously, a value in the range of <option>rand_time</option>
         gets subtracted to form the effective soft lifetime.
-        </para><para>
+
         By default CHILD_SA rekeying is scheduled every hour, minus
         <option>rand_time</option>.
       '';
@@ -783,11 +783,11 @@ in {
         Number of bytes processed before initiating CHILD_SA rekeying. CHILD_SA
         rekeying refreshes key material, optionally using a Diffie-Hellman
         exchange if a group is specified in the proposal.
-        </para><para>
+
         To avoid rekey collisions initiated by both ends simultaneously, a value
         in the range of <option>rand_bytes</option> gets subtracted to form the
         effective soft volume limit.
-        </para><para>
+
         Volume based CHILD_SA rekeying is disabled by default.
       '';
 
@@ -808,11 +808,11 @@ in {
         Number of packets processed before initiating CHILD_SA rekeying. CHILD_SA
         rekeying refreshes key material, optionally using a Diffie-Hellman
         exchange if a group is specified in the proposal.
-        </para><para>
+
         To avoid rekey collisions initiated by both ends simultaneously, a value
         in the range of <option>rand_packets</option> gets subtracted to form
         the effective soft packet count limit.
-        </para><para>
+
         Packet count based CHILD_SA rekeying is disabled by default.
       '';
 
@@ -821,7 +821,7 @@ in {
         this hard packets limit is never reached, because the CHILD_SA gets
         rekeyed before. If that fails for whatever reason, this limit closes the
         CHILD_SA.
-        </para><para>
+
         The default is 10% more than <option>rekey_bytes</option>.
       '';
 
@@ -936,7 +936,7 @@ in {
         <literal>%unique</literal> sets a unique mark on each CHILD_SA instance,
         beyond that the value <literal>%unique-dir</literal> assigns a different
         unique mark for each
-        </para><para>
+
         An additional mask may be appended to the mark, separated by
         <literal>/</literal>. The default mask if omitted is
         <literal>0xffffffff</literal>.
@@ -960,7 +960,7 @@ in {
         value <literal>%unique</literal> sets a unique mark on each CHILD_SA
         instance, beyond that the value <literal>%unique-dir</literal> assigns a
         different unique mark for each CHILD_SA direction (in/out).
-        </para><para>
+
         An additional mask may be appended to the mark, separated by
         <literal>/</literal>. The default mask if omitted is
         <literal>0xffffffff</literal>.
@@ -1102,7 +1102,7 @@ in {
         <literal>start</literal> tries to re-create the CHILD_SA.
         </para></listitem>
         </itemizedlist>
-        </para><para>
+
         <option>close_action</option> does not provide any guarantee that the
         CHILD_SA is kept alive. It acts on explicit close messages only, but not
         on negotiation failures. Use trap policies to reliably re-create failed
diff --git a/nixos/modules/services/networking/wireguard.nix b/nixos/modules/services/networking/wireguard.nix
index 412e9c921f52e..9017c53f4e562 100644
--- a/nixos/modules/services/networking/wireguard.nix
+++ b/nixos/modules/services/networking/wireguard.nix
@@ -118,12 +118,11 @@ let
         default = null;
         type = with types; nullOr str;
         example = "container";
-        description = ''The pre-existing network namespace in which the
+        description = lib.mdDoc ''The pre-existing network namespace in which the
         WireGuard interface is created, and which retains the socket even if the
-        interface is moved via <option>interfaceNamespace</option>. When
-        <literal>null</literal>, the interface is created in the init namespace.
-        See <link
-        xlink:href="https://www.wireguard.com/netns/">documentation</link>.
+        interface is moved via {option}`interfaceNamespace`. When
+        `null`, the interface is created in the init namespace.
+        See [documentation](https://www.wireguard.com/netns/).
         '';
       };
 
@@ -131,12 +130,11 @@ let
         default = null;
         type = with types; nullOr str;
         example = "init";
-        description = ''The pre-existing network namespace the WireGuard
-        interface is moved to. The special value <literal>init</literal> means
-        the init namespace. When <literal>null</literal>, the interface is not
+        description = lib.mdDoc ''The pre-existing network namespace the WireGuard
+        interface is moved to. The special value `init` means
+        the init namespace. When `null`, the interface is not
         moved.
-        See <link
-        xlink:href="https://www.wireguard.com/netns/">documentation</link>.
+        See [documentation](https://www.wireguard.com/netns/).
         '';
       };
     };
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index e21c25e2f78f8..ac5f597b4752d 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -190,7 +190,7 @@ in {
         description = ''
           Whether to allow configuring networks "imperatively" (e.g. via
           <package>wpa_supplicant_gui</package>) and declaratively via
-          <xref linkend="opt-networking.wireless.networks" />.
+          <xref linkend="opt-networking.wireless.networks"/>.
 
           Please note that this adds a custom patch to <package>wpa_supplicant</package>.
         '';
diff --git a/nixos/modules/services/networking/yggdrasil.nix b/nixos/modules/services/networking/yggdrasil.nix
index 07b2e2a2daf2c..266149cf22111 100644
--- a/nixos/modules/services/networking/yggdrasil.nix
+++ b/nixos/modules/services/networking/yggdrasil.nix
@@ -44,8 +44,8 @@ in {
           are supplied, they will be combined, with values from
           <option>configFile</option> taking precedence.
 
-          You can use the command <code>nix-shell -p yggdrasil --run
-          "yggdrasil -genconf"</code> to generate default
+          You can use the command <literal>nix-shell -p yggdrasil --run
+          "yggdrasil -genconf"</literal> to generate default
           configuration values with documentation.
         '';
       };
@@ -64,21 +64,21 @@ in {
         type = types.nullOr types.str;
         default = null;
         example = "wheel";
-        description = "Group to grant access to the Yggdrasil control socket. If <code>null</code>, only root can access the socket.";
+        description = lib.mdDoc "Group to grant access to the Yggdrasil control socket. If `null`, only root can access the socket.";
       };
 
       openMulticastPort = mkOption {
         type = bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to open the UDP port used for multicast peer
           discovery. The NixOS firewall blocks link-local
           communication, so in order to make local peering work you
-          will also need to set <code>LinkLocalTCPPort</code> in your
-          yggdrasil configuration (<option>config</option> or
-          <option>configFile</option>) to a port number other than 0,
+          will also need to set `LinkLocalTCPPort` in your
+          yggdrasil configuration ({option}`config` or
+          {option}`configFile`) to a port number other than 0,
           and then add that port to
-          <option>networking.firewall.allowedTCPPorts</option>.
+          {option}`networking.firewall.allowedTCPPorts`.
         '';
       };
 
diff --git a/nixos/modules/services/networking/znc/default.nix b/nixos/modules/services/networking/znc/default.nix
index a98f92d2d710c..42a332d6bf03b 100644
--- a/nixos/modules/services/networking/znc/default.nix
+++ b/nixos/modules/services/networking/znc/default.nix
@@ -156,22 +156,18 @@ in
           format ZNC expects. This is much more flexible than the legacy options
           under <option>services.znc.confOptions.*</option>, but also can't do
           any type checking.
-          </para>
-          <para>
+
           You can use <command>nix-instantiate --eval --strict '&lt;nixpkgs/nixos&gt;' -A config.services.znc.config</command>
           to view the current value. By default it contains a listener for port
           5000 with SSL enabled.
-          </para>
-          <para>
+
           Nix attributes called <literal>extraConfig</literal> will be inserted
           verbatim into the resulting config file.
-          </para>
-          <para>
+
           If <option>services.znc.useLegacyConfig</option> is turned on, the
           option values in <option>services.znc.confOptions.*</option> will be
           gracefully be applied to this option.
-          </para>
-          <para>
+
           If you intend to update the configuration through this option, be sure
           to enable <option>services.znc.mutable</option>, otherwise none of the
           changes here will be applied after the initial deploy.
@@ -184,8 +180,7 @@ in
         description = ''
           Configuration file for ZNC. It is recommended to use the
           <option>config</option> option instead.
-          </para>
-          <para>
+
           Setting this option will override any auto-generated config file
           through the <option>confOptions</option> or <option>config</option>
           options.
@@ -208,13 +203,11 @@ in
           Indicates whether to allow the contents of the
           <literal>dataDir</literal> directory to be changed by the user at
           run-time.
-          </para>
-          <para>
+
           If enabled, modifications to the ZNC configuration after its initial
           creation are not overwritten by a NixOS rebuild. If disabled, the
           ZNC configuration is rebuilt on every NixOS rebuild.
-          </para>
-          <para>
+
           If the user wants to manage the ZNC service using the web admin
           interface, this option should be enabled.
         '';
diff --git a/nixos/modules/services/networking/znc/options.nix b/nixos/modules/services/networking/znc/options.nix
index 830df809155a4..021fea9819a76 100644
--- a/nixos/modules/services/networking/znc/options.nix
+++ b/nixos/modules/services/networking/znc/options.nix
@@ -106,8 +106,7 @@ in
           <option>services.znc.confOptions.*</option> options.
           You can use <command>nix-instantiate --eval --strict '&lt;nixpkgs/nixos&gt;' -A config.services.znc.config</command>
           to view the current value of the config.
-          </para>
-          <para>
+
           In any case, if you need more flexibility,
           <option>services.znc.config</option> can be used to override/add to
           all of the legacy options.
diff --git a/nixos/modules/services/security/privacyidea.nix b/nixos/modules/services/security/privacyidea.nix
index 599ade003c031..29c499e33ab59 100644
--- a/nixos/modules/services/security/privacyidea.nix
+++ b/nixos/modules/services/security/privacyidea.nix
@@ -78,7 +78,7 @@ in
           using <package>envsubst</package> which is helpful for specifying
           secrets:
           <programlisting>
-          { <xref linkend="opt-services.privacyidea.secretKey" /> = "$SECRET"; }
+          { <xref linkend="opt-services.privacyidea.secretKey"/> = "$SECRET"; }
           </programlisting>
 
           The environment-file can now specify the actual secret key:
@@ -207,7 +207,7 @@ in
           description = ''
             Attribute-set containing the settings for <package>privacyidea-ldap-proxy</package>.
             It's possible to pass secrets using env-vars as substitutes and
-            use the option <xref linkend="opt-services.privacyidea.ldap-proxy.environmentFile" />
+            use the option <xref linkend="opt-services.privacyidea.ldap-proxy.environmentFile"/>
             to inject them via <package>envsubst</package>.
           '';
         };
@@ -215,9 +215,9 @@ in
         environmentFile = mkOption {
           default = null;
           type = types.nullOr types.str;
-          description = ''
+          description = lib.mdDoc ''
             Environment file containing secrets to be substituted into
-            <xref linkend="opt-services.privacyidea.ldap-proxy.settings" />.
+            [](#opt-services.privacyidea.ldap-proxy.settings).
           '';
         };
       };
diff --git a/nixos/modules/services/security/step-ca.nix b/nixos/modules/services/security/step-ca.nix
index 9b9b53f135166..1afcf659632e8 100644
--- a/nixos/modules/services/security/step-ca.nix
+++ b/nixos/modules/services/security/step-ca.nix
@@ -36,8 +36,8 @@ in
         type = with lib.types; attrsOf anything;
         description = ''
           Settings that go into <filename>ca.json</filename>. See
-          <link xlink:href="https://smallstep.com/docs/step-ca/configuration">
-          the step-ca manual</link> for more information. The easiest way to
+          <link xlink:href="https://smallstep.com/docs/step-ca/configuration">the step-ca manual</link>
+          for more information. The easiest way to
           configure this module would be to run <literal>step ca init</literal>
           to generate <filename>ca.json</filename> and then import it using
           <literal>builtins.fromJSON</literal>.
diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix
index f611fee69089e..84f577c3853b4 100644
--- a/nixos/modules/services/security/tor.nix
+++ b/nixos/modules/services/security/tor.nix
@@ -287,7 +287,7 @@ in
       relay = {
         enable = mkEnableOption ''relaying of Tor traffic for others.
 
-          See <link xlink:href="https://www.torproject.org/docs/tor-doc-relay" />
+          See <link xlink:href="https://www.torproject.org/docs/tor-doc-relay"/>
           for details.
 
           Setting this to true requires setting
@@ -348,7 +348,7 @@ in
 
                 <para>
                   See
-                  <link xlink:href="https://www.torproject.org/docs/tor-doc-relay.html.en" />
+                  <link xlink:href="https://www.torproject.org/docs/tor-doc-relay.html.en"/>
                   for more info.
                 </para>
               </listitem>
@@ -366,7 +366,7 @@ in
                 <para>
                   Using this option will make Tor advertise your bridge
                   to users through various mechanisms like
-                  <link xlink:href="https://bridges.torproject.org/" />, though.
+                  <link xlink:href="https://bridges.torproject.org/"/>, though.
                 </para>
 
                 <important>
@@ -384,7 +384,7 @@ in
                 </important>
 
                 <para>
-                  See <link xlink:href="https://www.torproject.org/docs/bridges.html.en" />
+                  See <link xlink:href="https://www.torproject.org/docs/bridges.html.en"/>
                   for more info.
                 </para>
               </listitem>
@@ -419,7 +419,7 @@ in
                 </para>
 
                 <para>
-                  See <link xlink:href="https://www.torproject.org/docs/bridges.html.en" />
+                  See <link xlink:href="https://www.torproject.org/docs/bridges.html.en"/>
                   for more info.
                 </para>
               </listitem>
@@ -476,11 +476,11 @@ in
                   };
                   clientNames = mkOption {
                     type = with types; nonEmptyListOf (strMatching "[A-Za-z0-9+-_]+");
-                    description = ''
+                    description = lib.mdDoc ''
                       Only clients that are listed here are authorized to access the hidden service.
-                      Generated authorization data can be found in <filename>${stateDir}/onion/$name/hostname</filename>.
+                      Generated authorization data can be found in {file}`${stateDir}/onion/$name/hostname`.
                       Clients need to put this authorization data in their configuration file using
-                      <xref linkend="opt-services.tor.settings.HidServAuth"/>.
+                      [](#opt-services.tor.settings.HidServAuth).
                     '';
                   };
                 };
diff --git a/nixos/modules/services/security/vault.nix b/nixos/modules/services/security/vault.nix
index e4777910b6d39..ef9829630296d 100644
--- a/nixos/modules/services/security/vault.nix
+++ b/nixos/modules/services/security/vault.nix
@@ -116,13 +116,13 @@ in
       storageConfig = mkOption {
         type = types.nullOr types.lines;
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           HCL configuration to insert in the storageBackend section.
 
           Confidential values should not be specified here because this option's
           value is written to the Nix store, which is publicly readable.
           Provide credentials and such in a separate file using
-          <xref linkend="opt-services.vault.extraSettingsPaths"/>.
+          [](#opt-services.vault.extraSettingsPaths).
         '';
       };
 
diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix
index 7e5389d78f4b7..1433438ba0091 100644
--- a/nixos/modules/services/security/vaultwarden/default.nix
+++ b/nixos/modules/services/security/vaultwarden/default.nix
@@ -116,7 +116,7 @@ in {
         The available configuration options can be found in
         <link xlink:href="https://github.com/dani-garcia/vaultwarden/blob/${vaultwarden.version}/.env.template">the environment template file</link>.
 
-        See <xref linkend="opt-services.vaultwarden.environmentFile" /> for how
+        See <xref linkend="opt-services.vaultwarden.environmentFile"/> for how
         to set up access to the Admin UI to invite initial users.
       '';
     };
diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix
index c02e0905f1ccf..def04d944f058 100644
--- a/nixos/modules/services/system/dbus.nix
+++ b/nixos/modules/services/system/dbus.nix
@@ -38,17 +38,17 @@ in
       packages = mkOption {
         type = types.listOf types.path;
         default = [ ];
-        description = ''
+        description = lib.mdDoc ''
           Packages whose D-Bus configuration files should be included in
           the configuration of the D-Bus system-wide or session-wide
           message bus.  Specifically, files in the following directories
           will be included into their respective DBus configuration paths:
-          <filename><replaceable>pkg</replaceable>/etc/dbus-1/system.d</filename>
-          <filename><replaceable>pkg</replaceable>/share/dbus-1/system.d</filename>
-          <filename><replaceable>pkg</replaceable>/share/dbus-1/system-services</filename>
-          <filename><replaceable>pkg</replaceable>/etc/dbus-1/session.d</filename>
-          <filename><replaceable>pkg</replaceable>/share/dbus-1/session.d</filename>
-          <filename><replaceable>pkg</replaceable>/share/dbus-1/services</filename>
+          {file}`«pkg»/etc/dbus-1/system.d`
+          {file}`«pkg»/share/dbus-1/system.d`
+          {file}`«pkg»/share/dbus-1/system-services`
+          {file}`«pkg»/etc/dbus-1/session.d`
+          {file}`«pkg»/share/dbus-1/session.d`
+          {file}`«pkg»/share/dbus-1/services`
         '';
       };
 
diff --git a/nixos/modules/services/system/earlyoom.nix b/nixos/modules/services/system/earlyoom.nix
index 3e361fce00f98..b2e2d21002ce1 100644
--- a/nixos/modules/services/system/earlyoom.nix
+++ b/nixos/modules/services/system/earlyoom.nix
@@ -32,32 +32,32 @@ in
     freeMemKillThreshold = mkOption {
       type = types.nullOr (types.ints.between 1 100);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Minimum available memory (in percent) before sending SIGKILL.
-        If unset, this defaults to half of <option>freeMemThreshold</option>.
+        If unset, this defaults to half of {option}`freeMemThreshold`.
 
-        See the description of <xref linkend="opt-services.earlyoom.freeMemThreshold"/>.
+        See the description of [](#opt-services.earlyoom.freeMemThreshold).
       '';
     };
 
     freeSwapThreshold = mkOption {
       type = types.ints.between 1 100;
       default = 10;
-      description = ''
+      description = lib.mdDoc ''
         Minimum free swap space (in percent) before sending SIGTERM.
 
-        See the description of <xref linkend="opt-services.earlyoom.freeMemThreshold"/>.
+        See the description of [](#opt-services.earlyoom.freeMemThreshold).
       '';
     };
 
     freeSwapKillThreshold = mkOption {
       type = types.nullOr (types.ints.between 1 100);
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Minimum free swap space (in percent) before sending SIGKILL.
-        If unset, this defaults to half of <option>freeSwapThreshold</option>.
+        If unset, this defaults to half of {option}`freeSwapThreshold`.
 
-        See the description of <xref linkend="opt-services.earlyoom.freeMemThreshold"/>.
+        See the description of [](#opt-services.earlyoom.freeMemThreshold).
       '';
     };
 
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index 9777964386c96..6a038dc0a32ce 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -55,13 +55,13 @@ in
             type = types.path;
             default = "${cfg.home}/${incompleteDir}";
             defaultText = literalExpression ''"''${config.${opt.home}}/${incompleteDir}"'';
-            description = ''
+            description = lib.mdDoc ''
               When enabled with
               services.transmission.home
-              <xref linkend="opt-services.transmission.settings.incomplete-dir-enabled"/>,
+              [](#opt-services.transmission.settings.incomplete-dir-enabled),
               new torrents will download the files to this directory.
               When complete, the files will be moved to download-dir
-              <xref linkend="opt-services.transmission.settings.download-dir"/>.
+              [](#opt-services.transmission.settings.download-dir).
             '';
           };
           options.incomplete-dir-enabled = mkOption {
@@ -82,17 +82,17 @@ in
           options.peer-port-random-high = mkOption {
             type = types.port;
             default = 65535;
-            description = ''
+            description = lib.mdDoc ''
               The maximum peer port to listen to for incoming connections
-              when <xref linkend="opt-services.transmission.settings.peer-port-random-on-start"/> is enabled.
+              when [](#opt-services.transmission.settings.peer-port-random-on-start) is enabled.
             '';
           };
           options.peer-port-random-low = mkOption {
             type = types.port;
             default = 65535;
-            description = ''
+            description = lib.mdDoc ''
               The minimal peer port to listen to for incoming connections
-              when <xref linkend="opt-services.transmission.settings.peer-port-random-on-start"/> is enabled.
+              when [](#opt-services.transmission.settings.peer-port-random-on-start) is enabled.
             '';
           };
           options.peer-port-random-on-start = mkOption {
@@ -117,9 +117,9 @@ in
           options.script-torrent-done-enabled = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Whether to run
-              <xref linkend="opt-services.transmission.settings.script-torrent-done-filename"/>
+              [](#opt-services.transmission.settings.script-torrent-done-filename)
               at torrent completion.
             '';
           };
@@ -156,15 +156,15 @@ in
           options.watch-dir-enabled = mkOption {
             type = types.bool;
             default = false;
-            description = ''Whether to enable the
-              <xref linkend="opt-services.transmission.settings.watch-dir"/>.
+            description = lib.mdDoc ''Whether to enable the
+              [](#opt-services.transmission.settings.watch-dir).
             '';
           };
           options.trash-original-torrent-files = mkOption {
             type = types.bool;
             default = false;
-            description = ''Whether to delete torrents added from the
-              <xref linkend="opt-services.transmission.settings.watch-dir"/>.
+            description = lib.mdDoc ''Whether to delete torrents added from the
+              [](#opt-services.transmission.settings.watch-dir).
             '';
           };
         };
@@ -174,26 +174,26 @@ in
         type = with types; nullOr str;
         default = null;
         example = "770";
-        description = ''
-          If not <code>null</code>, is used as the permissions
-          set by <literal>systemd.activationScripts.transmission-daemon</literal>
-          on the directories <xref linkend="opt-services.transmission.settings.download-dir"/>,
-          <xref linkend="opt-services.transmission.settings.incomplete-dir"/>.
-          and <xref linkend="opt-services.transmission.settings.watch-dir"/>.
+        description = lib.mdDoc ''
+          If not `null`, is used as the permissions
+          set by `systemd.activationScripts.transmission-daemon`
+          on the directories [](#opt-services.transmission.settings.download-dir),
+          [](#opt-services.transmission.settings.incomplete-dir).
+          and [](#opt-services.transmission.settings.watch-dir).
           Note that you may also want to change
-          <xref linkend="opt-services.transmission.settings.umask"/>.
+          [](#opt-services.transmission.settings.umask).
         '';
       };
 
       home = mkOption {
         type = types.path;
         default = "/var/lib/transmission";
-        description = ''
-          The directory where Transmission will create <literal>${settingsDir}</literal>.
-          as well as <literal>${downloadsDir}/</literal> unless
-          <xref linkend="opt-services.transmission.settings.download-dir"/> is changed,
-          and <literal>${incompleteDir}/</literal> unless
-          <xref linkend="opt-services.transmission.settings.incomplete-dir"/> is changed.
+        description = lib.mdDoc ''
+          The directory where Transmission will create `${settingsDir}`.
+          as well as `${downloadsDir}/` unless
+          [](#opt-services.transmission.settings.download-dir) is changed,
+          and `${incompleteDir}/` unless
+          [](#opt-services.transmission.settings.incomplete-dir) is changed.
         '';
       };
 
@@ -211,10 +211,10 @@ in
 
       credentialsFile = mkOption {
         type = types.path;
-        description = ''
+        description = lib.mdDoc ''
           Path to a JSON file to be merged with the settings.
           Useful to merge a file which is better kept out of the Nix store
-          to set secret config parameters like <code>rpc-password</code>.
+          to set secret config parameters like `rpc-password`.
         '';
         default = "/dev/null";
         example = "/var/lib/secrets/transmission/settings.json";
@@ -237,7 +237,7 @@ in
         to open many more connections at the same time.
 
         Note that you may also want to increase
-        <code>peer-limit-global"</code>.
+        <literal>peer-limit-global"</literal>.
         And be aware that these settings are quite aggressive
         and might not suite your regular desktop use.
         For instance, SSH sessions may time out more easily'';
diff --git a/nixos/modules/services/web-apps/bookstack.nix b/nixos/modules/services/web-apps/bookstack.nix
index 64a2767fab6e1..5d22a3b9a8d62 100644
--- a/nixos/modules/services/web-apps/bookstack.nix
+++ b/nixos/modules/services/web-apps/bookstack.nix
@@ -52,7 +52,7 @@ in {
       description = ''
         A file containing the Laravel APP_KEY - a 32 character long,
         base64 encoded key used for encryption where needed. Can be
-        generated with <code>head -c 32 /dev/urandom | base64</code>.
+        generated with <literal>head -c 32 /dev/urandom | base64</literal>.
       '';
       example = "/run/keys/bookstack-appkey";
       type = types.path;
@@ -74,7 +74,7 @@ in {
     appURL = mkOption {
       description = ''
         The root URL that you want to host BookStack on. All URLs in BookStack will be generated using this value.
-        If you change this in the future you may need to run a command to update stored URLs in the database. Command example: <code>php artisan bookstack:update-url https://old.example.com https://new.example.com</code>
+        If you change this in the future you may need to run a command to update stored URLs in the database. Command example: <literal>php artisan bookstack:update-url https://old.example.com https://new.example.com</literal>
       '';
       default = "http${lib.optionalString tlsEnabled "s"}://${cfg.hostname}";
       defaultText = ''http''${lib.optionalString tlsEnabled "s"}://''${cfg.hostname}'';
diff --git a/nixos/modules/services/web-apps/dokuwiki.nix b/nixos/modules/services/web-apps/dokuwiki.nix
index 49865b962d108..a148dec8199a8 100644
--- a/nixos/modules/services/web-apps/dokuwiki.nix
+++ b/nixos/modules/services/web-apps/dokuwiki.nix
@@ -260,14 +260,14 @@ in
       webserver = mkOption {
         type = types.enum [ "nginx" "caddy" ];
         default = "nginx";
-        description = ''
+        description = lib.mdDoc ''
           Whether to use nginx or caddy for virtual host management.
 
-          Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.&lt;name&gt;</literal>.
-          See <xref linkend="opt-services.nginx.virtualHosts"/> for further information.
+          Further nginx configuration can be done by adapting `services.nginx.virtualHosts.<name>`.
+          See [](#opt-services.nginx.virtualHosts) for further information.
 
-          Further apache2 configuration can be done by adapting <literal>services.httpd.virtualHosts.&lt;name&gt;</literal>.
-          See <xref linkend="opt-services.httpd.virtualHosts"/> for further information.
+          Further apache2 configuration can be done by adapting `services.httpd.virtualHosts.<name>`.
+          See [](#opt-services.httpd.virtualHosts) for further information.
         '';
       };
 
diff --git a/nixos/modules/services/web-apps/hedgedoc.nix b/nixos/modules/services/web-apps/hedgedoc.nix
index b8d83984ca7dc..6f579b365cfec 100644
--- a/nixos/modules/services/web-apps/hedgedoc.nix
+++ b/nixos/modules/services/web-apps/hedgedoc.nix
@@ -150,10 +150,9 @@ in
             addDefaults = true;
           }
         '';
-        description = ''
+        description = lib.mdDoc ''
           Specify the Content Security Policy which is passed to Helmet.
-          For configuration details see <link xlink:href="https://helmetjs.github.io/docs/csp/"
-          >https://helmetjs.github.io/docs/csp/</link>.
+          For configuration details see <https://helmetjs.github.io/docs/csp/>.
         '';
       };
       protocolUseSSL = mkOption {
diff --git a/nixos/modules/services/web-apps/keycloak.nix b/nixos/modules/services/web-apps/keycloak.nix
index de76babbaedd9..c1091bc09a06f 100644
--- a/nixos/modules/services/web-apps/keycloak.nix
+++ b/nixos/modules/services/web-apps/keycloak.nix
@@ -210,14 +210,13 @@ in
         name = mkOption {
           type = str;
           default = "keycloak";
-          description = ''
+          description = lib.mdDoc ''
             Database name to use when connecting to an external or
             manually provisioned database; has no effect when a local
             database is automatically provisioned.
 
-            To use this with a local database, set <xref
-            linkend="opt-services.keycloak.database.createLocally" /> to
-            <literal>false</literal> and create the database and user
+            To use this with a local database, set [](#opt-services.keycloak.database.createLocally) to
+            `false` and create the database and user
             manually.
           '';
         };
@@ -225,14 +224,13 @@ in
         username = mkOption {
           type = str;
           default = "keycloak";
-          description = ''
+          description = lib.mdDoc ''
             Username to use when connecting to an external or manually
             provisioned database; has no effect when a local database is
             automatically provisioned.
 
-            To use this with a local database, set <xref
-            linkend="opt-services.keycloak.database.createLocally" /> to
-            <literal>false</literal> and create the database and user
+            To use this with a local database, set [](#opt-services.keycloak.database.createLocally) to
+            `false` and create the database and user
             manually.
           '';
         };
@@ -329,10 +327,8 @@ in
                     want to set this to <literal>/auth</literal> to
                     keep compatibility with your clients.
 
-                    See <link
-                    xlink:href="https://www.keycloak.org/migration/migrating-to-quarkus"
-                    /> for more information on migrating from Wildfly
-                    to Quarkus.
+                    See <link xlink:href="https://www.keycloak.org/migration/migrating-to-quarkus"/>
+                    for more information on migrating from Wildfly to Quarkus.
                   </para>
                 </note>
               '';
@@ -404,9 +400,7 @@ in
                   </varlistentry>
                 </variablelist>
 
-                See <link
-                xlink:href="https://www.keycloak.org/server/reverseproxy"
-                /> for more information.
+                See <link xlink:href="https://www.keycloak.org/server/reverseproxy"/> for more information.
               '';
             };
           };
@@ -421,22 +415,21 @@ in
           }
         '';
 
-        description = ''
+        description = lib.mdDoc ''
           Configuration options corresponding to parameters set in
-          <filename>conf/keycloak.conf</filename>.
+          {file}`conf/keycloak.conf`.
 
-          Most available options are documented at <link
-          xlink:href="https://www.keycloak.org/server/all-config" />.
+          Most available options are documented at <https://www.keycloak.org/server/all-config>.
 
           Options containing secret data should be set to an attribute
-          set containing the attribute <literal>_secret</literal> - a
+          set containing the attribute `_secret` - a
           string pointing to a file containing the value the option
           should be set to. See the example to get a better picture of
           this: in the resulting
-          <filename>conf/keycloak.conf</filename> file, the
-          <literal>https-key-store-password</literal> key will be set
+          {file}`conf/keycloak.conf` file, the
+          `https-key-store-password` key will be set
           to the contents of the
-          <filename>/run/keys/store_password</filename> file.
+          {file}`/run/keys/store_password` file.
         '';
       };
     };
diff --git a/nixos/modules/services/web-apps/mastodon.nix b/nixos/modules/services/web-apps/mastodon.nix
index f3f0fb7cb5342..d0594ff741927 100644
--- a/nixos/modules/services/web-apps/mastodon.nix
+++ b/nixos/modules/services/web-apps/mastodon.nix
@@ -113,17 +113,17 @@ in {
           affect other virtualHosts running on your nginx instance, if any.
           Alternatively you can configure a reverse-proxy of your choice to serve these paths:
 
-          <code>/ -> $(nix-instantiate --eval '&lt;nixpkgs&gt;' -A mastodon.outPath)/public</code>
+          <literal>/ -> $(nix-instantiate --eval '&lt;nixpkgs&gt;' -A mastodon.outPath)/public</literal>
 
-          <code>/ -> 127.0.0.1:{{ webPort }} </code>(If there was no file in the directory above.)
+          <literal>/ -> 127.0.0.1:{{ webPort }} </literal>(If there was no file in the directory above.)
 
-          <code>/system/ -> /var/lib/mastodon/public-system/</code>
+          <literal>/system/ -> /var/lib/mastodon/public-system/</literal>
 
-          <code>/api/v1/streaming/ -> 127.0.0.1:{{ streamingPort }}</code>
+          <literal>/api/v1/streaming/ -> 127.0.0.1:{{ streamingPort }}</literal>
 
           Make sure that websockets are forwarded properly. You might want to set up caching
           of some requests. Take a look at mastodon's provided nginx configuration at
-          <code>https://github.com/mastodon/mastodon/blob/master/dist/nginx.conf</code>.
+          <literal>https://github.com/mastodon/mastodon/blob/master/dist/nginx.conf</literal>.
         '';
         type = lib.types.bool;
         default = false;
@@ -135,13 +135,13 @@ in {
           that user will be created, otherwise it should be set to the
           name of a user created elsewhere.  In both cases,
           <package>mastodon</package> and a package containing only
-          the shell script <code>mastodon-env</code> will be added to
+          the shell script <literal>mastodon-env</literal> will be added to
           the user's package set. To run a command from
-          <package>mastodon</package> such as <code>tootctl</code>
+          <package>mastodon</package> such as <literal>tootctl</literal>
           with the environment configured by this module use
-          <code>mastodon-env</code>, as in:
+          <literal>mastodon-env</literal>, as in:
 
-          <code>mastodon-env tootctl accounts create newuser --email newuser@example.com</code>
+          <literal>mastodon-env tootctl accounts create newuser --email newuser@example.com</literal>
         '';
         type = lib.types.str;
         default = "mastodon";
@@ -197,14 +197,14 @@ in {
       };
 
       vapidPublicKeyFile = lib.mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Path to file containing the public key used for Web Push
           Voluntary Application Server Identification.  A new keypair can
           be generated by running:
 
-          <code>nix build -f '&lt;nixpkgs&gt;' mastodon; cd result; bin/rake webpush:generate_keys</code>
+          `nix build -f '<nixpkgs>' mastodon; cd result; bin/rake webpush:generate_keys`
 
-          If <option>mastodon.vapidPrivateKeyFile</option>does not
+          If {option}`mastodon.vapidPrivateKeyFile`does not
           exist, it and this file will be created with a new keypair.
         '';
         default = "/var/lib/mastodon/secrets/vapid-public-key";
@@ -218,11 +218,11 @@ in {
       };
 
       secretKeyBaseFile = lib.mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Path to file containing the secret key base.
           A new secret key base can be generated by running:
 
-          <code>nix build -f '&lt;nixpkgs&gt;' mastodon; cd result; bin/rake secret</code>
+          `nix build -f '<nixpkgs>' mastodon; cd result; bin/rake secret`
 
           If this file does not exist, it will be created with a new secret key base.
         '';
@@ -231,11 +231,11 @@ in {
       };
 
       otpSecretFile = lib.mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Path to file containing the OTP secret.
           A new OTP secret can be generated by running:
 
-          <code>nix build -f '&lt;nixpkgs&gt;' mastodon; cd result; bin/rake secret</code>
+          `nix build -f '<nixpkgs>' mastodon; cd result; bin/rake secret`
 
           If this file does not exist, it will be created with a new OTP secret.
         '';
@@ -244,12 +244,12 @@ in {
       };
 
       vapidPrivateKeyFile = lib.mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Path to file containing the private key used for Web Push
           Voluntary Application Server Identification.  A new keypair can
           be generated by running:
 
-          <code>nix build -f '&lt;nixpkgs&gt;' mastodon; cd result; bin/rake webpush:generate_keys</code>
+          `nix build -f '<nixpkgs>' mastodon; cd result; bin/rake webpush:generate_keys`
 
           If this file does not exist, it will be created with a new
           private key.
diff --git a/nixos/modules/services/web-apps/mediawiki.nix b/nixos/modules/services/web-apps/mediawiki.nix
index 977b6f60b230e..71154555942ea 100644
--- a/nixos/modules/services/web-apps/mediawiki.nix
+++ b/nixos/modules/services/web-apps/mediawiki.nix
@@ -280,7 +280,7 @@ in
             one version of MediaWiki, or have other applications that also use the
             database, you can give the table names a unique prefix to stop any naming
             conflicts or confusion.
-            See <link xlink:href='https://www.mediawiki.org/wiki/Manual:$wgDBprefix'/>.
+            See <link xlink:href="https://www.mediawiki.org/wiki/Manual:$wgDBprefix"/>.
           '';
         };
 
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index 618ad85b8605c..feee7494a71af 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -93,8 +93,8 @@ in {
       type = types.str;
       default = config.services.nextcloud.home;
       defaultText = literalExpression "config.services.nextcloud.home";
-      description = ''
-        Data storage path of nextcloud.  Will be <xref linkend="opt-services.nextcloud.home" /> by default.
+      description = lib.mdDoc ''
+        Data storage path of nextcloud.  Will be [](#opt-services.nextcloud.home) by default.
         This folder will be populated with a config.php and data folder which contains the state of the instance (excl the database).";
       '';
       example = "/mnt/nextcloud-file";
@@ -102,10 +102,10 @@ in {
     extraApps = mkOption {
       type = types.attrsOf types.package;
       default = { };
-      description = ''
+      description = lib.mdDoc ''
         Extra apps to install. Should be an attrSet of appid to packages generated by fetchNextcloudApp.
         The appid must be identical to the "id" value in the apps appinfo/info.xml.
-        Using this will disable the appstore to prevent Nextcloud from updating these apps (see <xref linkend="opt-services.nextcloud.appstoreEnable" />).
+        Using this will disable the appstore to prevent Nextcloud from updating these apps (see [](#opt-services.nextcloud.appstoreEnable)).
       '';
       example = literalExpression ''
         {
@@ -127,8 +127,8 @@ in {
     extraAppsEnable = mkOption {
       type = types.bool;
       default = true;
-      description = ''
-        Automatically enable the apps in <xref linkend="opt-services.nextcloud.extraApps" /> every time nextcloud starts.
+      description = lib.mdDoc ''
+        Automatically enable the apps in [](#opt-services.nextcloud.extraApps) every time nextcloud starts.
         If set to false, apps need to be enabled in the Nextcloud user interface or with nextcloud-occ app:enable.
       '';
     };
@@ -136,10 +136,10 @@ in {
       type = types.nullOr types.bool;
       default = null;
       example = true;
-      description = ''
+      description = lib.mdDoc ''
         Allow the installation of apps and app updates from the store.
-        Enabled by default unless there are packages in <xref linkend="opt-services.nextcloud.extraApps" />.
-        Set to true to force enable the store even if <xref linkend="opt-services.nextcloud.extraApps" /> is used.
+        Enabled by default unless there are packages in [](#opt-services.nextcloud.extraApps).
+        Set to true to force enable the store even if [](#opt-services.nextcloud.extraApps) is used.
         Set to false to disable the installation of apps from the global appstore. App management is always enabled regardless of this setting.
       '';
     };
@@ -467,7 +467,7 @@ in {
         This is used by the theming app and for generating previews of certain images (e.g. SVG and HEIF).
         You may want to disable it for increased security. In that case, previews will still be available
         for some images (e.g. JPEG and PNG).
-        See <link xlink:href="https://github.com/nextcloud/server/issues/13099" />.
+        See <link xlink:href="https://github.com/nextcloud/server/issues/13099"/>.
     '' // {
       default = true;
     };
@@ -585,9 +585,9 @@ in {
       hstsMaxAge = mkOption {
         type = types.ints.positive;
         default = 15552000;
-        description = ''
-          Value for the <code>max-age</code> directive of the HTTP
-          <code>Strict-Transport-Security</code> header.
+        description = lib.mdDoc ''
+          Value for the `max-age` directive of the HTTP
+          `Strict-Transport-Security` header.
 
           See section 6.1.1 of IETF RFC 6797 for detailed information on this
           directive and header.
diff --git a/nixos/modules/services/web-apps/node-red.nix b/nixos/modules/services/web-apps/node-red.nix
index 1b9d14ecf4ff4..e5b0998d3c41d 100644
--- a/nixos/modules/services/web-apps/node-red.nix
+++ b/nixos/modules/services/web-apps/node-red.nix
@@ -47,10 +47,9 @@ in
       type = types.path;
       default = "${cfg.package}/lib/node_modules/node-red/settings.js";
       defaultText = literalExpression ''"''${package}/lib/node_modules/node-red/settings.js"'';
-      description = ''
+      description = lib.mdDoc ''
         Path to the JavaScript configuration file.
-        See <link
-        xlink:href="https://github.com/node-red/node-red/blob/master/packages/node_modules/node-red/settings.js"/>
+        See <https://github.com/node-red/node-red/blob/master/packages/node_modules/node-red/settings.js>
         for a configuration example.
       '';
     };
diff --git a/nixos/modules/services/web-apps/snipe-it.nix b/nixos/modules/services/web-apps/snipe-it.nix
index 842e0715c0256..3059e67cb43b8 100644
--- a/nixos/modules/services/web-apps/snipe-it.nix
+++ b/nixos/modules/services/web-apps/snipe-it.nix
@@ -46,7 +46,7 @@ in {
       description = ''
         A file containing the Laravel APP_KEY - a 32 character long,
         base64 encoded key used for encryption where needed. Can be
-        generated with <code>head -c 32 /dev/urandom | base64</code>.
+        generated with <literal>head -c 32 /dev/urandom | base64</literal>.
       '';
       example = "/run/keys/snipe-it/appkey";
       type = types.path;
@@ -69,7 +69,7 @@ in {
       description = ''
         The root URL that you want to host Snipe-IT on. All URLs in Snipe-IT will be generated using this value.
         If you change this in the future you may need to run a command to update stored URLs in the database.
-        Command example: <code>snipe-it snipe-it:update-url https://old.example.com https://new.example.com</code>
+        Command example: <literal>snipe-it snipe-it:update-url https://old.example.com https://new.example.com</literal>
       '';
       default = "http${lib.optionalString tlsEnabled "s"}://${cfg.hostName}";
       defaultText = ''
diff --git a/nixos/modules/services/web-apps/trilium.nix b/nixos/modules/services/web-apps/trilium.nix
index 75464b21fd417..bb1061cf278e0 100644
--- a/nixos/modules/services/web-apps/trilium.nix
+++ b/nixos/modules/services/web-apps/trilium.nix
@@ -53,7 +53,7 @@ in
     noAuthentication = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         If set to true, no password is required to access the web frontend.
       '';
     };
diff --git a/nixos/modules/services/web-apps/virtlyst.nix b/nixos/modules/services/web-apps/virtlyst.nix
deleted file mode 100644
index 5094367a49378..0000000000000
--- a/nixos/modules/services/web-apps/virtlyst.nix
+++ /dev/null
@@ -1,73 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  cfg = config.services.virtlyst;
-  stateDir = "/var/lib/virtlyst";
-
-  ini = pkgs.writeText "virtlyst-config.ini" ''
-    [wsgi]
-    master = true
-    threads = auto
-    http-socket = ${cfg.httpSocket}
-    application = ${pkgs.virtlyst}/lib/libVirtlyst.so
-    chdir2 = ${stateDir}
-    static-map = /static=${pkgs.virtlyst}/root/static
-
-    [Cutelyst]
-    production = true
-    DatabasePath = virtlyst.sqlite
-    TemplatePath = ${pkgs.virtlyst}/root/src
-
-    [Rules]
-    cutelyst.* = true
-    virtlyst.* = true
-  '';
-
-in
-
-{
-
-  options.services.virtlyst = {
-    enable = mkEnableOption "Virtlyst libvirt web interface";
-
-    adminPassword = mkOption {
-      type = types.str;
-      description = lib.mdDoc ''
-        Initial admin password with which the database will be seeded.
-      '';
-    };
-
-    httpSocket = mkOption {
-      type = types.str;
-      default = "localhost:3000";
-      description = lib.mdDoc ''
-        IP and/or port to which to bind the http socket.
-      '';
-    };
-  };
-
-  config = mkIf cfg.enable {
-    users.users.virtlyst = {
-      home = stateDir;
-      createHome = true;
-      group = mkIf config.virtualisation.libvirtd.enable "libvirtd";
-      isSystemUser = true;
-    };
-
-    systemd.services.virtlyst = {
-      wantedBy = [ "multi-user.target" ];
-      environment = {
-        VIRTLYST_ADMIN_PASSWORD = cfg.adminPassword;
-      };
-      serviceConfig = {
-        ExecStart = "${pkgs.cutelyst}/bin/cutelyst-wsgi2 --ini ${ini}";
-        User = "virtlyst";
-        WorkingDirectory = stateDir;
-      };
-    };
-  };
-
-}
diff --git a/nixos/modules/services/web-apps/wiki-js.nix b/nixos/modules/services/web-apps/wiki-js.nix
index 474fbb8f13c31..5dc0bb73259bf 100644
--- a/nixos/modules/services/web-apps/wiki-js.nix
+++ b/nixos/modules/services/web-apps/wiki-js.nix
@@ -95,12 +95,11 @@ in {
       };
       description = ''
         Settings to configure <package>wiki-js</package>. This directly
-        corresponds to <link xlink:href="https://docs.requarks.io/install/config">the upstream
-        configuration options</link>.
+        corresponds to <link xlink:href="https://docs.requarks.io/install/config">the upstream configuration options</link>.
 
         Secrets can be injected via the environment by
         <itemizedlist>
-          <listitem><para>specifying <xref linkend="opt-services.wiki-js.environmentFile" />
+          <listitem><para>specifying <xref linkend="opt-services.wiki-js.environmentFile"/>
           to contain secrets</para></listitem>
           <listitem><para>and setting sensitive values to <literal>$(ENVIRONMENT_VAR)</literal>
           with this value defined in the environment-file.</para></listitem>
diff --git a/nixos/modules/services/web-apps/wordpress.nix b/nixos/modules/services/web-apps/wordpress.nix
index 59471a739cbb7..b1ae4deb27617 100644
--- a/nixos/modules/services/web-apps/wordpress.nix
+++ b/nixos/modules/services/web-apps/wordpress.nix
@@ -192,7 +192,7 @@ let
               prefix. Typically this is changed if you are installing multiple WordPress blogs
               in the same database.
 
-              See <link xlink:href='https://codex.wordpress.org/Editing_wp-config.php#table_prefix'/>.
+              See <link xlink:href="https://codex.wordpress.org/Editing_wp-config.php#table_prefix"/>.
             '';
           };
 
@@ -246,7 +246,7 @@ let
           description = ''
             Any additional text to be appended to the wp-config.php
             configuration file. This is a PHP script. For configuration
-            settings, see <link xlink:href='https://codex.wordpress.org/Editing_wp-config.php'/>.
+            settings, see <link xlink:href="https://codex.wordpress.org/Editing_wp-config.php"/>.
           '';
           example = ''
             define( 'AUTOSAVE_INTERVAL', 60 ); // Seconds
diff --git a/nixos/modules/services/web-servers/apache-httpd/vhost-options.nix b/nixos/modules/services/web-servers/apache-httpd/vhost-options.nix
index c52ab2c596e01..559210a1418ce 100644
--- a/nixos/modules/services/web-servers/apache-httpd/vhost-options.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/vhost-options.nix
@@ -233,7 +233,7 @@ in
       default = false;
       description = ''
         Whether to enable serving <filename>~/public_html</filename> as
-        <literal>/~<replaceable>username</replaceable></literal>.
+        <literal>/~«username»</literal>.
       '';
     };
 
@@ -261,8 +261,7 @@ in
       default = "";
       example = "Disallow: /foo/";
       description = ''
-        Specification of pages to be ignored by web crawlers. See <link
-        xlink:href='http://www.robotstxt.org/'/> for details.
+        Specification of pages to be ignored by web crawlers. See <link xlink:href="http://www.robotstxt.org/"/> for details.
       '';
     };
 
@@ -280,8 +279,7 @@ in
         };
       '';
       description = ''
-        Declarative location config. See <link
-        xlink:href="https://httpd.apache.org/docs/2.4/mod/core.html#location"/> for details.
+        Declarative location config. See <link xlink:href="https://httpd.apache.org/docs/2.4/mod/core.html#location"/> for details.
       '';
     };
 
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 5ccbaf77481b7..166f38f9ea284 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -504,16 +504,16 @@ in
           This is mutually exclusive to any other config option for
           <filename>nginx.conf</filename> except for
           <itemizedlist>
-          <listitem><para><xref linkend="opt-services.nginx.appendConfig" />
+          <listitem><para><xref linkend="opt-services.nginx.appendConfig"/>
           </para></listitem>
-          <listitem><para><xref linkend="opt-services.nginx.httpConfig" />
+          <listitem><para><xref linkend="opt-services.nginx.httpConfig"/>
           </para></listitem>
-          <listitem><para><xref linkend="opt-services.nginx.logError" />
+          <listitem><para><xref linkend="opt-services.nginx.logError"/>
           </para></listitem>
           </itemizedlist>
 
           If additional verbatim config in addition to other options is needed,
-          <xref linkend="opt-services.nginx.appendConfig" /> should be used instead.
+          <xref linkend="opt-services.nginx.appendConfig"/> should be used instead.
         '';
       };
 
diff --git a/nixos/modules/services/web-servers/uwsgi.nix b/nixos/modules/services/web-servers/uwsgi.nix
index c76eb795a9ed6..af6c6c0661246 100644
--- a/nixos/modules/services/web-servers/uwsgi.nix
+++ b/nixos/modules/services/web-servers/uwsgi.nix
@@ -179,8 +179,7 @@ in {
             <para>
               When in Emperor mode, any capability to be inherited by a vassal must
               be specified again in the vassal configuration using <literal>cap</literal>.
-              See the uWSGI <link
-              xlink:href="https://uwsgi-docs.readthedocs.io/en/latest/Capabilities.html">docs</link>
+              See the uWSGI <link xlink:href="https://uwsgi-docs.readthedocs.io/en/latest/Capabilities.html">docs</link>
               for more information.
             </para>
           </note>
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index 0a59999231696..5c39de0dde744 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -170,10 +170,9 @@ in
     supportDDC = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Support setting monitor brightness via DDC.
-        </para>
-        <para>
+
         This is not needed for controlling brightness of the internal monitor
         of a laptop and as it is considered experimental by upstream, it is
         disabled by default.
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
index 020bce8f7191f..c050367e74df6 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
@@ -158,7 +158,7 @@ in
   config = mkIf (ldmcfg.enable && cfg.enable) {
 
     services.xserver.displayManager.lightdm.greeter = mkDefault {
-      package = pkgs.lightdm_gtk_greeter.xgreeters;
+      package = pkgs.lightdm-gtk-greeter.xgreeters;
       name = "lightdm-gtk-greeter";
     };
 
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 00a47e7814f78..f4195c4c2dc39 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
@@ -55,12 +55,12 @@ in
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable lightdm-mini-greeter as the lightdm greeter.
 
           Note that this greeter starts only the default X session.
           You can configure the default X session using
-          <xref linkend="opt-services.xserver.displayManager.defaultSession"/>.
+          [](#opt-services.xserver.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 e8f799e27295f..8d6bfa98a7e4b 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix
@@ -17,12 +17,12 @@ in
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable lightdm-tiny-greeter as the lightdm greeter.
 
           Note that this greeter starts only the default X session.
           You can configure the default X session using
-          <xref linkend="opt-services.xserver.displayManager.defaultSession"/>.
+          [](#opt-services.xserver.displayManager.defaultSession).
         '';
       };
 
diff --git a/nixos/modules/services/x11/window-managers/fvwm2.nix b/nixos/modules/services/x11/window-managers/fvwm2.nix
index 909b3a475a9c2..b5ef36f58d54c 100644
--- a/nixos/modules/services/x11/window-managers/fvwm2.nix
+++ b/nixos/modules/services/x11/window-managers/fvwm2.nix
@@ -24,7 +24,7 @@ in
       gestures = mkOption {
         default = false;
         type = types.bool;
-        description = "Whether or not to enable libstroke for gesture support";
+        description = lib.mdDoc "Whether or not to enable libstroke for gesture support";
       };
     };
   };
diff --git a/nixos/modules/services/x11/window-managers/xmonad.nix b/nixos/modules/services/x11/window-managers/xmonad.nix
index 476621bad778c..f616802acc445 100644
--- a/nixos/modules/services/x11/window-managers/xmonad.nix
+++ b/nixos/modules/services/x11/window-managers/xmonad.nix
@@ -30,7 +30,7 @@ let
         install -D ${xmonadEnv}/share/man/man1/xmonad.1.gz $out/share/man/man1/xmonad.1.gz
         makeWrapper ${configured}/bin/xmonad $out/bin/xmonad \
       '' + optionalString cfg.enableConfiguredRecompile ''
-          --set NIX_GHC "${xmonadEnv}/bin/ghc" \
+          --set XMONAD_GHC "${xmonadEnv}/bin/ghc" \
       '' + ''
           --set XMONAD_XMESSAGE "${pkgs.xorg.xmessage}/bin/xmessage"
       '');
@@ -46,7 +46,7 @@ in {
       haskellPackages = mkOption {
         default = pkgs.haskellPackages;
         defaultText = literalExpression "pkgs.haskellPackages";
-        example = literalExpression "pkgs.haskell.packages.ghc784";
+        example = literalExpression "pkgs.haskell.packages.ghc8107";
         type = types.attrs;
         description = ''
           haskellPackages used to build Xmonad and other packages.
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index 84f560691fc4d..87ff1d97d8fa8 100644
--- a/nixos/modules/system/activation/top-level.nix
+++ b/nixos/modules/system/activation/top-level.nix
@@ -335,7 +335,7 @@ in
       '';
       description = ''
         The name of the system used in the <option>system.build.toplevel</option> derivation.
-        </para><para>
+
         That derivation has the following name:
         <literal>"nixos-system-''${config.system.name}-''${config.system.nixos.label}"</literal>
       '';
diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix
index 43327fdd9da4b..a1017c3e24204 100644
--- a/nixos/modules/system/boot/initrd-network.nix
+++ b/nixos/modules/system/boot/initrd-network.nix
@@ -50,18 +50,17 @@ in
     boot.initrd.network.enable = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Add network connectivity support to initrd. The network may be
-        configured using the <literal>ip</literal> kernel parameter,
-        as described in <link
-        xlink:href="https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt">the
-        kernel documentation</link>.  Otherwise, if
-        <option>networking.useDHCP</option> is enabled, an IP address
+        configured using the `ip` kernel parameter,
+        as described in [the kernel documentation](https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt).
+        Otherwise, if
+        {option}`networking.useDHCP` is enabled, an IP address
         is acquired using DHCP.
 
         You should add the module(s) required for your network card to
         boot.initrd.availableKernelModules.
-        <literal>lspci -v | grep -iA8 'network\|ethernet'</literal>
+        `lspci -v | grep -iA8 'network\|ethernet'`
         will tell you which.
       '';
     };
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index 00ec3d237d532..1ad7cd8109488 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -624,9 +624,9 @@ in
         type = types.bool;
         description = ''
           Whether to invoke <literal>grub-install</literal> with
-          <literal>--removable</literal>.</para>
+          <literal>--removable</literal>.
 
-          <para>Unless you turn this on, GRUB will install itself somewhere in
+          Unless you turn this on, GRUB will install itself somewhere in
           <literal>boot.loader.efi.efiSysMountPoint</literal> (exactly where
           depends on other config variables). If you've set
           <literal>boot.loader.efi.canTouchEfiVariables</literal> *AND* you
@@ -637,14 +637,14 @@ in
           NVRAM will not be modified, and your system will not find GRUB at
           boot time. However, GRUB will still return success so you may miss
           the warning that gets printed ("<literal>efibootmgr: EFI variables
-          are not supported on this system.</literal>").</para>
+          are not supported on this system.</literal>").
 
-          <para>If you turn this feature on, GRUB will install itself in a
+          If you turn this feature on, GRUB will install itself in a
           special location within <literal>efiSysMountPoint</literal> (namely
           <literal>EFI/boot/boot$arch.efi</literal>) which the firmwares
-          are hardcoded to try first, regardless of NVRAM EFI variables.</para>
+          are hardcoded to try first, regardless of NVRAM EFI variables.
 
-          <para>To summarize, turn this on if:
+          To summarize, turn this on if:
           <itemizedlist>
             <listitem><para>You are installing NixOS and want it to boot in UEFI mode,
             but you are currently booted in legacy mode</para></listitem>
diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix
index 95556710bdef3..78301a57bd970 100644
--- a/nixos/modules/system/boot/luksroot.nix
+++ b/nixos/modules/system/boot/luksroot.nix
@@ -433,7 +433,7 @@ let
           echo "Please move your mouse to create needed randomness."
         ''}
           echo "Waiting for your FIDO2 device..."
-          fido2luks open ${dev.device} ${dev.name} ${dev.fido2.credential} --await-dev ${toString dev.fido2.gracePeriod} --salt string:$passphrase
+          fido2luks open${optionalString dev.allowDiscards " --allow-discards"} ${dev.device} ${dev.name} ${dev.fido2.credential} --await-dev ${toString dev.fido2.gracePeriod} --salt string:$passphrase
         if [ $? -ne 0 ]; then
           echo "No FIDO2 key found, falling back to normal open procedure"
           open_normally
@@ -548,11 +548,11 @@ in
     boot.initrd.luks.devices = mkOption {
       default = { };
       example = { luksroot.device = "/dev/disk/by-uuid/430e9eff-d852-4f68-aa3b-2fa3599ebe08"; };
-      description = ''
+      description = lib.mdDoc ''
         The encrypted disk that should be opened before the root
         filesystem is mounted. Both LVM-over-LUKS and LUKS-over-LVM
         setups are supported. The unencrypted devices can be accessed as
-        <filename>/dev/mapper/<replaceable>name</replaceable></filename>.
+        {file}`/dev/mapper/«name»`.
       '';
 
       type = with types; attrsOf (submodule (
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index b006ce77454fc..dd4c63ab7256e 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -1170,8 +1170,7 @@ let
         <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
         <manvolnum>5</manvolnum></citerefentry> for details.
         A detailed explanation about how VRFs work can be found in the
-        <link xlink:href="https://www.kernel.org/doc/Documentation/networking/vrf.txt">kernel
-        docs</link>.
+        <link xlink:href="https://www.kernel.org/doc/Documentation/networking/vrf.txt">kernel docs</link>.
       '';
     };
 
@@ -1388,7 +1387,7 @@ let
 
     dhcpServerStaticLeases = mkOption {
       default = [];
-      example = [ { MACAddress = "65:43:4a:5b:d8:5f"; Address = "192.168.1.42"; } ];
+      example = [ { dhcpServerStaticLeaseConfig = { MACAddress = "65:43:4a:5b:d8:5f"; Address = "192.168.1.42"; }; } ];
       type = with types; listOf (submodule dhcpServerStaticLeaseOptions);
       description = ''
         A list of DHCPServerStaticLease sections to be added to the unit.  See
@@ -1399,7 +1398,7 @@ let
 
     ipv6Prefixes = mkOption {
       default = [];
-      example = [ { AddressAutoconfiguration = true; OnLink = true; } ];
+      example = [ { ipv6PrefixConfig = { AddressAutoconfiguration = true; OnLink = true; }; } ];
       type = with types; listOf (submodule ipv6PrefixOptions);
       description = ''
         A list of ipv6Prefix sections to be added to the unit.  See
@@ -1905,13 +1904,11 @@ in
       };
 
       extraArgs = mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Extra command-line arguments to pass to systemd-networkd-wait-online.
-          These also affect per-interface <literal>systemd-network-wait-online@</literal> services.
+          These also affect per-interface `systemd-network-wait-online@` services.
 
-          See <link xlink:href="https://www.freedesktop.org/software/systemd/man/systemd-networkd-wait-online.service.html">
-          <citerefentry><refentrytitle>systemd-networkd-wait-online.service</refentrytitle><manvolnum>8</manvolnum>
-          </citerefentry></link> for all available options.
+          See [{manpage}`systemd-networkd-wait-online.service(8)`](https://www.freedesktop.org/software/systemd/man/systemd-networkd-wait-online.service.html) for all available options.
         '';
         type = with types; listOf str;
         default = [];
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index f3b9d798f6148..ec2f3d18c6850 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -480,7 +480,7 @@ in
         if you want to resume from file. If left empty, the swap partitions are used.
         Specify here the device where the file resides.
         You should also use <varname>boot.kernelParams</varname> to specify
-        <literal><replaceable>resume_offset</replaceable></literal>.
+        <literal>«resume_offset»</literal>.
       '';
     };
 
diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix
index f7c4d0c3a3e35..0351453a6587b 100644
--- a/nixos/modules/system/boot/systemd/initrd.nix
+++ b/nixos/modules/system/boot/systemd/initrd.nix
@@ -130,6 +130,7 @@ let
   initialRamdisk = pkgs.makeInitrdNG {
     name = "initrd-${kernel-name}";
     inherit (config.boot.initrd) compressor compressorArgs prepend;
+    inherit (cfg) strip;
 
     contents = map (path: { object = path; symlink = ""; }) (subtractLists cfg.suppressedStorePaths cfg.storePaths)
       ++ mapAttrsToList (_: v: { object = v.source; symlink = v.target; }) (filterAttrs (_: v: v.enable) cfg.contents);
@@ -170,6 +171,19 @@ in {
       default = [];
     };
 
+    strip = mkOption {
+      description = lib.mdDoc ''
+        Whether to completely strip executables and libraries copied to the initramfs.
+
+        Setting this to false may save on the order of 30MiB on the
+        machine building the system (by avoiding a binutils
+        reference), at the cost of ~1MiB of initramfs size. This puts
+        this option firmly in the territory of micro-optimisation.
+      '';
+      type = types.bool;
+      default = true;
+    };
+
     extraBin = mkOption {
       description = lib.mdDoc ''
         Tools to add to /bin
diff --git a/nixos/modules/system/boot/systemd/logind.nix b/nixos/modules/system/boot/systemd/logind.nix
index cb8fc448a9ef0..5980160321367 100644
--- a/nixos/modules/system/boot/systemd/logind.nix
+++ b/nixos/modules/system/boot/systemd/logind.nix
@@ -26,17 +26,14 @@ in
     services.logind.killUserProcesses = mkOption {
       default = false;
       type = types.bool;
-      description = ''
+      description = lib.mdDoc ''
         Specifies whether the processes of a user should be killed
         when the user logs out.  If true, the scope unit corresponding
         to the session and all processes inside that scope will be
         terminated.  If false, the scope is "abandoned" (see
-        <link xlink:href="https://www.freedesktop.org/software/systemd/man/systemd.scope.html#">
-        systemd.scope(5)</link>), and processes are not killed.
-        </para>
+        [systemd.scope(5)](https://www.freedesktop.org/software/systemd/man/systemd.scope.html#)), and processes are not killed.
 
-        <para>
-        See <link xlink:href="https://www.freedesktop.org/software/systemd/man/logind.conf.html#KillUserProcesses=">logind.conf(5)</link>
+        See [logind.conf(5)](https://www.freedesktop.org/software/systemd/man/logind.conf.html#KillUserProcesses=)
         for more details.
       '';
     };
diff --git a/nixos/modules/system/boot/systemd/tmpfiles.nix b/nixos/modules/system/boot/systemd/tmpfiles.nix
index eaa0ddf638782..e990e953b0572 100644
--- a/nixos/modules/system/boot/systemd/tmpfiles.nix
+++ b/nixos/modules/system/boot/systemd/tmpfiles.nix
@@ -25,16 +25,16 @@ in
       default = [];
       example = literalExpression "[ pkgs.lvm2 ]";
       apply = map getLib;
-      description = ''
-        List of packages containing <command>systemd-tmpfiles</command> rules.
+      description = lib.mdDoc ''
+        List of packages containing {command}`systemd-tmpfiles` rules.
 
         All files ending in .conf found in
-        <filename><replaceable>pkg</replaceable>/lib/tmpfiles.d</filename>
+        {file}`«pkg»/lib/tmpfiles.d`
         will be included.
         If this folder does not exist or does not contain any files an error will be returned instead.
 
-        If a <filename>lib</filename> output is available, rules are searched there and only there.
-        If there is no <filename>lib</filename> output it will fall back to <filename>out</filename>
+        If a {file}`lib` output is available, rules are searched there and only there.
+        If there is no {file}`lib` output it will fall back to {file}`out`
         and if that does not exist either, the default output will be used.
       '';
     };
diff --git a/nixos/modules/tasks/auto-upgrade.nix b/nixos/modules/tasks/auto-upgrade.nix
index 46a30c53ea889..ca2690167830a 100644
--- a/nixos/modules/tasks/auto-upgrade.nix
+++ b/nixos/modules/tasks/auto-upgrade.nix
@@ -25,10 +25,10 @@ in {
         type = types.enum ["switch" "boot"];
         default = "switch";
         example = "boot";
-        description = ''
+        description = lib.mdDoc ''
           Whether to run
-          <literal>nixos-rebuild switch --upgrade</literal> or run
-          <literal>nixos-rebuild boot --upgrade</literal>
+          `nixos-rebuild switch --upgrade` or run
+          `nixos-rebuild boot --upgrade`
         '';
       };
 
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index e6cb2daaffca8..a462035329487 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -1292,7 +1292,7 @@ in
       description = ''
         Whether to enable IPv6 Privacy Extensions for interfaces not
         configured explicitly in
-        <xref linkend="opt-networking.interfaces._name_.tempAddress" />.
+        <xref linkend="opt-networking.interfaces._name_.tempAddress"/>.
 
         This sets the ipv6.conf.*.use_tempaddr sysctl for all
         interfaces. Possible values are:
diff --git a/nixos/modules/tasks/scsi-link-power-management.nix b/nixos/modules/tasks/scsi-link-power-management.nix
index a9d987780ee1c..a5395657e9920 100644
--- a/nixos/modules/tasks/scsi-link-power-management.nix
+++ b/nixos/modules/tasks/scsi-link-power-management.nix
@@ -25,10 +25,10 @@ in
     powerManagement.scsiLinkPolicy = mkOption {
       default = null;
       type = types.nullOr (types.enum allowedValues);
-      description = ''
+      description = lib.mdDoc ''
         SCSI link power management policy. The kernel default is
         "max_performance".
-        </para><para>
+
         "med_power_with_dipm" is supported by kernel versions
         4.15 and newer.
       '';
diff --git a/nixos/modules/virtualisation/nixos-containers.nix b/nixos/modules/virtualisation/nixos-containers.nix
index e2fb28ed63321..6b8c21336c6b3 100644
--- a/nixos/modules/virtualisation/nixos-containers.nix
+++ b/nixos/modules/virtualisation/nixos-containers.nix
@@ -579,11 +579,11 @@ in
             privateNetwork = mkOption {
               type = types.bool;
               default = false;
-              description = ''
+              description = lib.mdDoc ''
                 Whether to give the container its own private virtual
                 Ethernet interface.  The interface is called
-                <literal>eth0</literal>, and is hooked up to the interface
-                <literal>ve-<replaceable>container-name</replaceable></literal>
+                `eth0`, and is hooked up to the interface
+                `ve-«container-name»`
                 on the host.  If this option is not set, then the
                 container shares the network interfaces of the host,
                 and can bind to any port on any interface.
@@ -728,12 +728,12 @@ in
               };
           }
         '';
-      description = ''
+      description = lib.mdDoc ''
         A set of NixOS system configurations to be run as lightweight
         containers.  Each container appears as a service
-        <literal>container-<replaceable>name</replaceable></literal>
+        `container-«name»`
         on the host system, allowing it to be started and stopped via
-        <command>systemctl</command>.
+        {command}`systemctl`.
       '';
     };
 
diff --git a/nixos/modules/virtualisation/podman/default.nix b/nixos/modules/virtualisation/podman/default.nix
index 361caeff70bef..1e2f8a7fae64f 100644
--- a/nixos/modules/virtualisation/podman/default.nix
+++ b/nixos/modules/virtualisation/podman/default.nix
@@ -74,7 +74,7 @@ in
 
         Podman implements the Docker API.
 
-        Users must be in the <code>podman</code> group in order to connect. As
+        Users must be in the <literal>podman</literal> group in order to connect. As
         with Docker, members of this group can gain root access.
       '';
     };
diff --git a/nixos/modules/virtualisation/podman/network-socket.nix b/nixos/modules/virtualisation/podman/network-socket.nix
index 94d8da9d2b614..5f6ce493558b9 100644
--- a/nixos/modules/virtualisation/podman/network-socket.nix
+++ b/nixos/modules/virtualisation/podman/network-socket.nix
@@ -22,7 +22,7 @@ in
         with TLS client certificate authentication.
 
         This allows Docker clients to connect with the equivalents of the Docker
-        CLI <code>-H</code> and <code>--tls*</code> family of options.
+        CLI <literal>-H</literal> and <literal>--tls*</literal> family of options.
 
         For certificate setup, see https://docs.docker.com/engine/security/protect-access/
 
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 5b2d81eeb68fc..98617a397a592 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -516,12 +516,12 @@ in
         description =
           ''
             Virtual networks to which the VM is connected.  Each
-            number <replaceable>N</replaceable> in this list causes
+            number «N» in this list causes
             the VM to have a virtual Ethernet interface attached to a
             separate virtual network on which it will be assigned IP
             address
-            <literal>192.168.<replaceable>N</replaceable>.<replaceable>M</replaceable></literal>,
-            where <replaceable>M</replaceable> is the index of this VM
+            <literal>192.168.«N».«M»</literal>,
+            where «M» is the index of this VM
             in the list of VMs.
           '';
       };
diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix
index 7f81ca1c69b88..e8677f7e1e975 100644
--- a/nixos/release-combined.nix
+++ b/nixos/release-combined.nix
@@ -43,7 +43,7 @@ in rec {
       name = "nixos-${nixos.channel.version}";
       meta = {
         description = "Release-critical builds for the NixOS channel";
-        maintainers = with pkgs.lib.maintainers; [ eelco fpletz ];
+        maintainers = with pkgs.lib.maintainers; [ eelco ];
       };
       constituents = pkgs.lib.concatLists [
         [ "nixos.channel" ]
diff --git a/nixos/tests/couchdb.nix b/nixos/tests/couchdb.nix
index 453f5dcd66e86..b57072d6be2dd 100644
--- a/nixos/tests/couchdb.nix
+++ b/nixos/tests/couchdb.nix
@@ -20,7 +20,7 @@ with lib;
 {
   name = "couchdb";
   meta = with pkgs.lib.maintainers; {
-    maintainers = [ fpletz ];
+    maintainers = [ ];
   };
 
   nodes = {
diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix
index 99a968f17af2f..d76f70b791cec 100644
--- a/nixos/tests/docker-tools.nix
+++ b/nixos/tests/docker-tools.nix
@@ -346,7 +346,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
             "docker load --input='${examples.layeredImageWithFakeRootCommands}'"
         )
         docker.succeed(
-            "docker run --rm ${examples.layeredImageWithFakeRootCommands.imageName} sh -c 'stat -c '%u' /home/jane | grep -E ^1000$'"
+            "docker run --rm ${examples.layeredImageWithFakeRootCommands.imageName} sh -c 'stat -c '%u' /home/alice | grep -E ^1000$'"
         )
 
     with subtest("Ensure docker load on merged images loads all of the constituent images"):
@@ -389,7 +389,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
             "docker load --input='${examples.mergedBashFakeRoot}'"
         )
         docker.succeed(
-            "docker run --rm ${examples.layeredImageWithFakeRootCommands.imageName} sh -c 'stat -c '%u' /home/jane | grep -E ^1000$'"
+            "docker run --rm ${examples.layeredImageWithFakeRootCommands.imageName} sh -c 'stat -c '%u' /home/alice | grep -E ^1000$'"
         )
 
     with subtest("The image contains store paths referenced by the fakeRootCommands output"):
diff --git a/nixos/tests/documize.nix b/nixos/tests/documize.nix
index 528bf5338ce0d..fda79b1a09318 100644
--- a/nixos/tests/documize.nix
+++ b/nixos/tests/documize.nix
@@ -47,9 +47,9 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
             " --data 'dbhash={}'"
             " --data 'title=NixOS'"
             " --data 'message=Docs'"
-            " --data 'firstname=John'"
-            " --data 'lastname=Doe'"
-            " --data 'email=john.doe@nixos.org'"
+            " --data 'firstname=Bob'"
+            " --data 'lastname=Foobar'"
+            " --data 'email=bob.foobar@nixos.org'"
             " --data 'password=verysafe'"
             " -f localhost:3000/api/setup"
         ).format(dbhash)
diff --git a/nixos/tests/nginx-auth.nix b/nixos/tests/nginx-auth.nix
index c0d24a20ddbcc..a85426dda8717 100644
--- a/nixos/tests/nginx-auth.nix
+++ b/nixos/tests/nginx-auth.nix
@@ -13,14 +13,14 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
         virtualHosts.lockedroot = {
           inherit root;
-          basicAuth.alice = "jane";
+          basicAuth.alice = "pwofa";
         };
 
         virtualHosts.lockedsubdir = {
           inherit root;
           locations."/sublocation/" = {
             alias = "${root}/";
-            basicAuth.bob = "john";
+            basicAuth.bob = "pwofb";
           };
         };
       };
@@ -33,7 +33,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
     webserver.fail("curl --fail --resolve lockedroot:80:127.0.0.1 http://lockedroot")
     webserver.succeed(
-        "curl --fail --resolve lockedroot:80:127.0.0.1 http://alice:jane@lockedroot"
+        "curl --fail --resolve lockedroot:80:127.0.0.1 http://alice:pwofa@lockedroot"
     )
 
     webserver.succeed("curl --fail --resolve lockedsubdir:80:127.0.0.1 http://lockedsubdir")
@@ -41,7 +41,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
         "curl --fail --resolve lockedsubdir:80:127.0.0.1 http://lockedsubdir/sublocation/index.html"
     )
     webserver.succeed(
-        "curl --fail --resolve lockedsubdir:80:127.0.0.1 http://bob:john@lockedsubdir/sublocation/index.html"
+        "curl --fail --resolve lockedsubdir:80:127.0.0.1 http://bob:pwofb@lockedsubdir/sublocation/index.html"
     )
   '';
 })
diff --git a/nixos/tests/privacyidea.nix b/nixos/tests/privacyidea.nix
index fb072514dd90f..401ad72c37b72 100644
--- a/nixos/tests/privacyidea.nix
+++ b/nixos/tests/privacyidea.nix
@@ -3,7 +3,7 @@
 import ./make-test-python.nix ({ pkgs, ...} : rec {
   name = "privacyidea";
   meta = with pkgs.lib.maintainers; {
-    maintainers = [ fpletz ];
+    maintainers = [ ];
   };
 
   nodes.machine = { ... }: {
diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix
index 0a1ec824986ab..d14c737a4bd11 100644
--- a/nixos/tests/prometheus-exporters.nix
+++ b/nixos/tests/prometheus-exporters.nix
@@ -35,7 +35,7 @@ let
     *      };
     *      exporterTest = ''
     *        wait_for_unit("prometheus-<exporterName>-exporter.service")
-    *        wait_for_open_port("1234")
+    *        wait_for_open_port(1234)
     *        succeed("curl -sSf 'localhost:1234/metrics'")
     *      '';
     *    };
@@ -1063,7 +1063,7 @@ let
       };
       exporterTest = ''
         wait_for_unit("prometheus-smartctl-exporter.service")
-        wait_for_open_port("9633")
+        wait_for_open_port(9633)
         wait_until_succeeds(
           "curl -sSf 'localhost:9633/metrics'"
         )
diff --git a/nixos/tests/sympa.nix b/nixos/tests/sympa.nix
index 76ca17d0a1890..80daa4134f75a 100644
--- a/nixos/tests/sympa.nix
+++ b/nixos/tests/sympa.nix
@@ -13,7 +13,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
             webHost = "localhost";
           };
         };
-        listMasters = [ "joe@example.org" ];
+        listMasters = [ "bob@example.org" ];
         web.enable = true;
         web.https = false;
         database = {
diff --git a/nixos/tests/systemd-nspawn.nix b/nixos/tests/systemd-nspawn.nix
index c2cb92d11301c..bc77ee2a4d158 100644
--- a/nixos/tests/systemd-nspawn.nix
+++ b/nixos/tests/systemd-nspawn.nix
@@ -10,8 +10,8 @@ let
       Key-Length: 1024
       Subkey-Type: ELG-E
       Subkey-Length: 1024
-      Name-Real: Joe Tester
-      Name-Email: joe@foo.bar
+      Name-Real: Bob Foobar
+      Name-Email: bob@foo.bar
       Expire-Date: 0
       # Do a commit here, so that we can later print "done"
       %commit
@@ -19,7 +19,7 @@ let
     EOF
     gpg --batch --generate-key foo
     rm $out/S.gpg-agent $out/S.gpg-agent.*
-    gpg --export joe@foo.bar -a > $out/pubkey.gpg
+    gpg --export bob@foo.bar -a > $out/pubkey.gpg
   '');
 
   nspawnImages = (pkgs.runCommand "localhost" { buildInputs = [ pkgs.coreutils pkgs.gnupg ]; } ''
diff --git a/nixos/tests/xmpp/xmpp-sendmessage.nix b/nixos/tests/xmpp/xmpp-sendmessage.nix
index 80dfcff2d0ebc..4c009464b7041 100644
--- a/nixos/tests/xmpp/xmpp-sendmessage.nix
+++ b/nixos/tests/xmpp/xmpp-sendmessage.nix
@@ -6,7 +6,7 @@ let
     Please find this *really* important attachment.
 
     Yours truly,
-    John
+    Bob
   '';
 in writeScriptBin "send-message" ''
 #!${(python3.withPackages (ps: [ ps.slixmpp ])).interpreter}