summary refs log tree commit diff
path: root/nixos/modules/services/web-apps
diff options
context:
space:
mode:
authorpennae <github@quasiparticle.net>2022-07-28 23:19:15 +0200
committerpennae <github@quasiparticle.net>2022-07-30 15:16:34 +0200
commit2e751c0772b9d48ff6923569adfa661b030ab6a2 (patch)
tree0accd740380b7b7fe3ea5965a3a4517674e79260 /nixos/modules/services/web-apps
parent52b0ad17e3727fe0c3ca028787128ede5fb86352 (diff)
downloadnixpkgs-2e751c0772b9d48ff6923569adfa661b030ab6a2.tar
nixpkgs-2e751c0772b9d48ff6923569adfa661b030ab6a2.tar.gz
nixpkgs-2e751c0772b9d48ff6923569adfa661b030ab6a2.tar.bz2
nixpkgs-2e751c0772b9d48ff6923569adfa661b030ab6a2.tar.lz
nixpkgs-2e751c0772b9d48ff6923569adfa661b030ab6a2.tar.xz
nixpkgs-2e751c0772b9d48ff6923569adfa661b030ab6a2.tar.zst
nixpkgs-2e751c0772b9d48ff6923569adfa661b030ab6a2.zip
treewide: automatically md-convert option descriptions
the conversion procedure is simple:

 - find all things that look like options, ie calls to either `mkOption`
   or `lib.mkOption` that take an attrset. remember the attrset as the
   option
 - for all options, find a `description` attribute who's value is not a
   call to `mdDoc` or `lib.mdDoc`
 - textually convert the entire value of the attribute to MD with a few
   simple regexes (the set from mdize-module.sh)
 - if the change produced a change in the manual output, discard
 - if the change kept the manual unchanged, add some text to the
   description to make sure we've actually found an option. if the
   manual changes this time, keep the converted description

this procedure converts 80% of nixos options to markdown. around 2000
options remain to be inspected, but most of those fail the "does not
change the manual output check": currently the MD conversion process
does not faithfully convert docbook tags like <code> and <package>, so
any option using such tags will not be converted at all.
Diffstat (limited to 'nixos/modules/services/web-apps')
-rw-r--r--nixos/modules/services/web-apps/atlassian/confluence.nix32
-rw-r--r--nixos/modules/services/web-apps/atlassian/crowd.nix28
-rw-r--r--nixos/modules/services/web-apps/atlassian/jira.nix32
-rw-r--r--nixos/modules/services/web-apps/baget.nix6
-rw-r--r--nixos/modules/services/web-apps/calibre-web.nix24
-rw-r--r--nixos/modules/services/web-apps/code-server.nix26
-rw-r--r--nixos/modules/services/web-apps/convos.nix10
-rw-r--r--nixos/modules/services/web-apps/dex.nix4
-rw-r--r--nixos/modules/services/web-apps/discourse.nix102
-rw-r--r--nixos/modules/services/web-apps/documize.nix26
-rw-r--r--nixos/modules/services/web-apps/dokuwiki.nix36
-rw-r--r--nixos/modules/services/web-apps/engelsystem.nix12
-rw-r--r--nixos/modules/services/web-apps/ethercalc.nix10
-rw-r--r--nixos/modules/services/web-apps/galene.nix26
-rw-r--r--nixos/modules/services/web-apps/gerrit.nix30
-rw-r--r--nixos/modules/services/web-apps/gotify-server.nix6
-rw-r--r--nixos/modules/services/web-apps/grocy.nix18
-rw-r--r--nixos/modules/services/web-apps/healthchecks.nix14
-rw-r--r--nixos/modules/services/web-apps/hedgedoc.nix276
-rw-r--r--nixos/modules/services/web-apps/hledger-web.nix20
-rw-r--r--nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix20
-rw-r--r--nixos/modules/services/web-apps/icingaweb2/module-monitoring.nix34
-rw-r--r--nixos/modules/services/web-apps/ihatemoney/default.nix20
-rw-r--r--nixos/modules/services/web-apps/invidious.nix30
-rw-r--r--nixos/modules/services/web-apps/invoiceplane.nix30
-rw-r--r--nixos/modules/services/web-apps/jitsi-meet.nix48
-rw-r--r--nixos/modules/services/web-apps/keycloak.nix52
-rw-r--r--nixos/modules/services/web-apps/lemmy.nix14
-rw-r--r--nixos/modules/services/web-apps/mastodon.nix66
-rw-r--r--nixos/modules/services/web-apps/mattermost.nix34
-rw-r--r--nixos/modules/services/web-apps/miniflux.nix6
-rw-r--r--nixos/modules/services/web-apps/netbox.nix32
-rw-r--r--nixos/modules/services/web-apps/nextcloud.nix100
-rw-r--r--nixos/modules/services/web-apps/nexus.nix12
-rw-r--r--nixos/modules/services/web-apps/nifi.nix24
-rw-r--r--nixos/modules/services/web-apps/node-red.nix18
-rw-r--r--nixos/modules/services/web-apps/onlyoffice.nix20
-rw-r--r--nixos/modules/services/web-apps/openwebrx.nix2
-rw-r--r--nixos/modules/services/web-apps/peertube.nix46
-rw-r--r--nixos/modules/services/web-apps/phylactery.nix8
-rw-r--r--nixos/modules/services/web-apps/pict-rs.nix6
-rw-r--r--nixos/modules/services/web-apps/plantuml-server.nix26
-rw-r--r--nixos/modules/services/web-apps/plausible.nix44
-rw-r--r--nixos/modules/services/web-apps/powerdns-admin.nix10
-rw-r--r--nixos/modules/services/web-apps/prosody-filer.nix4
-rw-r--r--nixos/modules/services/web-apps/restya-board.nix32
-rw-r--r--nixos/modules/services/web-apps/rss-bridge.nix12
-rw-r--r--nixos/modules/services/web-apps/selfoss.nix18
-rw-r--r--nixos/modules/services/web-apps/shiori.nix6
-rw-r--r--nixos/modules/services/web-apps/sogo.nix12
-rw-r--r--nixos/modules/services/web-apps/trilium.nix16
-rw-r--r--nixos/modules/services/web-apps/tt-rss.nix86
-rw-r--r--nixos/modules/services/web-apps/vikunja.nix34
-rw-r--r--nixos/modules/services/web-apps/virtlyst.nix4
-rw-r--r--nixos/modules/services/web-apps/whitebophir.nix6
-rw-r--r--nixos/modules/services/web-apps/wiki-js.nix16
-rw-r--r--nixos/modules/services/web-apps/youtrack.nix20
57 files changed, 853 insertions, 853 deletions
diff --git a/nixos/modules/services/web-apps/atlassian/confluence.nix b/nixos/modules/services/web-apps/atlassian/confluence.nix
index 4aad307731a..6c5de3fbe4b 100644
--- a/nixos/modules/services/web-apps/atlassian/confluence.nix
+++ b/nixos/modules/services/web-apps/atlassian/confluence.nix
@@ -34,38 +34,38 @@ in
       user = mkOption {
         type = types.str;
         default = "confluence";
-        description = "User which runs confluence.";
+        description = lib.mdDoc "User which runs confluence.";
       };
 
       group = mkOption {
         type = types.str;
         default = "confluence";
-        description = "Group which runs confluence.";
+        description = lib.mdDoc "Group which runs confluence.";
       };
 
       home = mkOption {
         type = types.str;
         default = "/var/lib/confluence";
-        description = "Home directory of the confluence instance.";
+        description = lib.mdDoc "Home directory of the confluence instance.";
       };
 
       listenAddress = mkOption {
         type = types.str;
         default = "127.0.0.1";
-        description = "Address to listen on.";
+        description = lib.mdDoc "Address to listen on.";
       };
 
       listenPort = mkOption {
         type = types.int;
         default = 8090;
-        description = "Port to listen on.";
+        description = lib.mdDoc "Port to listen on.";
       };
 
       catalinaOptions = mkOption {
         type = types.listOf types.str;
         default = [];
         example = [ "-Xms1024m" "-Xmx2048m" "-Dconfluence.disable.peopledirectory.all=true" ];
-        description = "Java options to pass to catalina/tomcat.";
+        description = lib.mdDoc "Java options to pass to catalina/tomcat.";
       };
 
       proxy = {
@@ -74,21 +74,21 @@ in
         name = mkOption {
           type = types.str;
           example = "confluence.example.com";
-          description = "Virtual hostname at the proxy";
+          description = lib.mdDoc "Virtual hostname at the proxy";
         };
 
         port = mkOption {
           type = types.int;
           default = 443;
           example = 80;
-          description = "Port used at the proxy";
+          description = lib.mdDoc "Port used at the proxy";
         };
 
         scheme = mkOption {
           type = types.str;
           default = "https";
           example = "http";
-          description = "Protocol used at the proxy.";
+          description = lib.mdDoc "Protocol used at the proxy.";
         };
       };
 
@@ -98,32 +98,32 @@ in
         crowd = mkOption {
           type = types.str;
           example = "http://localhost:8095/crowd";
-          description = "Crowd Base URL without trailing slash";
+          description = lib.mdDoc "Crowd Base URL without trailing slash";
         };
 
         applicationName = mkOption {
           type = types.str;
           example = "jira";
-          description = "Exact name of this Confluence instance in Crowd";
+          description = lib.mdDoc "Exact name of this Confluence instance in Crowd";
         };
 
         applicationPassword = mkOption {
           type = types.nullOr types.str;
           default = null;
-          description = "Application password of this Confluence instance in Crowd";
+          description = lib.mdDoc "Application password of this Confluence instance in Crowd";
         };
 
         applicationPasswordFile = mkOption {
           type = types.nullOr types.str;
           default = null;
-          description = "Path to the application password for Crowd of Confluence.";
+          description = lib.mdDoc "Path to the application password for Crowd of Confluence.";
         };
 
         validationInterval = mkOption {
           type = types.int;
           default = 2;
           example = 0;
-          description = ''
+          description = lib.mdDoc ''
             Set to 0, if you want authentication checks to occur on each
             request. Otherwise set to the number of minutes between request
             to validate if the user is logged in or out of the Crowd SSO
@@ -137,14 +137,14 @@ in
         type = types.package;
         default = pkgs.atlassian-confluence;
         defaultText = literalExpression "pkgs.atlassian-confluence";
-        description = "Atlassian Confluence package to use.";
+        description = lib.mdDoc "Atlassian Confluence package to use.";
       };
 
       jrePackage = mkOption {
         type = types.package;
         default = pkgs.oraclejre8;
         defaultText = literalExpression "pkgs.oraclejre8";
-        description = "Note that Atlassian only support the Oracle JRE (JRASERVER-46152).";
+        description = lib.mdDoc "Note that Atlassian only support the Oracle JRE (JRASERVER-46152).";
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/atlassian/crowd.nix b/nixos/modules/services/web-apps/atlassian/crowd.nix
index 9418aff12ad..abe3a8bdb22 100644
--- a/nixos/modules/services/web-apps/atlassian/crowd.nix
+++ b/nixos/modules/services/web-apps/atlassian/crowd.nix
@@ -39,50 +39,50 @@ in
       user = mkOption {
         type = types.str;
         default = "crowd";
-        description = "User which runs Crowd.";
+        description = lib.mdDoc "User which runs Crowd.";
       };
 
       group = mkOption {
         type = types.str;
         default = "crowd";
-        description = "Group which runs Crowd.";
+        description = lib.mdDoc "Group which runs Crowd.";
       };
 
       home = mkOption {
         type = types.str;
         default = "/var/lib/crowd";
-        description = "Home directory of the Crowd instance.";
+        description = lib.mdDoc "Home directory of the Crowd instance.";
       };
 
       listenAddress = mkOption {
         type = types.str;
         default = "127.0.0.1";
-        description = "Address to listen on.";
+        description = lib.mdDoc "Address to listen on.";
       };
 
       listenPort = mkOption {
         type = types.int;
         default = 8092;
-        description = "Port to listen on.";
+        description = lib.mdDoc "Port to listen on.";
       };
 
       openidPassword = mkOption {
         type = types.str;
         default = "WILL_NEVER_BE_SET";
-        description = "Application password for OpenID server.";
+        description = lib.mdDoc "Application password for OpenID server.";
       };
 
       openidPasswordFile = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = "Path to the file containing the application password for OpenID server.";
+        description = lib.mdDoc "Path to the file containing the application password for OpenID server.";
       };
 
       catalinaOptions = mkOption {
         type = types.listOf types.str;
         default = [];
         example = [ "-Xms1024m" "-Xmx2048m" ];
-        description = "Java options to pass to catalina/tomcat.";
+        description = lib.mdDoc "Java options to pass to catalina/tomcat.";
       };
 
       proxy = {
@@ -91,27 +91,27 @@ in
         name = mkOption {
           type = types.str;
           example = "crowd.example.com";
-          description = "Virtual hostname at the proxy";
+          description = lib.mdDoc "Virtual hostname at the proxy";
         };
 
         port = mkOption {
           type = types.int;
           default = 443;
           example = 80;
-          description = "Port used at the proxy";
+          description = lib.mdDoc "Port used at the proxy";
         };
 
         scheme = mkOption {
           type = types.str;
           default = "https";
           example = "http";
-          description = "Protocol used at the proxy.";
+          description = lib.mdDoc "Protocol used at the proxy.";
         };
 
         secure = mkOption {
           type = types.bool;
           default = true;
-          description = "Whether the connections to the proxy should be considered secure.";
+          description = lib.mdDoc "Whether the connections to the proxy should be considered secure.";
         };
       };
 
@@ -119,14 +119,14 @@ in
         type = types.package;
         default = pkgs.atlassian-crowd;
         defaultText = literalExpression "pkgs.atlassian-crowd";
-        description = "Atlassian Crowd package to use.";
+        description = lib.mdDoc "Atlassian Crowd package to use.";
       };
 
       jrePackage = mkOption {
         type = types.package;
         default = pkgs.oraclejre8;
         defaultText = literalExpression "pkgs.oraclejre8";
-        description = "Note that Atlassian only support the Oracle JRE (JRASERVER-46152).";
+        description = lib.mdDoc "Note that Atlassian only support the Oracle JRE (JRASERVER-46152).";
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/atlassian/jira.nix b/nixos/modules/services/web-apps/atlassian/jira.nix
index fd89d763c7f..5d62160ffb1 100644
--- a/nixos/modules/services/web-apps/atlassian/jira.nix
+++ b/nixos/modules/services/web-apps/atlassian/jira.nix
@@ -34,38 +34,38 @@ in
       user = mkOption {
         type = types.str;
         default = "jira";
-        description = "User which runs JIRA.";
+        description = lib.mdDoc "User which runs JIRA.";
       };
 
       group = mkOption {
         type = types.str;
         default = "jira";
-        description = "Group which runs JIRA.";
+        description = lib.mdDoc "Group which runs JIRA.";
       };
 
       home = mkOption {
         type = types.str;
         default = "/var/lib/jira";
-        description = "Home directory of the JIRA instance.";
+        description = lib.mdDoc "Home directory of the JIRA instance.";
       };
 
       listenAddress = mkOption {
         type = types.str;
         default = "127.0.0.1";
-        description = "Address to listen on.";
+        description = lib.mdDoc "Address to listen on.";
       };
 
       listenPort = mkOption {
         type = types.int;
         default = 8091;
-        description = "Port to listen on.";
+        description = lib.mdDoc "Port to listen on.";
       };
 
       catalinaOptions = mkOption {
         type = types.listOf types.str;
         default = [];
         example = [ "-Xms1024m" "-Xmx2048m" ];
-        description = "Java options to pass to catalina/tomcat.";
+        description = lib.mdDoc "Java options to pass to catalina/tomcat.";
       };
 
       proxy = {
@@ -74,27 +74,27 @@ in
         name = mkOption {
           type = types.str;
           example = "jira.example.com";
-          description = "Virtual hostname at the proxy";
+          description = lib.mdDoc "Virtual hostname at the proxy";
         };
 
         port = mkOption {
           type = types.int;
           default = 443;
           example = 80;
-          description = "Port used at the proxy";
+          description = lib.mdDoc "Port used at the proxy";
         };
 
         scheme = mkOption {
           type = types.str;
           default = "https";
           example = "http";
-          description = "Protocol used at the proxy.";
+          description = lib.mdDoc "Protocol used at the proxy.";
         };
 
         secure = mkOption {
           type = types.bool;
           default = true;
-          description = "Whether the connections to the proxy should be considered secure.";
+          description = lib.mdDoc "Whether the connections to the proxy should be considered secure.";
         };
       };
 
@@ -104,25 +104,25 @@ in
         crowd = mkOption {
           type = types.str;
           example = "http://localhost:8095/crowd";
-          description = "Crowd Base URL without trailing slash";
+          description = lib.mdDoc "Crowd Base URL without trailing slash";
         };
 
         applicationName = mkOption {
           type = types.str;
           example = "jira";
-          description = "Exact name of this JIRA instance in Crowd";
+          description = lib.mdDoc "Exact name of this JIRA instance in Crowd";
         };
 
         applicationPasswordFile = mkOption {
           type = types.str;
-          description = "Path to the file containing the application password of this JIRA instance in Crowd";
+          description = lib.mdDoc "Path to the file containing the application password of this JIRA instance in Crowd";
         };
 
         validationInterval = mkOption {
           type = types.int;
           default = 2;
           example = 0;
-          description = ''
+          description = lib.mdDoc ''
             Set to 0, if you want authentication checks to occur on each
             request. Otherwise set to the number of minutes between request
             to validate if the user is logged in or out of the Crowd SSO
@@ -136,14 +136,14 @@ in
         type = types.package;
         default = pkgs.atlassian-jira;
         defaultText = literalExpression "pkgs.atlassian-jira";
-        description = "Atlassian JIRA package to use.";
+        description = lib.mdDoc "Atlassian JIRA package to use.";
       };
 
       jrePackage = mkOption {
         type = types.package;
         default = pkgs.oraclejre8;
         defaultText = literalExpression "pkgs.oraclejre8";
-        description = "Note that Atlassian only support the Oracle JRE (JRASERVER-46152).";
+        description = lib.mdDoc "Note that Atlassian only support the Oracle JRE (JRASERVER-46152).";
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/baget.nix b/nixos/modules/services/web-apps/baget.nix
index 3007dd4fbb2..dd70d462d57 100644
--- a/nixos/modules/services/web-apps/baget.nix
+++ b/nixos/modules/services/web-apps/baget.nix
@@ -58,7 +58,7 @@ in
     apiKeyFile = mkOption {
       type = types.path;
       example = "/root/baget.key";
-      description = ''
+      description = lib.mdDoc ''
         Private API key for BaGet.
       '';
     };
@@ -112,8 +112,8 @@ in
           };
         }
       '';
-      description = ''
-        Extra configuration options for BaGet. Refer to <link xlink:href="https://loic-sharma.github.io/BaGet/configuration/"/> for details.
+      description = lib.mdDoc ''
+        Extra configuration options for BaGet. Refer to <https://loic-sharma.github.io/BaGet/configuration/> for details.
         Default value is merged with values from here.
       '';
     };
diff --git a/nixos/modules/services/web-apps/calibre-web.nix b/nixos/modules/services/web-apps/calibre-web.nix
index 2bc817343a9..6bcf733452b 100644
--- a/nixos/modules/services/web-apps/calibre-web.nix
+++ b/nixos/modules/services/web-apps/calibre-web.nix
@@ -14,7 +14,7 @@ in
         ip = mkOption {
           type = types.str;
           default = "::1";
-          description = ''
+          description = lib.mdDoc ''
             IP address that Calibre-Web should listen on.
           '';
         };
@@ -22,7 +22,7 @@ in
         port = mkOption {
           type = types.port;
           default = 8083;
-          description = ''
+          description = lib.mdDoc ''
             Listen port for Calibre-Web.
           '';
         };
@@ -31,27 +31,27 @@ in
       dataDir = mkOption {
         type = types.str;
         default = "calibre-web";
-        description = ''
-          The directory below <filename>/var/lib</filename> where Calibre-Web stores its data.
+        description = lib.mdDoc ''
+          The directory below {file}`/var/lib` where Calibre-Web stores its data.
         '';
       };
 
       user = mkOption {
         type = types.str;
         default = "calibre-web";
-        description = "User account under which Calibre-Web runs.";
+        description = lib.mdDoc "User account under which Calibre-Web runs.";
       };
 
       group = mkOption {
         type = types.str;
         default = "calibre-web";
-        description = "Group account under which Calibre-Web runs.";
+        description = lib.mdDoc "Group account under which Calibre-Web runs.";
       };
 
       openFirewall = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Open ports in the firewall for the server.
         '';
       };
@@ -60,7 +60,7 @@ in
         calibreLibrary = mkOption {
           type = types.nullOr types.path;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             Path to Calibre library.
           '';
         };
@@ -68,7 +68,7 @@ in
         enableBookConversion = mkOption {
           type = types.bool;
           default = false;
-          description = ''
+          description = lib.mdDoc ''
             Configure path to the Calibre's ebook-convert in the DB.
           '';
         };
@@ -76,7 +76,7 @@ in
         enableBookUploading = mkOption {
           type = types.bool;
           default = false;
-          description = ''
+          description = lib.mdDoc ''
             Allow books to be uploaded via Calibre-Web UI.
           '';
         };
@@ -85,7 +85,7 @@ in
           enable = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Enable authorization using auth proxy.
             '';
           };
@@ -93,7 +93,7 @@ in
           header = mkOption {
             type = types.str;
             default = "";
-            description = ''
+            description = lib.mdDoc ''
               Auth proxy header name.
             '';
           };
diff --git a/nixos/modules/services/web-apps/code-server.nix b/nixos/modules/services/web-apps/code-server.nix
index 474e9140ae8..84fc03deabf 100644
--- a/nixos/modules/services/web-apps/code-server.nix
+++ b/nixos/modules/services/web-apps/code-server.nix
@@ -16,13 +16,13 @@ in {
       package = mkOption {
         default = pkgs.code-server;
         defaultText = "pkgs.code-server";
-        description = "Which code-server derivation to use.";
+        description = lib.mdDoc "Which code-server derivation to use.";
         type = types.package;
       };
 
       extraPackages = mkOption {
         default = [ ];
-        description = "Packages that are available in the PATH of code-server.";
+        description = lib.mdDoc "Packages that are available in the PATH of code-server.";
         example = "[ pkgs.go ]";
         type = types.listOf types.package;
       };
@@ -30,49 +30,49 @@ in {
       extraEnvironment = mkOption {
         type = types.attrsOf types.str;
         description =
-          "Additional environment variables to passed to code-server.";
+          lib.mdDoc "Additional environment variables to passed to code-server.";
         default = { };
         example = { PKG_CONFIG_PATH = "/run/current-system/sw/lib/pkgconfig"; };
       };
 
       extraArguments = mkOption {
         default = [ "--disable-telemetry" ];
-        description = "Additional arguments that passed to code-server";
+        description = lib.mdDoc "Additional arguments that passed to code-server";
         example = ''[ "--verbose" ]'';
         type = types.listOf types.str;
       };
 
       host = mkOption {
         default = "127.0.0.1";
-        description = "The host-ip to bind to.";
+        description = lib.mdDoc "The host-ip to bind to.";
         type = types.str;
       };
 
       port = mkOption {
         default = 4444;
-        description = "The port where code-server runs.";
+        description = lib.mdDoc "The port where code-server runs.";
         type = types.port;
       };
 
       auth = mkOption {
         default = "password";
-        description = "The type of authentication to use.";
+        description = lib.mdDoc "The type of authentication to use.";
         type = types.enum [ "none" "password" ];
       };
 
       hashedPassword = mkOption {
         default = "";
         description =
-          "Create the password with: 'echo -n 'thisismypassword' | npx argon2-cli -e'.";
+          lib.mdDoc "Create the password with: 'echo -n 'thisismypassword' | npx argon2-cli -e'.";
         type = types.str;
       };
 
       user = mkOption {
         default = defaultUser;
         example = "yourUser";
-        description = ''
+        description = lib.mdDoc ''
           The user to run code-server as.
-          By default, a user named <literal>${defaultUser}</literal> will be created.
+          By default, a user named `${defaultUser}` will be created.
         '';
         type = types.str;
       };
@@ -80,9 +80,9 @@ in {
       group = mkOption {
         default = defaultGroup;
         example = "yourGroup";
-        description = ''
+        description = lib.mdDoc ''
           The group to run code-server under.
-          By default, a group named <literal>${defaultGroup}</literal> will be created.
+          By default, a group named `${defaultGroup}` will be created.
         '';
         type = types.str;
       };
@@ -90,7 +90,7 @@ in {
       extraGroups = mkOption {
         default = [ ];
         description =
-          "An array of additional groups for the <literal>${defaultUser}</literal> user.";
+          lib.mdDoc "An array of additional groups for the `${defaultUser}` user.";
         example = [ "docker" ];
         type = types.listOf types.str;
       };
diff --git a/nixos/modules/services/web-apps/convos.nix b/nixos/modules/services/web-apps/convos.nix
index 8be11eec9f3..120481c6401 100644
--- a/nixos/modules/services/web-apps/convos.nix
+++ b/nixos/modules/services/web-apps/convos.nix
@@ -12,21 +12,21 @@ in
       type = types.port;
       default = 3000;
       example = 8080;
-      description = "Port the web interface should listen on";
+      description = lib.mdDoc "Port the web interface should listen on";
     };
     listenAddress = mkOption {
       type = types.str;
       default = "*";
       example = "127.0.0.1";
-      description = "Address or host the web interface should listen on";
+      description = lib.mdDoc "Address or host the web interface should listen on";
     };
     reverseProxy = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Enables reverse proxy support. This will allow Convos to automatically
-        pick up the <literal>X-Forwarded-For</literal> and
-        <literal>X-Request-Base</literal> HTTP headers set in your reverse proxy
+        pick up the `X-Forwarded-For` and
+        `X-Request-Base` HTTP headers set in your reverse proxy
         web server. Note that enabling this option without a reverse proxy in
         front will be a security issue.
       '';
diff --git a/nixos/modules/services/web-apps/dex.nix b/nixos/modules/services/web-apps/dex.nix
index 4d4689a4cf2..eebf4b740c7 100644
--- a/nixos/modules/services/web-apps/dex.nix
+++ b/nixos/modules/services/web-apps/dex.nix
@@ -45,9 +45,9 @@ in
           ];
         }
       '';
-      description = ''
+      description = lib.mdDoc ''
         The available options can be found in
-        <link xlink:href="https://github.com/dexidp/dex/blob/v${pkgs.dex.version}/config.yaml.dist">the example configuration</link>.
+        [the example configuration](https://github.com/dexidp/dex/blob/v${pkgs.dex.version}/config.yaml.dist).
       '';
     };
   };
diff --git a/nixos/modules/services/web-apps/discourse.nix b/nixos/modules/services/web-apps/discourse.nix
index 7dbbf4a12fe..20ad653429a 100644
--- a/nixos/modules/services/web-apps/discourse.nix
+++ b/nixos/modules/services/web-apps/discourse.nix
@@ -35,7 +35,7 @@ in
           plugins = lib.unique (p.enabledPlugins ++ cfg.plugins);
         };
         defaultText = lib.literalExpression "pkgs.discourse";
-        description = ''
+        description = lib.mdDoc ''
           The discourse package to use.
         '';
       };
@@ -48,7 +48,7 @@ in
                     config.networking.hostName;
         defaultText = lib.literalExpression "config.networking.fqdn";
         example = "discourse.example.com";
-        description = ''
+        description = lib.mdDoc ''
           The hostname to serve Discourse on.
         '';
       };
@@ -81,7 +81,7 @@ in
         type = with lib.types; nullOr path;
         default = null;
         example = "/run/keys/ssl.cert";
-        description = ''
+        description = lib.mdDoc ''
           The path to the server SSL certificate. Set this to enable
           SSL.
         '';
@@ -91,7 +91,7 @@ in
         type = with lib.types; nullOr path;
         default = null;
         example = "/run/keys/ssl.key";
-        description = ''
+        description = lib.mdDoc ''
           The path to the server SSL certificate key. Set this to
           enable SSL.
         '';
@@ -104,7 +104,7 @@ in
           <literal>true</literal>, unless <option>services.discourse.sslCertificate</option>
           and <option>services.discourse.sslCertificateKey</option> are set.
         '';
-        description = ''
+        description = lib.mdDoc ''
           Whether an ACME certificate should be used to secure
           connections to the server.
         '';
@@ -151,26 +151,26 @@ in
             };
           };
         '';
-        description = ''
+        description = lib.mdDoc ''
           Discourse site settings. These are the settings that can be
           changed from the UI. This only defines their default values:
           they can still be overridden from the UI.
 
           Available settings can be found by looking in the
-          <link xlink:href="https://github.com/discourse/discourse/blob/master/config/site_settings.yml">site_settings.yml</link>
+          [site_settings.yml](https://github.com/discourse/discourse/blob/master/config/site_settings.yml)
           file of the upstream distribution. To find a setting's path,
           you only need to care about the first two levels; i.e. its
           category and name. See the example.
 
           Settings containing secret data should be set to an
           attribute set containing the attribute
-          <literal>_secret</literal> - a string pointing to a file
+          `_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>config/nixos_site_settings.json</filename> file,
-          the <literal>login.github_client_secret</literal> key will
+          {file}`config/nixos_site_settings.json` file,
+          the `login.github_client_secret` key will
           be set to the contents of the
-          <filename>/run/keys/discourse_github_client_secret</filename>
+          {file}`/run/keys/discourse_github_client_secret`
           file.
         '';
       };
@@ -179,7 +179,7 @@ in
         skipCreate = lib.mkOption {
           type = lib.types.bool;
           default = false;
-          description = ''
+          description = lib.mdDoc ''
             Do not create the admin account, instead rely on other
             existing admin accounts.
           '';
@@ -188,7 +188,7 @@ in
         email = lib.mkOption {
           type = lib.types.str;
           example = "admin@example.com";
-          description = ''
+          description = lib.mdDoc ''
             The admin user email address.
           '';
         };
@@ -196,21 +196,21 @@ in
         username = lib.mkOption {
           type = lib.types.str;
           example = "admin";
-          description = ''
+          description = lib.mdDoc ''
             The admin user username.
           '';
         };
 
         fullName = lib.mkOption {
           type = lib.types.str;
-          description = ''
+          description = lib.mdDoc ''
             The admin user's full name.
           '';
         };
 
         passwordFile = lib.mkOption {
           type = lib.types.path;
-          description = ''
+          description = lib.mdDoc ''
             A path to a file containing the admin user's password.
 
             This should be a string, not a nix path, since nix paths are
@@ -222,8 +222,8 @@ in
       nginx.enable = lib.mkOption {
         type = lib.types.bool;
         default = true;
-        description = ''
-          Whether an <literal>nginx</literal> virtual host should be
+        description = lib.mdDoc ''
+          Whether an `nginx` virtual host should be
           set up to serve Discourse. Only disable if you're planning
           to use a different web server, which is not recommended.
         '';
@@ -233,7 +233,7 @@ in
         pool = lib.mkOption {
           type = lib.types.int;
           default = 8;
-          description = ''
+          description = lib.mdDoc ''
             Database connection pool size.
           '';
         };
@@ -250,7 +250,7 @@ in
         passwordFile = lib.mkOption {
           type = with lib.types; nullOr path;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             File containing the Discourse database user password.
 
             This should be a string, not a nix path, since nix paths are
@@ -261,18 +261,18 @@ in
         createLocally = lib.mkOption {
           type = lib.types.bool;
           default = true;
-          description = ''
+          description = lib.mdDoc ''
             Whether a database should be automatically created on the
-            local host. Set this to <literal>false</literal> if you plan
+            local host. Set this to `false` if you plan
             on provisioning a local database yourself. This has no effect
-            if <option>services.discourse.database.host</option> is customized.
+            if {option}`services.discourse.database.host` is customized.
           '';
         };
 
         name = lib.mkOption {
           type = lib.types.str;
           default = "discourse";
-          description = ''
+          description = lib.mdDoc ''
             Discourse database name.
           '';
         };
@@ -280,7 +280,7 @@ in
         username = lib.mkOption {
           type = lib.types.str;
           default = "discourse";
-          description = ''
+          description = lib.mdDoc ''
             Discourse database user.
           '';
         };
@@ -288,10 +288,10 @@ in
         ignorePostgresqlVersion = lib.mkOption {
           type = lib.types.bool;
           default = false;
-          description = ''
+          description = lib.mdDoc ''
             Whether to allow other versions of PostgreSQL than the
             recommended one. Only effective when
-            <option>services.discourse.database.createLocally</option>
+            {option}`services.discourse.database.createLocally`
             is enabled.
           '';
         };
@@ -301,7 +301,7 @@ in
         host = lib.mkOption {
           type = lib.types.str;
           default = "localhost";
-          description = ''
+          description = lib.mdDoc ''
             Redis server hostname.
           '';
         };
@@ -309,7 +309,7 @@ in
         passwordFile = lib.mkOption {
           type = with lib.types; nullOr path;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             File containing the Redis password.
 
             This should be a string, not a nix path, since nix paths are
@@ -320,7 +320,7 @@ in
         dbNumber = lib.mkOption {
           type = lib.types.int;
           default = 0;
-          description = ''
+          description = lib.mdDoc ''
             Redis database number.
           '';
         };
@@ -329,7 +329,7 @@ in
           type = lib.types.bool;
           default = cfg.redis.host != "localhost";
           defaultText = lib.literalExpression ''config.${opt.redis.host} != "localhost"'';
-          description = ''
+          description = lib.mdDoc ''
             Connect to Redis with SSL.
           '';
         };
@@ -342,8 +342,8 @@ in
           defaultText = lib.literalExpression ''
             "''${if config.services.discourse.mail.incoming.enable then "notifications" else "noreply"}@''${config.services.discourse.hostname}"
           '';
-          description = ''
-            The <literal>from:</literal> email address used when
+          description = lib.mdDoc ''
+            The `from:` email address used when
             sending all essential system emails. The domain specified
             here must have SPF, DKIM and reverse PTR records set
             correctly for email to arrive.
@@ -353,10 +353,10 @@ in
         contactEmailAddress = lib.mkOption {
           type = lib.types.str;
           default = "";
-          description = ''
+          description = lib.mdDoc ''
             Email address of key contact responsible for this
             site. Used for critical notifications, as well as on the
-            <literal>/about</literal> contact form for urgent matters.
+            `/about` contact form for urgent matters.
           '';
         };
 
@@ -364,7 +364,7 @@ in
           serverAddress = lib.mkOption {
             type = lib.types.str;
             default = "localhost";
-            description = ''
+            description = lib.mdDoc ''
               The address of the SMTP server Discourse should use to
               send email.
             '';
@@ -373,7 +373,7 @@ in
           port = lib.mkOption {
             type = lib.types.port;
             default = 25;
-            description = ''
+            description = lib.mdDoc ''
               The port of the SMTP server Discourse should use to
               send email.
             '';
@@ -382,7 +382,7 @@ in
           username = lib.mkOption {
             type = with lib.types; nullOr str;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               The username of the SMTP server.
             '';
           };
@@ -390,7 +390,7 @@ in
           passwordFile = lib.mkOption {
             type = lib.types.nullOr lib.types.path;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               A file containing the password of the SMTP server account.
 
               This should be a string, not a nix path, since nix paths
@@ -402,7 +402,7 @@ in
             type = lib.types.str;
             default = cfg.hostname;
             defaultText = lib.literalExpression "config.${opt.hostname}";
-            description = ''
+            description = lib.mdDoc ''
               HELO domain to use for outgoing mail.
             '';
           };
@@ -410,7 +410,7 @@ in
           authentication = lib.mkOption {
             type = with lib.types; nullOr (enum ["plain" "login" "cram_md5"]);
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Authentication type to use, see http://api.rubyonrails.org/classes/ActionMailer/Base.html
             '';
           };
@@ -418,7 +418,7 @@ in
           enableStartTLSAuto = lib.mkOption {
             type = lib.types.bool;
             default = true;
-            description = ''
+            description = lib.mdDoc ''
               Whether to try to use StartTLS.
             '';
           };
@@ -426,7 +426,7 @@ in
           opensslVerifyMode = lib.mkOption {
             type = lib.types.str;
             default = "peer";
-            description = ''
+            description = lib.mdDoc ''
               How OpenSSL checks the certificate, see http://api.rubyonrails.org/classes/ActionMailer/Base.html
             '';
           };
@@ -434,7 +434,7 @@ in
           forceTLS = lib.mkOption {
             type = lib.types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Force implicit TLS as per RFC 8314 3.3.
             '';
           };
@@ -444,7 +444,7 @@ in
           enable = lib.mkOption {
             type = lib.types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Whether to set up Postfix to receive incoming mail.
             '';
           };
@@ -453,7 +453,7 @@ in
             type = lib.types.str;
             default = "%{reply_key}@${cfg.hostname}";
             defaultText = lib.literalExpression ''"%{reply_key}@''${config.services.discourse.hostname}"'';
-            description = ''
+            description = lib.mdDoc ''
               Template for reply by email incoming email address, for
               example: %{reply_key}@reply.example.com or
               replies+%{reply_key}@example.com
@@ -464,7 +464,7 @@ in
             type = lib.types.package;
             default = pkgs.discourse-mail-receiver;
             defaultText = lib.literalExpression "pkgs.discourse-mail-receiver";
-            description = ''
+            description = lib.mdDoc ''
               The discourse-mail-receiver package to use.
             '';
           };
@@ -472,10 +472,10 @@ in
           apiKeyFile = lib.mkOption {
             type = lib.types.nullOr lib.types.path;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               A file containing the Discourse API key used to add
               posts and messages from mail. If left at its default
-              value <literal>null</literal>, one will be automatically
+              value `null`, one will be automatically
               generated.
 
               This should be a string, not a nix path, since nix paths
@@ -504,7 +504,7 @@ in
       sidekiqProcesses = lib.mkOption {
         type = lib.types.int;
         default = 1;
-        description = ''
+        description = lib.mdDoc ''
           How many Sidekiq processes should be spawned.
         '';
       };
@@ -512,7 +512,7 @@ in
       unicornTimeout = lib.mkOption {
         type = lib.types.int;
         default = 30;
-        description = ''
+        description = lib.mdDoc ''
           Time in seconds before a request to Unicorn times out.
 
           This can be raised if the system Discourse is running on is
diff --git a/nixos/modules/services/web-apps/documize.nix b/nixos/modules/services/web-apps/documize.nix
index 7f2ed82ee33..4353e3c2445 100644
--- a/nixos/modules/services/web-apps/documize.nix
+++ b/nixos/modules/services/web-apps/documize.nix
@@ -17,8 +17,8 @@ in {
     stateDirectoryName = mkOption {
       type = types.str;
       default = "documize";
-      description = ''
-        The name of the directory below <filename>/var/lib/private</filename>
+      description = lib.mdDoc ''
+        The name of the directory below {file}`/var/lib/private`
         where documize runs in and stores, for example, backups.
       '';
     };
@@ -27,7 +27,7 @@ in {
       type = types.package;
       default = pkgs.documize-community;
       defaultText = literalExpression "pkgs.documize-community";
-      description = ''
+      description = lib.mdDoc ''
         Which package to use for documize.
       '';
     };
@@ -36,7 +36,7 @@ in {
       type = types.nullOr types.str;
       default = null;
       example = "3edIYV6c8B28b19fh";
-      description = ''
+      description = lib.mdDoc ''
         The salt string used to encode JWT tokens, if not set a random value will be generated.
       '';
     };
@@ -44,23 +44,23 @@ in {
     cert = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
-        The <filename>cert.pem</filename> file used for https.
+      description = lib.mdDoc ''
+        The {file}`cert.pem` file used for https.
       '';
     };
 
     key = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
-        The <filename>key.pem</filename> file used for https.
+      description = lib.mdDoc ''
+        The {file}`key.pem` file used for https.
       '';
     };
 
     port = mkOption {
       type = types.port;
       default = 5001;
-      description = ''
+      description = lib.mdDoc ''
         The http/https port number.
       '';
     };
@@ -68,7 +68,7 @@ in {
     forcesslport = mkOption {
       type = types.nullOr types.port;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Redirect given http port number to TLS.
       '';
     };
@@ -76,8 +76,8 @@ in {
     offline = mkOption {
       type = types.bool;
       default = false;
-      description = ''
-        Set <literal>true</literal> for offline mode.
+      description = lib.mdDoc ''
+        Set `true` for offline mode.
       '';
       apply = v: if true == v then 1 else 0;
     };
@@ -122,7 +122,7 @@ in {
     location = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         reserved
       '';
     };
diff --git a/nixos/modules/services/web-apps/dokuwiki.nix b/nixos/modules/services/web-apps/dokuwiki.nix
index d8fc978774e..49865b962d1 100644
--- a/nixos/modules/services/web-apps/dokuwiki.nix
+++ b/nixos/modules/services/web-apps/dokuwiki.nix
@@ -66,21 +66,21 @@ let
           type = types.package;
           default = pkgs.dokuwiki;
           defaultText = literalExpression "pkgs.dokuwiki";
-          description = "Which DokuWiki package to use.";
+          description = lib.mdDoc "Which DokuWiki package to use.";
         };
 
         stateDir = mkOption {
           type = types.path;
           default = "/var/lib/dokuwiki/${name}/data";
-          description = "Location of the DokuWiki state directory.";
+          description = lib.mdDoc "Location of the DokuWiki state directory.";
         };
 
         acl = mkOption {
           type = types.nullOr types.lines;
           default = null;
           example = "*               @ALL               8";
-          description = ''
-            Access Control Lists: see <link xlink:href="https://www.dokuwiki.org/acl"/>
+          description = lib.mdDoc ''
+            Access Control Lists: see <https://www.dokuwiki.org/acl>
             Mutually exclusive with services.dokuwiki.aclFile
             Set this to a value other than null to take precedence over aclFile option.
 
@@ -92,11 +92,11 @@ let
         aclFile = mkOption {
           type = with types; nullOr str;
           default = if (config.aclUse && config.acl == null) then "/var/lib/dokuwiki/${name}/acl.auth.php" else null;
-          description = ''
+          description = lib.mdDoc ''
             Location of the dokuwiki acl rules. Mutually exclusive with services.dokuwiki.acl
             Mutually exclusive with services.dokuwiki.acl which is preferred.
-            Consult documentation <link xlink:href="https://www.dokuwiki.org/acl"/> for further instructions.
-            Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/acl.auth.php.dist"/>
+            Consult documentation <https://www.dokuwiki.org/acl> for further instructions.
+            Example: <https://github.com/splitbrain/dokuwiki/blob/master/conf/acl.auth.php.dist>
           '';
           example = "/var/lib/dokuwiki/${name}/acl.auth.php";
         };
@@ -104,7 +104,7 @@ let
         aclUse = mkOption {
           type = types.bool;
           default = true;
-          description = ''
+          description = lib.mdDoc ''
             Necessary for users to log in into the system.
             Also limits anonymous users. When disabled,
             everyone is able to create and edit content.
@@ -119,7 +119,7 @@ let
             $plugins['authmysql'] = 0;
             $plugins['authpgsql'] = 0;
           '';
-          description = ''
+          description = lib.mdDoc ''
             List of the dokuwiki (un)loaded plugins.
           '';
         };
@@ -127,10 +127,10 @@ let
         superUser = mkOption {
           type = types.nullOr types.str;
           default = "@admin";
-          description = ''
+          description = lib.mdDoc ''
             You can set either a username, a list of usernames (“admin1,admin2”),
             or the name of a group by prepending an @ char to the groupname
-            Consult documentation <link xlink:href="https://www.dokuwiki.org/config:superuser"/> for further instructions.
+            Consult documentation <https://www.dokuwiki.org/config:superuser> for further instructions.
           '';
         };
 
@@ -150,9 +150,9 @@ let
           type = types.nullOr types.str;
           default = "";
           example = "search,register";
-          description = ''
+          description = lib.mdDoc ''
             Disable individual action modes. Refer to
-            <link xlink:href="https://www.dokuwiki.org/config:action_modes"/>
+            <https://www.dokuwiki.org/config:action_modes>
             for details on supported values.
           '';
         };
@@ -222,8 +222,8 @@ let
             "pm.max_spare_servers" = 4;
             "pm.max_requests" = 500;
           };
-          description = ''
-            Options for the DokuWiki PHP pool. See the documentation on <literal>php-fpm.conf</literal>
+          description = lib.mdDoc ''
+            Options for the DokuWiki PHP pool. See the documentation on `php-fpm.conf`
             for details on configuration directives.
           '';
         };
@@ -235,9 +235,9 @@ let
             $conf['title'] = 'My Wiki';
             $conf['userewrite'] = 1;
           '';
-          description = ''
+          description = lib.mdDoc ''
             DokuWiki configuration. Refer to
-            <link xlink:href="https://www.dokuwiki.org/config"/>
+            <https://www.dokuwiki.org/config>
             for details on supported values.
           '';
         };
@@ -254,7 +254,7 @@ in
       sites = mkOption {
         type = types.attrsOf (types.submodule siteOpts);
         default = {};
-        description = "Specification of one or more DokuWiki sites to serve";
+        description = lib.mdDoc "Specification of one or more DokuWiki sites to serve";
       };
 
       webserver = mkOption {
diff --git a/nixos/modules/services/web-apps/engelsystem.nix b/nixos/modules/services/web-apps/engelsystem.nix
index 06c3c6dfc3d..f1d71f17447 100644
--- a/nixos/modules/services/web-apps/engelsystem.nix
+++ b/nixos/modules/services/web-apps/engelsystem.nix
@@ -9,7 +9,7 @@ in {
       enable = mkOption {
         default = false;
         example = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable engelsystem, an online tool for coordinating volunteers
           and shifts on large events.
         '';
@@ -19,12 +19,12 @@ in {
       domain = mkOption {
         type = types.str;
         example = "engelsystem.example.com";
-        description = "Domain to serve on.";
+        description = lib.mdDoc "Domain to serve on.";
       };
 
       package = mkOption {
         type = types.package;
-        description = "Engelsystem package used for the service.";
+        description = lib.mdDoc "Engelsystem package used for the service.";
         default = pkgs.engelsystem;
         defaultText = literalExpression "pkgs.engelsystem";
       };
@@ -32,9 +32,9 @@ in {
       createDatabase = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to create a local database automatically.
-          This will override every database setting in <option>services.engelsystem.config</option>.
+          This will override every database setting in {option}`services.engelsystem.config`.
         '';
       };
     };
@@ -70,7 +70,7 @@ in {
         min_password_length = 6;
         default_locale = "de_DE";
       };
-      description = ''
+      description = lib.mdDoc ''
         Options to be added to config.php, as a nix attribute set. Options containing secret data
         should be set to an attribute 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
diff --git a/nixos/modules/services/web-apps/ethercalc.nix b/nixos/modules/services/web-apps/ethercalc.nix
index d74def59c6c..a5be86a34aa 100644
--- a/nixos/modules/services/web-apps/ethercalc.nix
+++ b/nixos/modules/services/web-apps/ethercalc.nix
@@ -10,11 +10,11 @@ in {
       enable = mkOption {
         default = false;
         type = types.bool;
-        description = ''
+        description = lib.mdDoc ''
           ethercalc, an online collaborative spreadsheet server.
 
           Persistent state will be maintained under
-          <filename>/var/lib/ethercalc</filename>. Upstream supports using a
+          {file}`/var/lib/ethercalc`. Upstream supports using a
           redis server for storage and recommends the redis backend for
           intensive use; however, the Nix module doesn't currently support
           redis.
@@ -28,19 +28,19 @@ in {
         default = pkgs.ethercalc;
         defaultText = literalExpression "pkgs.ethercalc";
         type = types.package;
-        description = "Ethercalc package to use.";
+        description = lib.mdDoc "Ethercalc package to use.";
       };
 
       host = mkOption {
         type = types.str;
         default = "0.0.0.0";
-        description = "Address to listen on (use 0.0.0.0 to allow access from any address).";
+        description = lib.mdDoc "Address to listen on (use 0.0.0.0 to allow access from any address).";
       };
 
       port = mkOption {
         type = types.port;
         default = 8000;
-        description = "Port to bind to.";
+        description = lib.mdDoc "Port to bind to.";
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/galene.nix b/nixos/modules/services/web-apps/galene.nix
index 38c3392014f..2fef43753d7 100644
--- a/nixos/modules/services/web-apps/galene.nix
+++ b/nixos/modules/services/web-apps/galene.nix
@@ -17,7 +17,7 @@ in
       stateDir = mkOption {
         default = defaultstateDir;
         type = types.str;
-        description = ''
+        description = lib.mdDoc ''
           The directory where Galene stores its internal state. If left as the default
           value this directory will automatically be created before the Galene server
           starts, otherwise the sysadmin is responsible for ensuring the directory
@@ -28,19 +28,19 @@ in
       user = mkOption {
         type = types.str;
         default = "galene";
-        description = "User account under which galene runs.";
+        description = lib.mdDoc "User account under which galene runs.";
       };
 
       group = mkOption {
         type = types.str;
         default = "galene";
-        description = "Group under which galene runs.";
+        description = lib.mdDoc "Group under which galene runs.";
       };
 
       insecure = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether Galene should listen in http or in https. If left as the default
           value (false), Galene needs to be fed a private key and a certificate.
         '';
@@ -50,7 +50,7 @@ in
         type = types.nullOr types.str;
         default = null;
         example = "/path/to/your/cert.pem";
-        description = ''
+        description = lib.mdDoc ''
           Path to the server's certificate. The file is copied at runtime to
           Galene's data directory where it needs to reside.
         '';
@@ -60,7 +60,7 @@ in
         type = types.nullOr types.str;
         default = null;
         example = "/path/to/your/key.pem";
-        description = ''
+        description = lib.mdDoc ''
           Path to the server's private key. The file is copied at runtime to
           Galene's data directory where it needs to reside.
         '';
@@ -69,13 +69,13 @@ in
       httpAddress = mkOption {
         type = types.str;
         default = "";
-        description = "HTTP listen address for galene.";
+        description = lib.mdDoc "HTTP listen address for galene.";
       };
 
       httpPort = mkOption {
         type = types.port;
         default = 8443;
-        description = "HTTP listen port.";
+        description = lib.mdDoc "HTTP listen port.";
       };
 
       staticDir = mkOption {
@@ -83,7 +83,7 @@ in
         default = "${cfg.package.static}/static";
         defaultText = literalExpression ''"''${package.static}/static"'';
         example = "/var/lib/galene/static";
-        description = "Web server directory.";
+        description = lib.mdDoc "Web server directory.";
       };
 
       recordingsDir = mkOption {
@@ -91,7 +91,7 @@ in
         default = defaultrecordingsDir;
         defaultText = literalExpression ''"''${config.${opt.stateDir}}/recordings"'';
         example = "/var/lib/galene/recordings";
-        description = "Recordings directory.";
+        description = lib.mdDoc "Recordings directory.";
       };
 
       dataDir = mkOption {
@@ -99,7 +99,7 @@ in
         default = defaultdataDir;
         defaultText = literalExpression ''"''${config.${opt.stateDir}}/data"'';
         example = "/var/lib/galene/data";
-        description = "Data directory.";
+        description = lib.mdDoc "Data directory.";
       };
 
       groupsDir = mkOption {
@@ -107,14 +107,14 @@ in
         default = defaultgroupsDir;
         defaultText = literalExpression ''"''${config.${opt.stateDir}}/groups"'';
         example = "/var/lib/galene/groups";
-        description = "Web server directory.";
+        description = lib.mdDoc "Web server directory.";
       };
 
       package = mkOption {
         default = pkgs.galene;
         defaultText = literalExpression "pkgs.galene";
         type = types.package;
-        description = ''
+        description = lib.mdDoc ''
           Package for running Galene.
         '';
       };
diff --git a/nixos/modules/services/web-apps/gerrit.nix b/nixos/modules/services/web-apps/gerrit.nix
index 6bfc67368dd..5b36204ff05 100644
--- a/nixos/modules/services/web-apps/gerrit.nix
+++ b/nixos/modules/services/web-apps/gerrit.nix
@@ -65,14 +65,14 @@ in
         type = types.package;
         default = pkgs.gerrit;
         defaultText = literalExpression "pkgs.gerrit";
-        description = "Gerrit package to use";
+        description = lib.mdDoc "Gerrit package to use";
       };
 
       jvmPackage = mkOption {
         type = types.package;
         default = pkgs.jre_headless;
         defaultText = literalExpression "pkgs.jre_headless";
-        description = "Java Runtime Environment package to use";
+        description = lib.mdDoc "Java Runtime Environment package to use";
       };
 
       jvmOpts = mkOption {
@@ -81,13 +81,13 @@ in
           "-Dflogger.backend_factory=com.google.common.flogger.backend.log4j.Log4jBackendFactory#getInstance"
           "-Dflogger.logging_context=com.google.gerrit.server.logging.LoggingContext#getInstance"
         ];
-        description = "A list of JVM options to start gerrit with.";
+        description = lib.mdDoc "A list of JVM options to start gerrit with.";
       };
 
       jvmHeapLimit = mkOption {
         type = types.str;
         default = "1024m";
-        description = ''
+        description = lib.mdDoc ''
           How much memory to allocate to the JVM heap
         '';
       };
@@ -95,8 +95,8 @@ in
       listenAddress = mkOption {
         type = types.str;
         default = "[::]:8080";
-        description = ''
-          <literal>hostname:port</literal> to listen for HTTP traffic.
+        description = lib.mdDoc ''
+          `hostname:port` to listen for HTTP traffic.
 
           This is bound using the systemd socket activation.
         '';
@@ -105,25 +105,25 @@ in
       settings = mkOption {
         type = gitIniType;
         default = {};
-        description = ''
+        description = lib.mdDoc ''
           Gerrit configuration. This will be generated to the
-          <literal>etc/gerrit.config</literal> file.
+          `etc/gerrit.config` file.
         '';
       };
 
       replicationSettings = mkOption {
         type = gitIniType;
         default = {};
-        description = ''
+        description = lib.mdDoc ''
           Replication configuration. This will be generated to the
-          <literal>etc/replication.config</literal> file.
+          `etc/replication.config` file.
         '';
       };
 
       plugins = mkOption {
         type = types.listOf types.package;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           List of plugins to add to Gerrit. Each derivation is a jar file
           itself where the name of the derivation is the name of plugin.
         '';
@@ -132,19 +132,19 @@ in
       builtinPlugins = mkOption {
         type = types.listOf (types.enum cfg.package.passthru.plugins);
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           List of builtins plugins to install. Those are shipped in the
-          <literal>gerrit.war</literal> file.
+          `gerrit.war` file.
         '';
       };
 
       serverId = mkOption {
         type = types.str;
-        description = ''
+        description = lib.mdDoc ''
           Set a UUID that uniquely identifies the server.
 
           This can be generated with
-          <literal>nix-shell -p util-linux --run uuidgen</literal>.
+          `nix-shell -p util-linux --run uuidgen`.
         '';
       };
     };
diff --git a/nixos/modules/services/web-apps/gotify-server.nix b/nixos/modules/services/web-apps/gotify-server.nix
index 03e01f46a94..9e278b41ad1 100644
--- a/nixos/modules/services/web-apps/gotify-server.nix
+++ b/nixos/modules/services/web-apps/gotify-server.nix
@@ -11,7 +11,7 @@ in {
 
       port = mkOption {
         type = types.port;
-        description = ''
+        description = lib.mdDoc ''
           Port the server listens to.
         '';
       };
@@ -19,8 +19,8 @@ in {
       stateDirectoryName = mkOption {
         type = types.str;
         default = "gotify-server";
-        description = ''
-          The name of the directory below <filename>/var/lib</filename> where
+        description = lib.mdDoc ''
+          The name of the directory below {file}`/var/lib` where
           gotify stores its runtime data.
         '';
       };
diff --git a/nixos/modules/services/web-apps/grocy.nix b/nixos/modules/services/web-apps/grocy.nix
index a77fddf1f2f..173dd63ddaa 100644
--- a/nixos/modules/services/web-apps/grocy.nix
+++ b/nixos/modules/services/web-apps/grocy.nix
@@ -10,7 +10,7 @@ in {
 
     hostName = mkOption {
       type = types.str;
-      description = ''
+      description = lib.mdDoc ''
         FQDN for the grocy instance.
       '';
     };
@@ -18,7 +18,7 @@ in {
     nginx.enableSSL = mkOption {
       type = types.bool;
       default = true;
-      description = ''
+      description = lib.mdDoc ''
         Whether or not to enable SSL (with ACME and let's encrypt)
         for the grocy vhost.
       '';
@@ -39,7 +39,7 @@ in {
         "pm.max_requests" = "500";
       };
 
-      description = ''
+      description = lib.mdDoc ''
         Options for grocy's PHPFPM pool.
       '';
     };
@@ -47,8 +47,8 @@ in {
     dataDir = mkOption {
       type = types.str;
       default = "/var/lib/grocy";
-      description = ''
-        Home directory of the <literal>grocy</literal> user which contains
+      description = lib.mdDoc ''
+        Home directory of the `grocy` user which contains
         the application's state.
       '';
     };
@@ -58,7 +58,7 @@ in {
         type = types.str;
         default = "USD";
         example = "EUR";
-        description = ''
+        description = lib.mdDoc ''
           ISO 4217 code for the currency to display.
         '';
       };
@@ -66,7 +66,7 @@ in {
       culture = mkOption {
         type = types.enum [ "de" "en" "da" "en_GB" "es" "fr" "hu" "it" "nl" "no" "pl" "pt_BR" "ru" "sk_SK" "sv_SE" "tr" ];
         default = "en";
-        description = ''
+        description = lib.mdDoc ''
           Display language of the frontend.
         '';
       };
@@ -75,14 +75,14 @@ in {
         showWeekNumber = mkOption {
           default = true;
           type = types.bool;
-          description = ''
+          description = lib.mdDoc ''
             Show the number of the weeks in the calendar views.
           '';
         };
         firstDayOfWeek = mkOption {
           default = null;
           type = types.nullOr (types.enum (range 0 6));
-          description = ''
+          description = lib.mdDoc ''
             Which day of the week (0=Sunday, 1=Monday etc.) should be the
             first day.
           '';
diff --git a/nixos/modules/services/web-apps/healthchecks.nix b/nixos/modules/services/web-apps/healthchecks.nix
index be025e7dd55..e58cc6f202b 100644
--- a/nixos/modules/services/web-apps/healthchecks.nix
+++ b/nixos/modules/services/web-apps/healthchecks.nix
@@ -37,7 +37,7 @@ in
       default = pkgs.healthchecks;
       defaultText = literalExpression "pkgs.healthchecks";
       type = types.package;
-      description = "healthchecks package to use.";
+      description = lib.mdDoc "healthchecks package to use.";
     };
 
     user = mkOption {
@@ -71,13 +71,13 @@ in
     listenAddress = mkOption {
       type = types.str;
       default = "localhost";
-      description = "Address the server will listen on.";
+      description = lib.mdDoc "Address the server will listen on.";
     };
 
     port = mkOption {
       type = types.port;
       default = 8000;
-      description = "Port the server will listen on.";
+      description = lib.mdDoc "Port the server will listen on.";
     };
 
     dataDir = mkOption {
@@ -114,26 +114,26 @@ in
           ALLOWED_HOSTS = lib.mkOption {
             type = types.listOf types.str;
             default = [ "*" ];
-            description = "The host/domain names that this site can serve.";
+            description = lib.mdDoc "The host/domain names that this site can serve.";
             apply = lib.concatStringsSep ",";
           };
 
           SECRET_KEY_FILE = mkOption {
             type = types.path;
-            description = "Path to a file containing the secret key.";
+            description = lib.mdDoc "Path to a file containing the secret key.";
           };
 
           DEBUG = mkOption {
             type = types.bool;
             default = false;
-            description = "Enable debug mode.";
+            description = lib.mdDoc "Enable debug mode.";
             apply = boolToPython;
           };
 
           REGISTRATION_OPEN = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               A boolean that controls whether site visitors can create new accounts.
               Set it to false if you are setting up a private Healthchecks instance,
               but it needs to be publicly accessible (so, for example, your cloud
diff --git a/nixos/modules/services/web-apps/hedgedoc.nix b/nixos/modules/services/web-apps/hedgedoc.nix
index f0e4f753eb7..b8d83984ca7 100644
--- a/nixos/modules/services/web-apps/hedgedoc.nix
+++ b/nixos/modules/services/web-apps/hedgedoc.nix
@@ -37,7 +37,7 @@ in
     groups = mkOption {
       type = types.listOf types.str;
       default = [];
-      description = ''
+      description = lib.mdDoc ''
         Groups to which the service user should be added.
       '';
     };
@@ -45,7 +45,7 @@ in
     workDir = mkOption {
       type = types.path;
       default = "/var/lib/${name}";
-      description = ''
+      description = lib.mdDoc ''
         Working directory for the HedgeDoc service.
       '';
     };
@@ -56,7 +56,7 @@ in
         type = types.nullOr types.str;
         default = null;
         example = "hedgedoc.org";
-        description = ''
+        description = lib.mdDoc ''
           Domain name for the HedgeDoc instance.
         '';
       };
@@ -64,14 +64,14 @@ in
         type = types.nullOr types.str;
         default = null;
         example = "/url/path/to/hedgedoc";
-        description = ''
+        description = lib.mdDoc ''
           Path under which HedgeDoc is accessible.
         '';
       };
       host = mkOption {
         type = types.str;
         default = "localhost";
-        description = ''
+        description = lib.mdDoc ''
           Address to listen on.
         '';
       };
@@ -79,7 +79,7 @@ in
         type = types.int;
         default = 3000;
         example = 80;
-        description = ''
+        description = lib.mdDoc ''
           Port to listen on.
         '';
       };
@@ -87,7 +87,7 @@ in
         type = types.nullOr types.str;
         default = null;
         example = "/run/hedgedoc.sock";
-        description = ''
+        description = lib.mdDoc ''
           Specify where a UNIX domain socket should be placed.
         '';
       };
@@ -95,44 +95,44 @@ in
         type = types.listOf types.str;
         default = [];
         example = [ "localhost" "hedgedoc.org" ];
-        description = ''
+        description = lib.mdDoc ''
           List of domains to whitelist.
         '';
       };
       useSSL = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Enable to use SSL server. This will also enable
-          <option>protocolUseSSL</option>.
+          {option}`protocolUseSSL`.
         '';
       };
       hsts = {
         enable = mkOption {
           type = types.bool;
           default = true;
-          description = ''
+          description = lib.mdDoc ''
             Whether to enable HSTS if HTTPS is also enabled.
           '';
         };
         maxAgeSeconds = mkOption {
           type = types.int;
           default = 31536000;
-          description = ''
+          description = lib.mdDoc ''
             Max duration for clients to keep the HSTS status.
           '';
         };
         includeSubdomains = mkOption {
           type = types.bool;
           default = true;
-          description = ''
+          description = lib.mdDoc ''
             Whether to include subdomains in HSTS.
           '';
         };
         preload = mkOption {
           type = types.bool;
           default = true;
-          description = ''
+          description = lib.mdDoc ''
             Whether to allow preloading of the site's HSTS status.
           '';
         };
@@ -159,31 +159,31 @@ in
       protocolUseSSL = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Enable to use TLS for resource paths.
-          This only applies when <option>domain</option> is set.
+          This only applies when {option}`domain` is set.
         '';
       };
       urlAddPort = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Enable to add the port to callback URLs.
-          This only applies when <option>domain</option> is set
+          This only applies when {option}`domain` is set
           and only for ports other than 80 and 443.
         '';
       };
       useCDN = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to use CDN resources or not.
         '';
       };
       allowAnonymous = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to allow anonymous usage.
         '';
       };
@@ -198,21 +198,21 @@ in
       allowFreeURL = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to allow note creation by accessing a nonexistent note URL.
         '';
       };
       requireFreeURLAuthentication = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to require authentication for FreeURL mode style note creation.
         '';
       };
       defaultPermission = mkOption {
         type = types.enum [ "freely" "editable" "limited" "locked" "private" ];
         default = "editable";
-        description = ''
+        description = lib.mdDoc ''
           Default permissions for notes.
           This only applies for signed-in users.
         '';
@@ -223,12 +223,12 @@ in
         example = ''
           postgres://user:pass@host:5432/dbname
         '';
-        description = ''
+        description = lib.mdDoc ''
           Specify which database to use.
           HedgeDoc supports mysql, postgres, sqlite and mssql.
-          See <link xlink:href="https://sequelize.readthedocs.io/en/v3/">
-          https://sequelize.readthedocs.io/en/v3/</link> for more information.
-          Note: This option overrides <option>db</option>.
+          See [
+          https://sequelize.readthedocs.io/en/v3/](https://sequelize.readthedocs.io/en/v3/) for more information.
+          Note: This option overrides {option}`db`.
         '';
       };
       db = mkOption {
@@ -240,52 +240,52 @@ in
             storage = "/var/lib/${name}/db.${name}.sqlite";
           }
         '';
-        description = ''
+        description = lib.mdDoc ''
           Specify the configuration for sequelize.
           HedgeDoc supports mysql, postgres, sqlite and mssql.
-          See <link xlink:href="https://sequelize.readthedocs.io/en/v3/">
-          https://sequelize.readthedocs.io/en/v3/</link> for more information.
-          Note: This option overrides <option>db</option>.
+          See [
+          https://sequelize.readthedocs.io/en/v3/](https://sequelize.readthedocs.io/en/v3/) for more information.
+          Note: This option overrides {option}`db`.
         '';
       };
       sslKeyPath= mkOption {
         type = types.nullOr types.str;
         default = null;
         example = "/var/lib/hedgedoc/hedgedoc.key";
-        description = ''
-          Path to the SSL key. Needed when <option>useSSL</option> is enabled.
+        description = lib.mdDoc ''
+          Path to the SSL key. Needed when {option}`useSSL` is enabled.
         '';
       };
       sslCertPath = mkOption {
         type = types.nullOr types.str;
         default = null;
         example = "/var/lib/hedgedoc/hedgedoc.crt";
-        description = ''
-          Path to the SSL cert. Needed when <option>useSSL</option> is enabled.
+        description = lib.mdDoc ''
+          Path to the SSL cert. Needed when {option}`useSSL` is enabled.
         '';
       };
       sslCAPath = mkOption {
         type = types.listOf types.str;
         default = [];
         example = [ "/var/lib/hedgedoc/ca.crt" ];
-        description = ''
-          SSL ca chain. Needed when <option>useSSL</option> is enabled.
+        description = lib.mdDoc ''
+          SSL ca chain. Needed when {option}`useSSL` is enabled.
         '';
       };
       dhParamPath = mkOption {
         type = types.nullOr types.str;
         default = null;
         example = "/var/lib/hedgedoc/dhparam.pem";
-        description = ''
-          Path to the SSL dh params. Needed when <option>useSSL</option> is enabled.
+        description = lib.mdDoc ''
+          Path to the SSL dh params. Needed when {option}`useSSL` is enabled.
         '';
       };
       tmpPath = mkOption {
         type = types.str;
         default = "/tmp";
-        description = ''
+        description = lib.mdDoc ''
           Path to the temp directory HedgeDoc should use.
-          Note that <option>serviceConfig.PrivateTmp</option> is enabled for
+          Note that {option}`serviceConfig.PrivateTmp` is enabled for
           the HedgeDoc systemd service by default.
           (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
@@ -293,7 +293,7 @@ in
       defaultNotePath = mkOption {
         type = types.nullOr types.str;
         default = "./public/default.md";
-        description = ''
+        description = lib.mdDoc ''
           Path to the default Note file.
           (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
@@ -301,7 +301,7 @@ in
       docsPath = mkOption {
         type = types.nullOr types.str;
         default = "./public/docs";
-        description = ''
+        description = lib.mdDoc ''
           Path to the docs directory.
           (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
@@ -309,7 +309,7 @@ in
       indexPath = mkOption {
         type = types.nullOr types.str;
         default = "./public/views/index.ejs";
-        description = ''
+        description = lib.mdDoc ''
           Path to the index template file.
           (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
@@ -317,7 +317,7 @@ in
       hackmdPath = mkOption {
         type = types.nullOr types.str;
         default = "./public/views/hackmd.ejs";
-        description = ''
+        description = lib.mdDoc ''
           Path to the hackmd template file.
           (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
@@ -326,7 +326,7 @@ in
         type = types.nullOr types.str;
         default = null;
         defaultText = literalExpression "./public/views/error.ejs";
-        description = ''
+        description = lib.mdDoc ''
           Path to the error template file.
           (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
@@ -335,7 +335,7 @@ in
         type = types.nullOr types.str;
         default = null;
         defaultText = literalExpression "./public/views/pretty.ejs";
-        description = ''
+        description = lib.mdDoc ''
           Path to the pretty template file.
           (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
@@ -344,7 +344,7 @@ in
         type = types.nullOr types.str;
         default = null;
         defaultText = literalExpression "./public/views/slide.hbs";
-        description = ''
+        description = lib.mdDoc ''
           Path to the slide template file.
           (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
@@ -353,21 +353,21 @@ in
         type = types.str;
         default = "${cfg.workDir}/uploads";
         defaultText = literalExpression "/var/lib/${name}/uploads";
-        description = ''
+        description = lib.mdDoc ''
           Path under which uploaded files are saved.
         '';
       };
       sessionName = mkOption {
         type = types.str;
         default = "connect.sid";
-        description = ''
+        description = lib.mdDoc ''
           Specify the name of the session cookie.
         '';
       };
       sessionSecret = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           Specify the secret used to sign the session cookie.
           If unset, one will be generated on startup.
         '';
@@ -375,56 +375,56 @@ in
       sessionLife = mkOption {
         type = types.int;
         default = 1209600000;
-        description = ''
+        description = lib.mdDoc ''
           Session life time in milliseconds.
         '';
       };
       heartbeatInterval = mkOption {
         type = types.int;
         default = 5000;
-        description = ''
+        description = lib.mdDoc ''
           Specify the socket.io heartbeat interval.
         '';
       };
       heartbeatTimeout = mkOption {
         type = types.int;
         default = 10000;
-        description = ''
+        description = lib.mdDoc ''
           Specify the socket.io heartbeat timeout.
         '';
       };
       documentMaxLength = mkOption {
         type = types.int;
         default = 100000;
-        description = ''
+        description = lib.mdDoc ''
           Specify the maximum document length.
         '';
       };
       email = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable email sign-in.
         '';
       };
       allowEmailRegister = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable email registration.
         '';
       };
       allowGravatar = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to use gravatar as profile picture source.
         '';
       };
       imageUploadType = mkOption {
         type = types.enum [ "imgur" "s3" "minio" "filesystem" ];
         default = "filesystem";
-        description = ''
+        description = lib.mdDoc ''
           Specify where to upload images.
         '';
       };
@@ -433,85 +433,85 @@ in
           options = {
             accessKey = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Minio access key.
               '';
             };
             secretKey = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Minio secret key.
               '';
             };
             endPoint = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Minio endpoint.
               '';
             };
             port = mkOption {
               type = types.int;
               default = 9000;
-              description = ''
+              description = lib.mdDoc ''
                 Minio listen port.
               '';
             };
             secure = mkOption {
               type = types.bool;
               default = true;
-              description = ''
+              description = lib.mdDoc ''
                 Whether to use HTTPS for Minio.
               '';
             };
           };
         });
         default = null;
-        description = "Configure the minio third-party integration.";
+        description = lib.mdDoc "Configure the minio third-party integration.";
       };
       s3 = mkOption {
         type = types.nullOr (types.submodule {
           options = {
             accessKeyId = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 AWS access key id.
               '';
             };
             secretAccessKey = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 AWS access key.
               '';
             };
             region = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 AWS S3 region.
               '';
             };
           };
         });
         default = null;
-        description = "Configure the s3 third-party integration.";
+        description = lib.mdDoc "Configure the s3 third-party integration.";
       };
       s3bucket = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = ''
-          Specify the bucket name for upload types <literal>s3</literal> and <literal>minio</literal>.
+        description = lib.mdDoc ''
+          Specify the bucket name for upload types `s3` and `minio`.
         '';
       };
       allowPDFExport = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable PDF exports.
         '';
       };
       imgur.clientId = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           Imgur API client ID.
         '';
       };
@@ -520,13 +520,13 @@ in
           options = {
             connectionString = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Azure Blob Storage connection string.
               '';
             };
             container = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Azure Blob Storage container name.
                 It will be created if non-existent.
               '';
@@ -534,162 +534,162 @@ in
           };
         });
         default = null;
-        description = "Configure the azure third-party integration.";
+        description = lib.mdDoc "Configure the azure third-party integration.";
       };
       oauth2 = mkOption {
         type = types.nullOr (types.submodule {
           options = {
             authorizationURL = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the OAuth authorization URL.
               '';
             };
             tokenURL = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the OAuth token URL.
               '';
             };
             baseURL = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the OAuth base URL.
               '';
             };
             userProfileURL = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the OAuth userprofile URL.
               '';
             };
             userProfileUsernameAttr = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the name of the attribute for the username from the claim.
               '';
             };
             userProfileDisplayNameAttr = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the name of the attribute for the display name from the claim.
               '';
             };
             userProfileEmailAttr = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the name of the attribute for the email from the claim.
               '';
             };
             scope = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the OAuth scope.
               '';
             };
             providerName = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the name to be displayed for this strategy.
               '';
             };
             rolesClaim = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the role claim name.
               '';
             };
             accessRole = mkOption {
               type = with types; nullOr str;
               default = null;
-              description = ''
+              description = lib.mdDoc ''
                 Specify role which should be included in the ID token roles claim to grant access
               '';
             };
             clientID = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the OAuth client ID.
               '';
             };
             clientSecret = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Specify the OAuth client secret.
               '';
             };
           };
         });
         default = null;
-        description = "Configure the OAuth integration.";
+        description = lib.mdDoc "Configure the OAuth integration.";
       };
       facebook = mkOption {
         type = types.nullOr (types.submodule {
           options = {
             clientID = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Facebook API client ID.
               '';
             };
             clientSecret = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Facebook API client secret.
               '';
             };
           };
         });
         default = null;
-        description = "Configure the facebook third-party integration";
+        description = lib.mdDoc "Configure the facebook third-party integration";
       };
       twitter = mkOption {
         type = types.nullOr (types.submodule {
           options = {
             consumerKey = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Twitter API consumer key.
               '';
             };
             consumerSecret = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Twitter API consumer secret.
               '';
             };
           };
         });
         default = null;
-        description = "Configure the Twitter third-party integration.";
+        description = lib.mdDoc "Configure the Twitter third-party integration.";
       };
       github = mkOption {
         type = types.nullOr (types.submodule {
           options = {
             clientID = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 GitHub API client ID.
               '';
             };
             clientSecret = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Github API client secret.
               '';
             };
           };
         });
         default = null;
-        description = "Configure the GitHub third-party integration.";
+        description = lib.mdDoc "Configure the GitHub third-party integration.";
       };
       gitlab = mkOption {
         type = types.nullOr (types.submodule {
@@ -697,27 +697,27 @@ in
             baseURL = mkOption {
               type = types.str;
               default = "";
-              description = ''
+              description = lib.mdDoc ''
                 GitLab API authentication endpoint.
                 Only needed for other endpoints than gitlab.com.
               '';
             };
             clientID = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 GitLab API client ID.
               '';
             };
             clientSecret = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 GitLab API client secret.
               '';
             };
             scope = mkOption {
               type = types.enum [ "api" "read_user" ];
               default = "api";
-              description = ''
+              description = lib.mdDoc ''
                 GitLab API requested scope.
                 GitLab snippet import/export requires api scope.
               '';
@@ -725,79 +725,79 @@ in
           };
         });
         default = null;
-        description = "Configure the GitLab third-party integration.";
+        description = lib.mdDoc "Configure the GitLab third-party integration.";
       };
       mattermost = mkOption {
         type = types.nullOr (types.submodule {
           options = {
             baseURL = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Mattermost authentication endpoint.
               '';
             };
             clientID = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Mattermost API client ID.
               '';
             };
             clientSecret = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Mattermost API client secret.
               '';
             };
           };
         });
         default = null;
-        description = "Configure the Mattermost third-party integration.";
+        description = lib.mdDoc "Configure the Mattermost third-party integration.";
       };
       dropbox = mkOption {
         type = types.nullOr (types.submodule {
           options = {
             clientID = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Dropbox API client ID.
               '';
             };
             clientSecret = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Dropbox API client secret.
               '';
             };
             appKey = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Dropbox app key.
               '';
             };
           };
         });
         default = null;
-        description = "Configure the Dropbox third-party integration.";
+        description = lib.mdDoc "Configure the Dropbox third-party integration.";
       };
       google = mkOption {
         type = types.nullOr (types.submodule {
           options = {
             clientID = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Google API client ID.
               '';
             };
             clientSecret = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Google API client secret.
               '';
             };
           };
         });
         default = null;
-        description = "Configure the Google third-party integration.";
+        description = lib.mdDoc "Configure the Google third-party integration.";
       };
       ldap = mkOption {
         type = types.nullOr (types.submodule {
@@ -805,40 +805,40 @@ in
             providerName = mkOption {
               type = types.str;
               default = "";
-              description = ''
+              description = lib.mdDoc ''
                 Optional name to be displayed at login form, indicating the LDAP provider.
               '';
             };
             url = mkOption {
               type = types.str;
               example = "ldap://localhost";
-              description = ''
+              description = lib.mdDoc ''
                 URL of LDAP server.
               '';
             };
             bindDn = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Bind DN for LDAP access.
               '';
             };
             bindCredentials = mkOption {
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Bind credentials for LDAP access.
               '';
             };
             searchBase = mkOption {
               type = types.str;
               example = "o=users,dc=example,dc=com";
-              description = ''
+              description = lib.mdDoc ''
                 LDAP directory to begin search from.
               '';
             };
             searchFilter = mkOption {
               type = types.str;
               example = "(uid={{username}})";
-              description = ''
+              description = lib.mdDoc ''
                 LDAP filter to search with.
               '';
             };
@@ -846,22 +846,22 @@ in
               type = types.nullOr (types.listOf types.str);
               default = null;
               example = [ "displayName" "mail" ];
-              description = ''
+              description = lib.mdDoc ''
                 LDAP attributes to search with.
               '';
             };
             userNameField = mkOption {
               type = types.str;
               default = "";
-              description = ''
+              description = lib.mdDoc ''
                 LDAP field which is used as the username on HedgeDoc.
-                By default <option>useridField</option> is used.
+                By default {option}`useridField` is used.
               '';
             };
             useridField = mkOption {
               type = types.str;
               example = "uid";
-              description = ''
+              description = lib.mdDoc ''
                 LDAP field which is a unique identifier for users on HedgeDoc.
               '';
             };
@@ -869,14 +869,14 @@ in
               type = types.str;
               default = "/etc/ssl/certs/ca-certificates.crt";
               example = "server-cert.pem,root.pem";
-              description = ''
+              description = lib.mdDoc ''
                 Root CA for LDAP TLS in PEM format.
               '';
             };
           };
         });
         default = null;
-        description = "Configure the LDAP integration.";
+        description = lib.mdDoc "Configure the LDAP integration.";
       };
       saml = mkOption {
         type = types.nullOr (types.submodule {
@@ -884,21 +884,21 @@ in
             idpSsoUrl = mkOption {
               type = types.str;
               example = "https://idp.example.com/sso";
-              description = ''
+              description = lib.mdDoc ''
                 IdP authentication endpoint.
               '';
             };
             idpCert = mkOption {
               type = types.path;
               example = "/path/to/cert.pem";
-              description = ''
+              description = lib.mdDoc ''
                 Path to IdP certificate file in PEM format.
               '';
             };
             issuer = mkOption {
               type = types.str;
               default = "";
-              description = ''
+              description = lib.mdDoc ''
                 Optional identity of the service provider.
                 This defaults to the server URL.
               '';
@@ -906,7 +906,7 @@ in
             identifierFormat = mkOption {
               type = types.str;
               default = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress";
-              description = ''
+              description = lib.mdDoc ''
                 Optional name identifier format.
               '';
             };
@@ -914,7 +914,7 @@ in
               type = types.str;
               default = "";
               example = "memberOf";
-              description = ''
+              description = lib.mdDoc ''
                 Optional attribute name for group list.
               '';
             };
@@ -922,7 +922,7 @@ in
               type = types.listOf types.str;
               default = [];
               example = [ "Temporary-staff" "External-users" ];
-              description = ''
+              description = lib.mdDoc ''
                 Excluded group names.
               '';
             };
@@ -930,7 +930,7 @@ in
               type = types.listOf types.str;
               default = [];
               example = [ "Hedgedoc-Users" ];
-              description = ''
+              description = lib.mdDoc ''
                 Required group names.
               '';
             };
@@ -965,16 +965,16 @@ in
           };
         });
         default = null;
-        description = "Configure the SAML integration.";
+        description = lib.mdDoc "Configure the SAML integration.";
       };
     }; in lib.mkOption {
       type = lib.types.submodule {
         freeformType = settingsFormat.type;
         inherit options;
       };
-      description = ''
+      description = lib.mdDoc ''
         HedgeDoc configuration, see
-        <link xlink:href="https://docs.hedgedoc.org/configuration/"/>
+        <https://docs.hedgedoc.org/configuration/>
         for documentation.
       '';
     };
@@ -1013,7 +1013,7 @@ in
       type = types.package;
       default = pkgs.hedgedoc;
       defaultText = literalExpression "pkgs.hedgedoc";
-      description = ''
+      description = lib.mdDoc ''
         Package that provides HedgeDoc.
       '';
     };
diff --git a/nixos/modules/services/web-apps/hledger-web.nix b/nixos/modules/services/web-apps/hledger-web.nix
index 4f6a34e6d2f..4f02a637cdd 100644
--- a/nixos/modules/services/web-apps/hledger-web.nix
+++ b/nixos/modules/services/web-apps/hledger-web.nix
@@ -12,7 +12,7 @@ in {
     host = mkOption {
       type = types.str;
       default = "127.0.0.1";
-      description = ''
+      description = lib.mdDoc ''
         Address to listen on.
       '';
     };
@@ -21,7 +21,7 @@ in {
       type = types.port;
       default = 5000;
       example = 80;
-      description = ''
+      description = lib.mdDoc ''
         Port to listen on.
       '';
     };
@@ -30,21 +30,21 @@ in {
       view = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Enable the view capability.
         '';
       };
       add = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Enable the add capability.
         '';
       };
       manage = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Enable the manage capability.
         '';
       };
@@ -53,7 +53,7 @@ in {
     stateDir = mkOption {
       type = types.path;
       default = "/var/lib/hledger-web";
-      description = ''
+      description = lib.mdDoc ''
         Path the service has access to. If left as the default value this
         directory will automatically be created before the hledger-web server
         starts, otherwise the sysadmin is responsible for ensuring the
@@ -64,8 +64,8 @@ in {
     journalFiles = mkOption {
       type = types.listOf types.str;
       default = [ ".hledger.journal" ];
-      description = ''
-        Paths to journal files relative to <option>services.hledger-web.stateDir</option>.
+      description = lib.mdDoc ''
+        Paths to journal files relative to {option}`services.hledger-web.stateDir`.
       '';
     };
 
@@ -73,7 +73,7 @@ in {
       type = with types; nullOr str;
       default = null;
       example = "https://example.org";
-      description = ''
+      description = lib.mdDoc ''
         Base URL, when sharing over a network.
       '';
     };
@@ -82,7 +82,7 @@ in {
       type = types.listOf types.str;
       default = [];
       example = [ "--forecast" ];
-      description = ''
+      description = lib.mdDoc ''
         Extra command line arguments to pass to hledger-web.
       '';
     };
diff --git a/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix b/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
index b9761061aaa..b96baaec767 100644
--- a/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
+++ b/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
@@ -17,7 +17,7 @@ in {
     pool = mkOption {
       type = str;
       default = poolName;
-      description = ''
+      description = lib.mdDoc ''
          Name of existing PHP-FPM pool that is used to run Icingaweb2.
          If not specified, a pool will automatically created with default values.
       '';
@@ -26,7 +26,7 @@ in {
     libraryPaths = mkOption {
       type = attrsOf package;
       default = { };
-      description = ''
+      description = lib.mdDoc ''
         Libraries to add to the Icingaweb2 library path.
         The name of the attribute is the name of the library, the value
         is the package to add.
@@ -36,7 +36,7 @@ in {
     virtualHost = mkOption {
       type = nullOr str;
       default = "icingaweb2";
-      description = ''
+      description = lib.mdDoc ''
         Name of the nginx virtualhost to use and setup. If null, no virtualhost is set up.
       '';
     };
@@ -45,7 +45,7 @@ in {
       type = str;
       default = "UTC";
       example = "Europe/Berlin";
-      description = "PHP-compliant timezone specification";
+      description = lib.mdDoc "PHP-compliant timezone specification";
     };
 
     modules = {
@@ -64,7 +64,7 @@ in {
           "snow" = icingaweb2Modules.theme-snow;
         }
       '';
-      description = ''
+      description = lib.mdDoc ''
         Name-package attrset of Icingaweb 2 modules packages to enable.
 
         If you enable modules manually (e.g. via the web ui), they will not be touched.
@@ -84,7 +84,7 @@ in {
           level = "CRITICAL";
         };
       };
-      description = ''
+      description = lib.mdDoc ''
         config.ini contents.
         Will automatically be converted to a .ini file.
         If you don't set global.module_path, the module will take care of it.
@@ -108,7 +108,7 @@ in {
           dbname = "icingaweb2";
         };
       };
-      description = ''
+      description = lib.mdDoc ''
         resources.ini contents.
         Will automatically be converted to a .ini file.
 
@@ -127,7 +127,7 @@ in {
           resource = "icingaweb_db";
         };
       };
-      description = ''
+      description = lib.mdDoc ''
         authentication.ini contents.
         Will automatically be converted to a .ini file.
 
@@ -145,7 +145,7 @@ in {
           resource = "icingaweb_db";
         };
       };
-      description = ''
+      description = lib.mdDoc ''
         groups.ini contents.
         Will automatically be converted to a .ini file.
 
@@ -163,7 +163,7 @@ in {
           permissions = "*";
         };
       };
-      description = ''
+      description = lib.mdDoc ''
         roles.ini contents.
         Will automatically be converted to a .ini file.
 
diff --git a/nixos/modules/services/web-apps/icingaweb2/module-monitoring.nix b/nixos/modules/services/web-apps/icingaweb2/module-monitoring.nix
index e9c1d4ffe5e..0579c602216 100644
--- a/nixos/modules/services/web-apps/icingaweb2/module-monitoring.nix
+++ b/nixos/modules/services/web-apps/icingaweb2/module-monitoring.nix
@@ -34,32 +34,32 @@ in {
     enable = mkOption {
       type = bool;
       default = true;
-      description = "Whether to enable the icingaweb2 monitoring module.";
+      description = lib.mdDoc "Whether to enable the icingaweb2 monitoring module.";
     };
 
     generalConfig = {
       mutable = mkOption {
         type = bool;
         default = false;
-        description = "Make config.ini of the monitoring module mutable (e.g. via the web interface).";
+        description = lib.mdDoc "Make config.ini of the monitoring module mutable (e.g. via the web interface).";
       };
 
       protectedVars = mkOption {
         type = listOf str;
         default = [ "*pw*" "*pass*" "community" ];
-        description = "List of string patterns for custom variables which should be excluded from user’s view.";
+        description = lib.mdDoc "List of string patterns for custom variables which should be excluded from user’s view.";
       };
     };
 
     mutableBackends = mkOption {
       type = bool;
       default = false;
-      description = "Make backends.ini of the monitoring module mutable (e.g. via the web interface).";
+      description = lib.mdDoc "Make backends.ini of the monitoring module mutable (e.g. via the web interface).";
     };
 
     backends = mkOption {
       default = { icinga = { resource = "icinga_ido"; }; };
-      description = "Monitoring backends to define";
+      description = lib.mdDoc "Monitoring backends to define";
       type = attrsOf (submodule ({ name, ... }: {
         options = {
           name = mkOption {
@@ -71,13 +71,13 @@ in {
 
           resource = mkOption {
             type = str;
-            description = "Name of the IDO resource";
+            description = lib.mdDoc "Name of the IDO resource";
           };
 
           disabled = mkOption {
             type = bool;
             default = false;
-            description = "Disable this backend";
+            description = lib.mdDoc "Disable this backend";
           };
         };
       }));
@@ -86,12 +86,12 @@ in {
     mutableTransports = mkOption {
       type = bool;
       default = true;
-      description = "Make commandtransports.ini of the monitoring module mutable (e.g. via the web interface).";
+      description = lib.mdDoc "Make commandtransports.ini of the monitoring module mutable (e.g. via the web interface).";
     };
 
     transports = mkOption {
       default = {};
-      description = "Command transports to define";
+      description = lib.mdDoc "Command transports to define";
       type = attrsOf (submodule ({ name, ... }: {
         options = {
           name = mkOption {
@@ -104,44 +104,44 @@ in {
           type = mkOption {
             type = enum [ "api" "local" "remote" ];
             default = "api";
-            description = "Type of  this transport";
+            description = lib.mdDoc "Type of  this transport";
           };
 
           instance = mkOption {
             type = nullOr str;
             default = null;
-            description = "Assign a icinga instance to this transport";
+            description = lib.mdDoc "Assign a icinga instance to this transport";
           };
 
           path = mkOption {
             type = str;
-            description = "Path to the socket for local or remote transports";
+            description = lib.mdDoc "Path to the socket for local or remote transports";
           };
 
           host = mkOption {
             type = str;
-            description = "Host for the api or remote transport";
+            description = lib.mdDoc "Host for the api or remote transport";
           };
 
           port = mkOption {
             type = nullOr str;
             default = null;
-            description = "Port to connect to for the api or remote transport";
+            description = lib.mdDoc "Port to connect to for the api or remote transport";
           };
 
           username = mkOption {
             type = str;
-            description = "Username for the api or remote transport";
+            description = lib.mdDoc "Username for the api or remote transport";
           };
 
           password = mkOption {
             type = str;
-            description = "Password for the api transport";
+            description = lib.mdDoc "Password for the api transport";
           };
 
           resource = mkOption {
             type = str;
-            description = "SSH identity resource for the remote transport";
+            description = lib.mdDoc "SSH identity resource for the remote transport";
           };
         };
       }));
diff --git a/nixos/modules/services/web-apps/ihatemoney/default.nix b/nixos/modules/services/web-apps/ihatemoney/default.nix
index ad314c885ba..c771f0afa23 100644
--- a/nixos/modules/services/web-apps/ihatemoney/default.nix
+++ b/nixos/modules/services/web-apps/ihatemoney/default.nix
@@ -51,42 +51,42 @@ in
       backend = mkOption {
         type = types.enum [ "sqlite" "postgresql" ];
         default = "sqlite";
-        description = ''
+        description = lib.mdDoc ''
           The database engine to use for ihatemoney.
-          If <literal>postgresql</literal> is selected, then a database called
-          <literal>${db}</literal> will be created. If you disable this option,
+          If `postgresql` is selected, then a database called
+          `${db}` will be created. If you disable this option,
           it will however not be removed.
         '';
       };
       adminHashedPassword = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = "The hashed password of the administrator. To obtain it, run <literal>ihatemoney generate_password_hash</literal>";
+        description = lib.mdDoc "The hashed password of the administrator. To obtain it, run `ihatemoney generate_password_hash`";
       };
       uwsgiConfig = mkOption {
         type = types.attrs;
         example = {
           http = ":8000";
         };
-        description = "Additionnal configuration of the UWSGI vassal running ihatemoney. It should notably specify on which interfaces and ports the vassal should listen.";
+        description = lib.mdDoc "Additionnal configuration of the UWSGI vassal running ihatemoney. It should notably specify on which interfaces and ports the vassal should listen.";
       };
       defaultSender = {
         name = mkOption {
           type = types.str;
           default = "Budget manager";
-          description = "The display name of the sender of ihatemoney emails";
+          description = lib.mdDoc "The display name of the sender of ihatemoney emails";
         };
         email = mkOption {
           type = types.str;
           default = "ihatemoney@${config.networking.hostName}";
           defaultText = literalExpression ''"ihatemoney@''${config.networking.hostName}"'';
-          description = "The email of the sender of ihatemoney emails";
+          description = lib.mdDoc "The email of the sender of ihatemoney emails";
         };
       };
       secureCookie = mkOption {
         type = types.bool;
         default = true;
-        description = "Use secure cookies. Disable this when ihatemoney is served via http instead of https";
+        description = lib.mdDoc "Use secure cookies. Disable this when ihatemoney is served via http instead of https";
       };
       enableDemoProject = mkEnableOption "access to the demo project in ihatemoney";
       enablePublicProjectCreation = mkEnableOption "permission to create projects in ihatemoney by anyone";
@@ -95,12 +95,12 @@ in
       legalLink = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = "The URL to a page explaining legal statements about your service, eg. GDPR-related information.";
+        description = lib.mdDoc "The URL to a page explaining legal statements about your service, eg. GDPR-related information.";
       };
       extraConfig = mkOption {
         type = types.str;
         default = "";
-        description = "Extra configuration appended to ihatemoney's configuration file. It is a python file, so pay attention to indentation.";
+        description = lib.mdDoc "Extra configuration appended to ihatemoney's configuration file. It is a python file, so pay attention to indentation.";
       };
     };
     config = mkIf cfg.enable {
diff --git a/nixos/modules/services/web-apps/invidious.nix b/nixos/modules/services/web-apps/invidious.nix
index 10b30bf1fd1..0b9d9b03c6a 100644
--- a/nixos/modules/services/web-apps/invidious.nix
+++ b/nixos/modules/services/web-apps/invidious.nix
@@ -152,27 +152,27 @@ in
       type = types.package;
       default = pkgs.invidious;
       defaultText = "pkgs.invidious";
-      description = "The Invidious package to use.";
+      description = lib.mdDoc "The Invidious package to use.";
     };
 
     settings = lib.mkOption {
       type = settingsFormat.type;
       default = { };
-      description = ''
+      description = lib.mdDoc ''
         The settings Invidious should use.
 
-        See <link xlink:href="https://github.com/iv-org/invidious/blob/master/config/config.example.yml">config.example.yml</link> for a list of all possible options.
+        See [config.example.yml](https://github.com/iv-org/invidious/blob/master/config/config.example.yml) for a list of all possible options.
       '';
     };
 
     extraSettingsFile = lib.mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         A file including Invidious settings.
 
-        It gets merged with the setttings specified in <option>services.invidious.settings</option>
-        and can be used to store secrets like <literal>hmac_key</literal> outside of the nix store.
+        It gets merged with the setttings specified in {option}`services.invidious.settings`
+        and can be used to store secrets like `hmac_key` outside of the nix store.
       '';
     };
 
@@ -182,7 +182,7 @@ in
     domain = lib.mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         The FQDN Invidious is reachable on.
 
         This is used to configure nginx and for building absolute URLs.
@@ -193,12 +193,12 @@ in
       type = types.port;
       # Default from https://docs.invidious.io/Configuration.md
       default = 3000;
-      description = ''
+      description = lib.mdDoc ''
         The port Invidious should listen on.
 
         To allow access from outside,
-        you can use either <option>services.invidious.nginx</option>
-        or add <literal>config.services.invidious.port</literal> to <option>networking.firewall.allowedTCPPorts</option>.
+        you can use either {option}`services.invidious.nginx`
+        or add `config.services.invidious.port` to {option}`networking.firewall.allowedTCPPorts`.
       '';
     };
 
@@ -206,7 +206,7 @@ in
       createLocally = lib.mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to create a local database with PostgreSQL.
         '';
       };
@@ -214,10 +214,10 @@ in
       host = lib.mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           The database host Invidious should use.
 
-          If <literal>null</literal>, the local unix socket is used. Otherwise
+          If `null`, the local unix socket is used. Otherwise
           TCP is used.
         '';
       };
@@ -226,7 +226,7 @@ in
         type = types.port;
         default = options.services.postgresql.port.default;
         defaultText = lib.literalExpression "options.services.postgresql.port.default";
-        description = ''
+        description = lib.mdDoc ''
           The port of the database Invidious should use.
 
           Defaults to the the default postgresql port.
@@ -237,7 +237,7 @@ in
         type = types.nullOr types.str;
         apply = lib.mapNullable toString;
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           Path to file containing the database password.
         '';
       };
diff --git a/nixos/modules/services/web-apps/invoiceplane.nix b/nixos/modules/services/web-apps/invoiceplane.nix
index 527e248f65b..2a936027bd4 100644
--- a/nixos/modules/services/web-apps/invoiceplane.nix
+++ b/nixos/modules/services/web-apps/invoiceplane.nix
@@ -72,7 +72,7 @@ let
         stateDir = mkOption {
           type = types.path;
           default = "/var/lib/invoiceplane/${name}";
-          description = ''
+          description = lib.mdDoc ''
             This directory is used for uploads of attachements and cache.
             The directory passed here is automatically created and permissions
             adjusted as required.
@@ -83,41 +83,41 @@ let
           host = mkOption {
             type = types.str;
             default = "localhost";
-            description = "Database host address.";
+            description = lib.mdDoc "Database host address.";
           };
 
           port = mkOption {
             type = types.port;
             default = 3306;
-            description = "Database host port.";
+            description = lib.mdDoc "Database host port.";
           };
 
           name = mkOption {
             type = types.str;
             default = "invoiceplane";
-            description = "Database name.";
+            description = lib.mdDoc "Database name.";
           };
 
           user = mkOption {
             type = types.str;
             default = "invoiceplane";
-            description = "Database user.";
+            description = lib.mdDoc "Database user.";
           };
 
           passwordFile = mkOption {
             type = types.nullOr types.path;
             default = null;
             example = "/run/keys/invoiceplane-dbpassword";
-            description = ''
+            description = lib.mdDoc ''
               A file containing the password corresponding to
-              <option>database.user</option>.
+              {option}`database.user`.
             '';
           };
 
           createLocally = mkOption {
             type = types.bool;
             default = true;
-            description = "Create the database and database user locally.";
+            description = lib.mdDoc "Create the database and database user locally.";
           };
         };
 
@@ -160,8 +160,8 @@ let
             "pm.max_spare_servers" = 4;
             "pm.max_requests" = 500;
           };
-          description = ''
-            Options for the InvoicePlane PHP pool. See the documentation on <literal>php-fpm.conf</literal>
+          description = lib.mdDoc ''
+            Options for the InvoicePlane PHP pool. See the documentation on `php-fpm.conf`
             for details on configuration directives.
           '';
         };
@@ -174,9 +174,9 @@ let
             DISABLE_SETUP=true
             IP_URL=https://invoice.example.com
           '';
-          description = ''
+          description = lib.mdDoc ''
             InvoicePlane configuration. Refer to
-            <link xlink:href="https://github.com/InvoicePlane/InvoicePlane/blob/master/ipconfig.php.example"/>
+            <https://github.com/InvoicePlane/InvoicePlane/blob/master/ipconfig.php.example>
             for details on supported values.
           '';
         };
@@ -194,20 +194,20 @@ in
         options.sites = mkOption {
           type = types.attrsOf (types.submodule siteOpts);
           default = {};
-          description = "Specification of one or more WordPress sites to serve";
+          description = lib.mdDoc "Specification of one or more WordPress sites to serve";
         };
 
         options.webserver = mkOption {
           type = types.enum [ "caddy" ];
           default = "caddy";
-          description = ''
+          description = lib.mdDoc ''
             Which webserver to use for virtual host management. Currently only
             caddy is supported.
           '';
         };
       };
       default = {};
-      description = "InvoicePlane configuration.";
+      description = lib.mdDoc "InvoicePlane configuration.";
     };
 
   };
diff --git a/nixos/modules/services/web-apps/jitsi-meet.nix b/nixos/modules/services/web-apps/jitsi-meet.nix
index 8ad92706b06..b38a510bb87 100644
--- a/nixos/modules/services/web-apps/jitsi-meet.nix
+++ b/nixos/modules/services/web-apps/jitsi-meet.nix
@@ -51,7 +51,7 @@ in
     hostName = mkOption {
       type = str;
       example = "meet.example.org";
-      description = ''
+      description = lib.mdDoc ''
         FQDN of the Jitsi Meet instance.
       '';
     };
@@ -65,10 +65,10 @@ in
           defaultLang = "fi";
         }
       '';
-      description = ''
-        Client-side web application settings that override the defaults in <filename>config.js</filename>.
+      description = lib.mdDoc ''
+        Client-side web application settings that override the defaults in {file}`config.js`.
 
-        See <link xlink:href="https://github.com/jitsi/jitsi-meet/blob/master/config.js" /> for default
+        See <https://github.com/jitsi/jitsi-meet/blob/master/config.js> for default
         configuration with comments.
       '';
     };
@@ -76,8 +76,8 @@ in
     extraConfig = mkOption {
       type = lines;
       default = "";
-      description = ''
-        Text to append to <filename>config.js</filename> web application config file.
+      description = lib.mdDoc ''
+        Text to append to {file}`config.js` web application config file.
 
         Can be used to insert JavaScript logic to determine user's region in cascading bridges setup.
       '';
@@ -92,10 +92,10 @@ in
           SHOW_WATERMARK_FOR_GUESTS = false;
         }
       '';
-      description = ''
-        Client-side web-app interface settings that override the defaults in <filename>interface_config.js</filename>.
+      description = lib.mdDoc ''
+        Client-side web-app interface settings that override the defaults in {file}`interface_config.js`.
 
-        See <link xlink:href="https://github.com/jitsi/jitsi-meet/blob/master/interface_config.js" /> for
+        See <https://github.com/jitsi/jitsi-meet/blob/master/interface_config.js> for
         default configuration with comments.
       '';
     };
@@ -104,10 +104,10 @@ in
       enable = mkOption {
         type = bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable Jitsi Videobridge instance and configure it to connect to Prosody.
 
-          Additional configuration is possible with <option>services.jitsi-videobridge</option>.
+          Additional configuration is possible with {option}`services.jitsi-videobridge`.
         '';
       };
 
@@ -115,10 +115,10 @@ in
         type = nullOr str;
         default = null;
         example = "/run/keys/videobridge";
-        description = ''
+        description = lib.mdDoc ''
           File containing password to the Prosody account for videobridge.
 
-          If <literal>null</literal>, a file with password will be generated automatically. Setting
+          If `null`, a file with password will be generated automatically. Setting
           this option is useful if you plan to connect additional videobridges to the XMPP server.
         '';
       };
@@ -127,35 +127,35 @@ in
     jicofo.enable = mkOption {
       type = bool;
       default = true;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable JiCoFo instance and configure it to connect to Prosody.
 
-        Additional configuration is possible with <option>services.jicofo</option>.
+        Additional configuration is possible with {option}`services.jicofo`.
       '';
     };
 
     jibri.enable = mkOption {
       type = bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable a Jibri instance and configure it to connect to Prosody.
 
-        Additional configuration is possible with <option>services.jibri</option>, and
-        <option>services.jibri.finalizeScript</option> is especially useful.
+        Additional configuration is possible with {option}`services.jibri`, and
+        {option}`services.jibri.finalizeScript` is especially useful.
       '';
     };
 
     nginx.enable = mkOption {
       type = bool;
       default = true;
-      description = ''
+      description = lib.mdDoc ''
         Whether to enable nginx virtual host that will serve the javascript application and act as
         a proxy for the XMPP server. Further nginx configuration can be done by adapting
-        <option>services.nginx.virtualHosts.&lt;hostName&gt;</option>.
+        {option}`services.nginx.virtualHosts.<hostName>`.
         When this is enabled, ACME will be used to retrieve a TLS certificate by default. To disable
-        this, set the <option>services.nginx.virtualHosts.&lt;hostName&gt;.enableACME</option> to
-        <literal>false</literal> and if appropriate do the same for
-        <option>services.nginx.virtualHosts.&lt;hostName&gt;.forceSSL</option>.
+        this, set the {option}`services.nginx.virtualHosts.<hostName>.enableACME` to
+        `false` and if appropriate do the same for
+        {option}`services.nginx.virtualHosts.<hostName>.forceSSL`.
       '';
     };
 
@@ -164,7 +164,7 @@ in
     prosody.enable = mkOption {
       type = bool;
       default = true;
-      description = ''
+      description = lib.mdDoc ''
         Whether to configure Prosody to relay XMPP messages between Jitsi Meet components. Turn this
         off if you want to configure it manually.
       '';
diff --git a/nixos/modules/services/web-apps/keycloak.nix b/nixos/modules/services/web-apps/keycloak.nix
index a1855e1c1a7..de76babbaed 100644
--- a/nixos/modules/services/web-apps/keycloak.nix
+++ b/nixos/modules/services/web-apps/keycloak.nix
@@ -98,7 +98,7 @@ in
         type = bool;
         default = false;
         example = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to enable the Keycloak identity and access management
           server.
         '';
@@ -109,7 +109,7 @@ in
         default = null;
         example = "/run/keys/ssl_cert";
         apply = assertStringPath "sslCertificate";
-        description = ''
+        description = lib.mdDoc ''
           The path to a PEM formatted certificate to use for TLS/SSL
           connections.
         '';
@@ -120,7 +120,7 @@ in
         default = null;
         example = "/run/keys/ssl_key";
         apply = assertStringPath "sslCertificateKey";
-        description = ''
+        description = lib.mdDoc ''
           The path to a PEM formatted private key to use for TLS/SSL
           connections.
         '';
@@ -129,10 +129,10 @@ in
       plugins = lib.mkOption {
         type = lib.types.listOf lib.types.path;
         default = [ ];
-        description = ''
+        description = lib.mdDoc ''
           Keycloak plugin jar, ear files or derivations containing
           them. Packaged plugins are available through
-          <literal>pkgs.keycloak.plugins</literal>.
+          `pkgs.keycloak.plugins`.
         '';
       };
 
@@ -141,7 +141,7 @@ in
           type = enum [ "mysql" "mariadb" "postgresql" ];
           default = "postgresql";
           example = "mariadb";
-          description = ''
+          description = lib.mdDoc ''
             The type of database Keycloak should connect to.
           '';
         };
@@ -149,7 +149,7 @@ in
         host = mkOption {
           type = str;
           default = "localhost";
-          description = ''
+          description = lib.mdDoc ''
             Hostname of the database to connect to.
           '';
         };
@@ -166,7 +166,7 @@ in
             type = port;
             default = dbPorts.${cfg.database.type};
             defaultText = literalDocBook "default port of selected database";
-            description = ''
+            description = lib.mdDoc ''
               Port of the database to connect to.
             '';
           };
@@ -175,7 +175,7 @@ in
           type = bool;
           default = cfg.database.host != "localhost";
           defaultText = literalExpression ''config.${opt.database.host} != "localhost"'';
-          description = ''
+          description = lib.mdDoc ''
             Whether the database connection should be secured by SSL /
             TLS.
           '';
@@ -184,13 +184,13 @@ in
         caCert = mkOption {
           type = nullOr path;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             The SSL / TLS CA certificate that verifies the identity of the
             database server.
 
             Required when PostgreSQL is used and SSL is turned on.
 
-            For MySQL, if left at <literal>null</literal>, the default
+            For MySQL, if left at `null`, the default
             Java keystore is used, which should suffice if the server
             certificate is issued by an official CA.
           '';
@@ -199,7 +199,7 @@ in
         createLocally = mkOption {
           type = bool;
           default = true;
-          description = ''
+          description = lib.mdDoc ''
             Whether a database should be automatically created on the
             local host. Set this to false if you plan on provisioning a
             local database yourself. This has no effect if
@@ -241,7 +241,7 @@ in
           type = path;
           example = "/run/keys/db_password";
           apply = assertStringPath "passwordFile";
-          description = ''
+          description = lib.mdDoc ''
             The path to a file containing the database password.
           '';
         };
@@ -251,7 +251,7 @@ in
         type = package;
         default = pkgs.keycloak;
         defaultText = literalExpression "pkgs.keycloak";
-        description = ''
+        description = lib.mdDoc ''
           Keycloak package to use.
         '';
       };
@@ -259,8 +259,8 @@ in
       initialAdminPassword = mkOption {
         type = str;
         default = "changeme";
-        description = ''
-          Initial password set for the <literal>admin</literal>
+        description = lib.mdDoc ''
+          Initial password set for the `admin`
           user. The password is not stored safely and should be changed
           immediately in the admin panel.
         '';
@@ -269,13 +269,13 @@ in
       themes = mkOption {
         type = attrsOf package;
         default = { };
-        description = ''
+        description = lib.mdDoc ''
           Additional theme packages for Keycloak. Each theme is linked into
           subdirectory with a corresponding attribute name.
 
           Theme packages consist of several subdirectories which provide
-          different theme types: for example, <literal>account</literal>,
-          <literal>login</literal> etc. After adding a theme to this option you
+          different theme types: for example, `account`,
+          `login` etc. After adding a theme to this option you
           can select it by its name in Keycloak administration console.
         '';
       };
@@ -289,7 +289,7 @@ in
               type = str;
               default = "0.0.0.0";
               example = "127.0.0.1";
-              description = ''
+              description = lib.mdDoc ''
                 On which address Keycloak should accept new connections.
               '';
             };
@@ -298,7 +298,7 @@ in
               type = port;
               default = 80;
               example = 8080;
-              description = ''
+              description = lib.mdDoc ''
                 On which port Keycloak should listen for new HTTP connections.
               '';
             };
@@ -307,7 +307,7 @@ in
               type = port;
               default = 443;
               example = 8443;
-              description = ''
+              description = lib.mdDoc ''
                 On which port Keycloak should listen for new HTTPS connections.
               '';
             };
@@ -341,11 +341,11 @@ in
             hostname = mkOption {
               type = str;
               example = "keycloak.example.com";
-              description = ''
+              description = lib.mdDoc ''
                 The hostname part of the public URL used as base for
                 all frontend requests.
 
-                See <link xlink:href="https://www.keycloak.org/server/hostname" />
+                See <https://www.keycloak.org/server/hostname>
                 for more information about hostname configuration.
               '';
             };
@@ -354,14 +354,14 @@ in
               type = bool;
               default = false;
               example = true;
-              description = ''
+              description = lib.mdDoc ''
                 Whether Keycloak should force all requests to go
                 through the frontend URL. By default, Keycloak allows
                 backend requests to instead use its local hostname or
                 IP address and may also advertise it to clients
                 through its OpenID Connect Discovery endpoint.
 
-                See <link xlink:href="https://www.keycloak.org/server/hostname" />
+                See <https://www.keycloak.org/server/hostname>
                 for more information about hostname configuration.
               '';
             };
diff --git a/nixos/modules/services/web-apps/lemmy.nix b/nixos/modules/services/web-apps/lemmy.nix
index 15e616c5d5e..3e726149e93 100644
--- a/nixos/modules/services/web-apps/lemmy.nix
+++ b/nixos/modules/services/web-apps/lemmy.nix
@@ -16,14 +16,14 @@ in
 
     jwtSecretPath = mkOption {
       type = types.path;
-      description = "Path to read the jwt secret from.";
+      description = lib.mdDoc "Path to read the jwt secret from.";
     };
 
     ui = {
       port = mkOption {
         type = types.port;
         default = 1234;
-        description = "Port where lemmy-ui should listen for incoming requests.";
+        description = lib.mdDoc "Port where lemmy-ui should listen for incoming requests.";
       };
     };
 
@@ -31,7 +31,7 @@ in
 
     settings = mkOption {
       default = { };
-      description = "Lemmy configuration";
+      description = lib.mdDoc "Lemmy configuration";
 
       type = types.submodule {
         freeformType = settingsFormat.type;
@@ -39,13 +39,13 @@ in
         options.hostname = mkOption {
           type = types.str;
           default = null;
-          description = "The domain name of your instance (eg 'lemmy.ml').";
+          description = lib.mdDoc "The domain name of your instance (eg 'lemmy.ml').";
         };
 
         options.port = mkOption {
           type = types.port;
           default = 8536;
-          description = "Port where lemmy should listen for incoming requests.";
+          description = lib.mdDoc "Port where lemmy should listen for incoming requests.";
         };
 
         options.federation = {
@@ -56,12 +56,12 @@ in
           enabled = mkOption {
             type = types.bool;
             default = true;
-            description = "Enable Captcha.";
+            description = lib.mdDoc "Enable Captcha.";
           };
           difficulty = mkOption {
             type = types.enum [ "easy" "medium" "hard" ];
             default = "medium";
-            description = "The difficultly of the captcha to solve.";
+            description = lib.mdDoc "The difficultly of the captcha to solve.";
           };
         };
 
diff --git a/nixos/modules/services/web-apps/mastodon.nix b/nixos/modules/services/web-apps/mastodon.nix
index 03adaadff93..f3f0fb7cb53 100644
--- a/nixos/modules/services/web-apps/mastodon.nix
+++ b/nixos/modules/services/web-apps/mastodon.nix
@@ -148,7 +148,7 @@ in {
       };
 
       group = lib.mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Group under which mastodon runs.
         '';
         type = lib.types.str;
@@ -156,12 +156,12 @@ in {
       };
 
       streamingPort = lib.mkOption {
-        description = "TCP port used by the mastodon-streaming service.";
+        description = lib.mdDoc "TCP port used by the mastodon-streaming service.";
         type = lib.types.port;
         default = 55000;
       };
       streamingProcesses = lib.mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Processes used by the mastodon-streaming service.
           Defaults to the number of CPU cores minus one.
         '';
@@ -170,28 +170,28 @@ in {
       };
 
       webPort = lib.mkOption {
-        description = "TCP port used by the mastodon-web service.";
+        description = lib.mdDoc "TCP port used by the mastodon-web service.";
         type = lib.types.port;
         default = 55001;
       };
       webProcesses = lib.mkOption {
-        description = "Processes used by the mastodon-web service.";
+        description = lib.mdDoc "Processes used by the mastodon-web service.";
         type = lib.types.int;
         default = 2;
       };
       webThreads = lib.mkOption {
-        description = "Threads per process used by the mastodon-web service.";
+        description = lib.mdDoc "Threads per process used by the mastodon-web service.";
         type = lib.types.int;
         default = 5;
       };
 
       sidekiqPort = lib.mkOption {
-        description = "TCP port used by the mastodon-sidekiq service.";
+        description = lib.mdDoc "TCP port used by the mastodon-sidekiq service.";
         type = lib.types.port;
         default = 55002;
       };
       sidekiqThreads = lib.mkOption {
-        description = "Worker threads used by the mastodon-sidekiq service.";
+        description = lib.mdDoc "Worker threads used by the mastodon-sidekiq service.";
         type = lib.types.int;
         default = 25;
       };
@@ -212,7 +212,7 @@ in {
       };
 
       localDomain = lib.mkOption {
-        description = "The domain serving your Mastodon instance.";
+        description = lib.mdDoc "The domain serving your Mastodon instance.";
         example = "social.example.org";
         type = lib.types.str;
       };
@@ -259,7 +259,7 @@ in {
       };
 
       trustedProxy = lib.mkOption {
-        description = ''
+        description = lib.mdDoc ''
           You need to set it to the IP from which your reverse proxy sends requests to Mastodon's web process,
           otherwise Mastodon will record the reverse proxy's own IP as the IP of all requests, which would be
           bad because IP addresses are used for important rate limits and security functions.
@@ -269,7 +269,7 @@ in {
       };
 
       enableUnixSocket = lib.mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Instead of binding to an IP address like 127.0.0.1, you may bind to a Unix socket. This variable
           is process-specific, e.g. you need different values for every process, and it works for both web (Puma)
           processes and streaming API (Node.js) processes.
@@ -280,19 +280,19 @@ in {
 
       redis = {
         createLocally = lib.mkOption {
-          description = "Configure local Redis server for Mastodon.";
+          description = lib.mdDoc "Configure local Redis server for Mastodon.";
           type = lib.types.bool;
           default = true;
         };
 
         host = lib.mkOption {
-          description = "Redis host.";
+          description = lib.mdDoc "Redis host.";
           type = lib.types.str;
           default = "127.0.0.1";
         };
 
         port = lib.mkOption {
-          description = "Redis port.";
+          description = lib.mdDoc "Redis port.";
           type = lib.types.port;
           default = 31637;
         };
@@ -300,7 +300,7 @@ in {
 
       database = {
         createLocally = lib.mkOption {
-          description = "Configure local PostgreSQL database server for Mastodon.";
+          description = lib.mdDoc "Configure local PostgreSQL database server for Mastodon.";
           type = lib.types.bool;
           default = true;
         };
@@ -309,75 +309,75 @@ in {
           type = lib.types.str;
           default = "/run/postgresql";
           example = "192.168.23.42";
-          description = "Database host address or unix socket.";
+          description = lib.mdDoc "Database host address or unix socket.";
         };
 
         port = lib.mkOption {
           type = lib.types.int;
           default = 5432;
-          description = "Database host port.";
+          description = lib.mdDoc "Database host port.";
         };
 
         name = lib.mkOption {
           type = lib.types.str;
           default = "mastodon";
-          description = "Database name.";
+          description = lib.mdDoc "Database name.";
         };
 
         user = lib.mkOption {
           type = lib.types.str;
           default = "mastodon";
-          description = "Database user.";
+          description = lib.mdDoc "Database user.";
         };
 
         passwordFile = lib.mkOption {
           type = lib.types.nullOr lib.types.path;
           default = "/var/lib/mastodon/secrets/db-password";
           example = "/run/keys/mastodon-db-password";
-          description = ''
+          description = lib.mdDoc ''
             A file containing the password corresponding to
-            <option>database.user</option>.
+            {option}`database.user`.
           '';
         };
       };
 
       smtp = {
         createLocally = lib.mkOption {
-          description = "Configure local Postfix SMTP server for Mastodon.";
+          description = lib.mdDoc "Configure local Postfix SMTP server for Mastodon.";
           type = lib.types.bool;
           default = true;
         };
 
         authenticate = lib.mkOption {
-          description = "Authenticate with the SMTP server using username and password.";
+          description = lib.mdDoc "Authenticate with the SMTP server using username and password.";
           type = lib.types.bool;
           default = false;
         };
 
         host = lib.mkOption {
-          description = "SMTP host used when sending emails to users.";
+          description = lib.mdDoc "SMTP host used when sending emails to users.";
           type = lib.types.str;
           default = "127.0.0.1";
         };
 
         port = lib.mkOption {
-          description = "SMTP port used when sending emails to users.";
+          description = lib.mdDoc "SMTP port used when sending emails to users.";
           type = lib.types.port;
           default = 25;
         };
 
         fromAddress = lib.mkOption {
-          description = ''"From" address used when sending Emails to users.'';
+          description = lib.mdDoc ''"From" address used when sending Emails to users.'';
           type = lib.types.str;
         };
 
         user = lib.mkOption {
-          description = "SMTP login name.";
+          description = lib.mdDoc "SMTP login name.";
           type = lib.types.str;
         };
 
         passwordFile = lib.mkOption {
-          description = ''
+          description = lib.mdDoc ''
             Path to file containing the SMTP password.
           '';
           default = "/var/lib/mastodon/secrets/smtp-password";
@@ -388,7 +388,7 @@ in {
 
       elasticsearch = {
         host = lib.mkOption {
-          description = ''
+          description = lib.mdDoc ''
             Elasticsearch host.
             If it is not null, Elasticsearch full text search will be enabled.
           '';
@@ -397,7 +397,7 @@ in {
         };
 
         port = lib.mkOption {
-          description = "Elasticsearch port.";
+          description = lib.mdDoc "Elasticsearch port.";
           type = lib.types.port;
           default = 9200;
         };
@@ -407,13 +407,13 @@ in {
         type = lib.types.package;
         default = pkgs.mastodon;
         defaultText = lib.literalExpression "pkgs.mastodon";
-        description = "Mastodon package to use.";
+        description = lib.mdDoc "Mastodon package to use.";
       };
 
       extraConfig = lib.mkOption {
         type = lib.types.attrs;
         default = {};
-        description = ''
+        description = lib.mdDoc ''
           Extra environment variables to pass to all mastodon services.
         '';
       };
@@ -421,7 +421,7 @@ in {
       automaticMigrations = lib.mkOption {
         type = lib.types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Do automatic database migrations.
         '';
       };
diff --git a/nixos/modules/services/web-apps/mattermost.nix b/nixos/modules/services/web-apps/mattermost.nix
index 2901f307dc5..6e9e2abcaa8 100644
--- a/nixos/modules/services/web-apps/mattermost.nix
+++ b/nixos/modules/services/web-apps/mattermost.nix
@@ -107,19 +107,19 @@ in
         type = types.package;
         default = pkgs.mattermost;
         defaultText = "pkgs.mattermost";
-        description = "Mattermost derivation to use.";
+        description = lib.mdDoc "Mattermost derivation to use.";
       };
 
       statePath = mkOption {
         type = types.str;
         default = "/var/lib/mattermost";
-        description = "Mattermost working directory";
+        description = lib.mdDoc "Mattermost working directory";
       };
 
       siteUrl = mkOption {
         type = types.str;
         example = "https://chat.example.com";
-        description = ''
+        description = lib.mdDoc ''
           URL this Mattermost instance is reachable under, without trailing slash.
         '';
       };
@@ -127,14 +127,14 @@ in
       siteName = mkOption {
         type = types.str;
         default = "Mattermost";
-        description = "Name of this Mattermost site.";
+        description = lib.mdDoc "Name of this Mattermost site.";
       };
 
       listenAddress = mkOption {
         type = types.str;
         default = ":8065";
         example = "[::1]:8065";
-        description = ''
+        description = lib.mdDoc ''
           Address and port this Mattermost instance listens to.
         '';
       };
@@ -142,7 +142,7 @@ in
       mutableConfig = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether the Mattermost config.json is writeable by Mattermost.
 
           Most of the settings can be edited in the system console of
@@ -159,7 +159,7 @@ in
       preferNixConfig = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           If both mutableConfig and this option are set, the Nix configuration
           will take precedence over any settings configured in the server
           console.
@@ -169,7 +169,7 @@ in
       extraConfig = mkOption {
         type = types.attrs;
         default = { };
-        description = ''
+        description = lib.mdDoc ''
           Addtional configuration options as Nix attribute set in config.json schema.
         '';
       };
@@ -178,7 +178,7 @@ in
         type = types.listOf (types.oneOf [types.path types.package]);
         default = [];
         example = "[ ./com.github.moussetc.mattermost.plugin.giphy-2.0.0.tar.gz ]";
-        description = ''
+        description = lib.mdDoc ''
           Plugins to add to the configuration. Overrides any installed if non-null.
           This is a list of paths to .tar.gz files or derivations evaluating to
           .tar.gz files.
@@ -188,7 +188,7 @@ in
       localDatabaseCreate = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Create a local PostgreSQL database for Mattermost automatically.
         '';
       };
@@ -196,7 +196,7 @@ in
       localDatabaseName = mkOption {
         type = types.str;
         default = "mattermost";
-        description = ''
+        description = lib.mdDoc ''
           Local Mattermost database name.
         '';
       };
@@ -204,7 +204,7 @@ in
       localDatabaseUser = mkOption {
         type = types.str;
         default = "mattermost";
-        description = ''
+        description = lib.mdDoc ''
           Local Mattermost database username.
         '';
       };
@@ -212,7 +212,7 @@ in
       localDatabasePassword = mkOption {
         type = types.str;
         default = "mmpgsecret";
-        description = ''
+        description = lib.mdDoc ''
           Password for local Mattermost database user.
         '';
       };
@@ -220,7 +220,7 @@ in
       user = mkOption {
         type = types.str;
         default = "mattermost";
-        description = ''
+        description = lib.mdDoc ''
           User which runs the Mattermost service.
         '';
       };
@@ -228,7 +228,7 @@ in
       group = mkOption {
         type = types.str;
         default = "mattermost";
-        description = ''
+        description = lib.mdDoc ''
           Group which runs the Mattermost service.
         '';
       };
@@ -239,13 +239,13 @@ in
           type = types.package;
           default = pkgs.matterircd;
           defaultText = "pkgs.matterircd";
-          description = "matterircd derivation to use.";
+          description = lib.mdDoc "matterircd derivation to use.";
         };
         parameters = mkOption {
           type = types.listOf types.str;
           default = [ ];
           example = [ "-mmserver chat.example.com" "-bind [::]:6667" ];
-          description = ''
+          description = lib.mdDoc ''
             Set commandline parameters to pass to matterircd. See
             https://github.com/42wim/matterircd#usage for more information.
           '';
diff --git a/nixos/modules/services/web-apps/miniflux.nix b/nixos/modules/services/web-apps/miniflux.nix
index 641c9be85d8..55e3664bee6 100644
--- a/nixos/modules/services/web-apps/miniflux.nix
+++ b/nixos/modules/services/web-apps/miniflux.nix
@@ -29,9 +29,9 @@ in
             LISTEN_ADDR = "localhost:8080";
           }
         '';
-        description = ''
+        description = lib.mdDoc ''
           Configuration for Miniflux, refer to
-          <link xlink:href="https://miniflux.app/docs/configuration.html"/>
+          <https://miniflux.app/docs/configuration.html>
           for documentation on the supported values.
 
           Correct configuration for the database is already provided.
@@ -41,7 +41,7 @@ in
 
       adminCredentialsFile = mkOption  {
         type = types.path;
-        description = ''
+        description = lib.mdDoc ''
           File containing the ADMIN_USERNAME and
           ADMIN_PASSWORD (length >= 6) in the format of
           an EnvironmentFile=, as described by systemd.exec(5).
diff --git a/nixos/modules/services/web-apps/netbox.nix b/nixos/modules/services/web-apps/netbox.nix
index a7d8bede74b..2826e57f2c7 100644
--- a/nixos/modules/services/web-apps/netbox.nix
+++ b/nixos/modules/services/web-apps/netbox.nix
@@ -59,18 +59,18 @@ in {
     enable = mkOption {
       type = lib.types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Enable Netbox.
 
-        This module requires a reverse proxy that serves <literal>/static</literal> separately.
-        See this <link xlink:href="https://github.com/netbox-community/netbox/blob/develop/contrib/nginx.conf/">example</link> on how to configure this.
+        This module requires a reverse proxy that serves `/static` separately.
+        See this [example](https://github.com/netbox-community/netbox/blob/develop/contrib/nginx.conf/) on how to configure this.
       '';
     };
 
     listenAddress = mkOption {
       type = types.str;
       default = "[::1]";
-      description = ''
+      description = lib.mdDoc ''
         Address the server will listen on.
       '';
     };
@@ -78,7 +78,7 @@ in {
     port = mkOption {
       type = types.port;
       default = 8001;
-      description = ''
+      description = lib.mdDoc ''
         Port the server will listen on.
       '';
     };
@@ -89,7 +89,7 @@ in {
       defaultText = literalExpression ''
         python3Packages: with python3Packages; [];
       '';
-      description = ''
+      description = lib.mdDoc ''
         List of plugin packages to install.
       '';
     };
@@ -97,14 +97,14 @@ in {
     dataDir = mkOption {
       type = types.str;
       default = "/var/lib/netbox";
-      description = ''
+      description = lib.mdDoc ''
         Storage path of netbox.
       '';
     };
 
     secretKeyFile = mkOption {
       type = types.path;
-      description = ''
+      description = lib.mdDoc ''
         Path to a file containing the secret key.
       '';
     };
@@ -112,28 +112,28 @@ in {
     extraConfig = mkOption {
       type = types.lines;
       default = "";
-      description = ''
-        Additional lines of configuration appended to the <literal>configuration.py</literal>.
-        See the <link xlink:href="https://netbox.readthedocs.io/en/stable/configuration/optional-settings/">documentation</link> for more possible options.
+      description = lib.mdDoc ''
+        Additional lines of configuration appended to the `configuration.py`.
+        See the [documentation](https://netbox.readthedocs.io/en/stable/configuration/optional-settings/) for more possible options.
       '';
     };
 
     enableLdap = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Enable LDAP-Authentication for Netbox.
 
-        This requires a configuration file being pass through <literal>ldapConfigPath</literal>.
+        This requires a configuration file being pass through `ldapConfigPath`.
       '';
     };
 
     ldapConfigPath = mkOption {
       type = types.path;
       default = "";
-      description = ''
-        Path to the Configuration-File for LDAP-Authentification, will be loaded as <literal>ldap_config.py</literal>.
-        See the <link xlink:href="https://netbox.readthedocs.io/en/stable/installation/6-ldap/#configuration">documentation</link> for possible options.
+      description = lib.mdDoc ''
+        Path to the Configuration-File for LDAP-Authentification, will be loaded as `ldap_config.py`.
+        See the [documentation](https://netbox.readthedocs.io/en/stable/installation/6-ldap/#configuration) for possible options.
       '';
     };
   };
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index f8082d7544c..618ad85b860 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -82,12 +82,12 @@ in {
     enable = mkEnableOption "nextcloud";
     hostName = mkOption {
       type = types.str;
-      description = "FQDN for the nextcloud instance.";
+      description = lib.mdDoc "FQDN for the nextcloud instance.";
     };
     home = mkOption {
       type = types.str;
       default = "/var/lib/nextcloud";
-      description = "Storage path of nextcloud.";
+      description = lib.mdDoc "Storage path of nextcloud.";
     };
     datadir = mkOption {
       type = types.str;
@@ -146,23 +146,23 @@ in {
     logLevel = mkOption {
       type = types.ints.between 0 4;
       default = 2;
-      description = "Log level value between 0 (DEBUG) and 4 (FATAL).";
+      description = lib.mdDoc "Log level value between 0 (DEBUG) and 4 (FATAL).";
     };
     https = mkOption {
       type = types.bool;
       default = false;
-      description = "Use https for generated links.";
+      description = lib.mdDoc "Use https for generated links.";
     };
     package = mkOption {
       type = types.package;
-      description = "Which package to use for the Nextcloud instance.";
+      description = lib.mdDoc "Which package to use for the Nextcloud instance.";
       relatedPackages = [ "nextcloud23" "nextcloud24" ];
     };
     phpPackage = mkOption {
       type = types.package;
       relatedPackages = [ "php80" "php81" ];
       defaultText = "pkgs.php";
-      description = ''
+      description = lib.mdDoc ''
         PHP package to use for Nextcloud.
       '';
     };
@@ -170,7 +170,7 @@ in {
     maxUploadSize = mkOption {
       default = "512M";
       type = types.str;
-      description = ''
+      description = lib.mdDoc ''
         Defines the upload limit for files. This changes the relevant options
         in php.ini and nginx if enabled.
       '';
@@ -179,7 +179,7 @@ in {
     skeletonDirectory = mkOption {
       default = "";
       type = types.str;
-      description = ''
+      description = lib.mdDoc ''
         The directory where the skeleton files are located. These files will be
         copied to the data directory of new users. Leave empty to not copy any
         skeleton files.
@@ -189,7 +189,7 @@ in {
     webfinger = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Enable this option if you plan on using the webfinger plugin.
         The appropriate nginx rewrite rules will be added to your configuration.
       '';
@@ -199,7 +199,7 @@ in {
       type = with types; functionTo (listOf package);
       default = all: [];
       defaultText = literalExpression "all: []";
-      description = ''
+      description = lib.mdDoc ''
         Additional PHP extensions to use for nextcloud.
         By default, only extensions necessary for a vanilla nextcloud installation are enabled,
         but you may choose from the list of available extensions and add further ones.
@@ -226,7 +226,7 @@ in {
         "openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt";
         catch_workers_output = "yes";
       };
-      description = ''
+      description = lib.mdDoc ''
         Options for PHP's php.ini file for nextcloud.
       '';
     };
@@ -241,16 +241,16 @@ in {
         "pm.max_spare_servers" = "4";
         "pm.max_requests" = "500";
       };
-      description = ''
-        Options for nextcloud's PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives.
+      description = lib.mdDoc ''
+        Options for nextcloud's PHP pool. See the documentation on `php-fpm.conf` for details on configuration directives.
       '';
     };
 
     poolConfig = mkOption {
       type = types.nullOr types.lines;
       default = null;
-      description = ''
-        Options for nextcloud's PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives.
+      description = lib.mdDoc ''
+        Options for nextcloud's PHP pool. See the documentation on `php-fpm.conf` for details on configuration directives.
       '';
     };
 
@@ -259,7 +259,7 @@ in {
       createLocally = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Create the database and database user locally. Only available for
           mysql database.
           Note that this option will use the latest version of MariaDB which
@@ -275,72 +275,72 @@ in {
       dbtype = mkOption {
         type = types.enum [ "sqlite" "pgsql" "mysql" ];
         default = "sqlite";
-        description = "Database type.";
+        description = lib.mdDoc "Database type.";
       };
       dbname = mkOption {
         type = types.nullOr types.str;
         default = "nextcloud";
-        description = "Database name.";
+        description = lib.mdDoc "Database name.";
       };
       dbuser = mkOption {
         type = types.nullOr types.str;
         default = "nextcloud";
-        description = "Database user.";
+        description = lib.mdDoc "Database user.";
       };
       dbpassFile = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = ''
+        description = lib.mdDoc ''
           The full path to a file that contains the database password.
         '';
       };
       dbhost = mkOption {
         type = types.nullOr types.str;
         default = "localhost";
-        description = ''
+        description = lib.mdDoc ''
           Database host.
 
           Note: for using Unix authentication with PostgreSQL, this should be
-          set to <literal>/run/postgresql</literal>.
+          set to `/run/postgresql`.
         '';
       };
       dbport = mkOption {
         type = with types; nullOr (either int str);
         default = null;
-        description = "Database port.";
+        description = lib.mdDoc "Database port.";
       };
       dbtableprefix = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = "Table prefix in Nextcloud database.";
+        description = lib.mdDoc "Table prefix in Nextcloud database.";
       };
       adminuser = mkOption {
         type = types.str;
         default = "root";
-        description = "Admin username.";
+        description = lib.mdDoc "Admin username.";
       };
       adminpassFile = mkOption {
         type = types.str;
-        description = ''
+        description = lib.mdDoc ''
           The full path to a file that contains the admin's password. Must be
-          readable by user <literal>nextcloud</literal>.
+          readable by user `nextcloud`.
         '';
       };
 
       extraTrustedDomains = mkOption {
         type = types.listOf types.str;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           Trusted domains, from which the nextcloud installation will be
           acessible.  You don't need to add
-          <literal>services.nextcloud.hostname</literal> here.
+          `services.nextcloud.hostname` here.
         '';
       };
 
       trustedProxies = mkOption {
         type = types.listOf types.str;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           Trusted proxies, to provide if the nextcloud installation is being
           proxied to secure against e.g. spoofing.
         '';
@@ -351,10 +351,10 @@ in {
         default = null;
         example = "https";
 
-        description = ''
+        description = lib.mdDoc ''
           Force Nextcloud to always use HTTPS i.e. for link generation. Nextcloud
           uses the currently used protocol by default, but when behind a reverse-proxy,
-          it may use <literal>http</literal> for everything although Nextcloud
+          it may use `http` for everything although Nextcloud
           may be served via HTTPS.
         '';
       };
@@ -391,50 +391,50 @@ in {
           bucket = mkOption {
             type = types.str;
             example = "nextcloud";
-            description = ''
+            description = lib.mdDoc ''
               The name of the S3 bucket.
             '';
           };
           autocreate = mkOption {
             type = types.bool;
-            description = ''
+            description = lib.mdDoc ''
               Create the objectstore if it does not exist.
             '';
           };
           key = mkOption {
             type = types.str;
             example = "EJ39ITYZEUH5BGWDRUFY";
-            description = ''
+            description = lib.mdDoc ''
               The access key for the S3 bucket.
             '';
           };
           secretFile = mkOption {
             type = types.str;
             example = "/var/nextcloud-objectstore-s3-secret";
-            description = ''
+            description = lib.mdDoc ''
               The full path to a file that contains the access secret. Must be
-              readable by user <literal>nextcloud</literal>.
+              readable by user `nextcloud`.
             '';
           };
           hostname = mkOption {
             type = types.nullOr types.str;
             default = null;
             example = "example.com";
-            description = ''
+            description = lib.mdDoc ''
               Required for some non-Amazon implementations.
             '';
           };
           port = mkOption {
             type = types.nullOr types.port;
             default = null;
-            description = ''
+            description = lib.mdDoc ''
               Required for some non-Amazon implementations.
             '';
           };
           useSsl = mkOption {
             type = types.bool;
             default = true;
-            description = ''
+            description = lib.mdDoc ''
               Use SSL for objectstore access.
             '';
           };
@@ -442,20 +442,20 @@ in {
             type = types.nullOr types.str;
             default = null;
             example = "REGION";
-            description = ''
+            description = lib.mdDoc ''
               Required for some non-Amazon implementations.
             '';
           };
           usePathStyle = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Required for some non-Amazon S3 implementations.
 
               Ordinarily, requests will be made with
-              <literal>http://bucket.hostname.domain/</literal>, but with path style
+              `http://bucket.hostname.domain/`, but with path style
               enabled requests are made with
-              <literal>http://hostname.domain/bucket</literal> instead.
+              `http://hostname.domain/bucket` instead.
             '';
           };
         };
@@ -476,14 +476,14 @@ in {
       apcu = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Whether to load the APCu module into PHP.
         '';
       };
       redis = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to load the Redis module into PHP.
           You still need to enable Redis in your config.php.
           See https://docs.nextcloud.com/server/14/admin_manual/configuration_server/caching_configuration.html
@@ -492,7 +492,7 @@ in {
       memcached = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Whether to load the Memcached module into PHP.
           You still need to enable Memcached in your config.php.
           See https://docs.nextcloud.com/server/14/admin_manual/configuration_server/caching_configuration.html
@@ -503,7 +503,7 @@ in {
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Run regular auto update of all apps installed from the nextcloud app store.
         '';
       };
@@ -552,7 +552,7 @@ in {
     extraOptions = mkOption {
       type = jsonFormat.type;
       default = {};
-      description = ''
+      description = lib.mdDoc ''
         Extra options which should be appended to nextcloud's config.php file.
       '';
       example = literalExpression '' {
@@ -580,7 +580,7 @@ in {
       recommendedHttpHeaders = mkOption {
         type = types.bool;
         default = true;
-        description = "Enable additional recommended HTTP response headers";
+        description = lib.mdDoc "Enable additional recommended HTTP response headers";
       };
       hstsMaxAge = mkOption {
         type = types.ints.positive;
diff --git a/nixos/modules/services/web-apps/nexus.nix b/nixos/modules/services/web-apps/nexus.nix
index dc50a06705f..cfa137e77d2 100644
--- a/nixos/modules/services/web-apps/nexus.nix
+++ b/nixos/modules/services/web-apps/nexus.nix
@@ -17,37 +17,37 @@ in
         type = types.package;
         default = pkgs.nexus;
         defaultText = literalExpression "pkgs.nexus";
-        description = "Package which runs Nexus3";
+        description = lib.mdDoc "Package which runs Nexus3";
       };
 
       user = mkOption {
         type = types.str;
         default = "nexus";
-        description = "User which runs Nexus3.";
+        description = lib.mdDoc "User which runs Nexus3.";
       };
 
       group = mkOption {
         type = types.str;
         default = "nexus";
-        description = "Group which runs Nexus3.";
+        description = lib.mdDoc "Group which runs Nexus3.";
       };
 
       home = mkOption {
         type = types.str;
         default = "/var/lib/sonatype-work";
-        description = "Home directory of the Nexus3 instance.";
+        description = lib.mdDoc "Home directory of the Nexus3 instance.";
       };
 
       listenAddress = mkOption {
         type = types.str;
         default = "127.0.0.1";
-        description = "Address to listen on.";
+        description = lib.mdDoc "Address to listen on.";
       };
 
       listenPort = mkOption {
         type = types.int;
         default = 8081;
-        description = "Port to listen on.";
+        description = lib.mdDoc "Port to listen on.";
       };
 
       jvmOpts = mkOption {
diff --git a/nixos/modules/services/web-apps/nifi.nix b/nixos/modules/services/web-apps/nifi.nix
index 21a63127264..e3f30c710e0 100644
--- a/nixos/modules/services/web-apps/nifi.nix
+++ b/nixos/modules/services/web-apps/nifi.nix
@@ -33,25 +33,25 @@ in {
         type = lib.types.package;
         default = pkgs.nifi;
         defaultText = lib.literalExpression "pkgs.nifi";
-        description = "Apache NiFi package to use.";
+        description = lib.mdDoc "Apache NiFi package to use.";
       };
 
       user = lib.mkOption {
         type = lib.types.str;
         default = "nifi";
-        description = "User account where Apache NiFi runs.";
+        description = lib.mdDoc "User account where Apache NiFi runs.";
       };
 
       group = lib.mkOption {
         type = lib.types.str;
         default = "nifi";
-        description = "Group account where Apache NiFi runs.";
+        description = lib.mdDoc "Group account where Apache NiFi runs.";
       };
 
       enableHTTPS = lib.mkOption {
         type = lib.types.bool;
         default = true;
-        description = "Enable HTTPS protocol. Don`t use in production.";
+        description = lib.mdDoc "Enable HTTPS protocol. Don`t use in production.";
       };
 
       listenHost = lib.mkOption {
@@ -62,7 +62,7 @@ in {
           then "0.0.0.0"
           else "127.0.0.1"
         '';
-        description = "Bind to an ip for Apache NiFi web-ui.";
+        description = lib.mdDoc "Bind to an ip for Apache NiFi web-ui.";
       };
 
       listenPort = lib.mkOption {
@@ -73,7 +73,7 @@ in {
           then "8443"
           else "8000"
         '';
-        description = "Bind to a port for Apache NiFi web-ui.";
+        description = lib.mdDoc "Bind to a port for Apache NiFi web-ui.";
       };
 
       proxyHost = lib.mkOption {
@@ -84,7 +84,7 @@ in {
           then "0.0.0.0"
           else null
         '';
-        description = "Allow requests from a specific host.";
+        description = lib.mdDoc "Allow requests from a specific host.";
       };
 
       proxyPort = lib.mkOption {
@@ -95,34 +95,34 @@ in {
           then "8443"
           else null
         '';
-        description = "Allow requests from a specific port.";
+        description = lib.mdDoc "Allow requests from a specific port.";
       };
 
       initUser = lib.mkOption {
         type = lib.types.nullOr lib.types.str;
         default = null;
-        description = "Initial user account for Apache NiFi. Username must be at least 4 characters.";
+        description = lib.mdDoc "Initial user account for Apache NiFi. Username must be at least 4 characters.";
       };
 
       initPasswordFile = lib.mkOption {
         type = lib.types.nullOr lib.types.path;
         default = null;
         example = "/run/keys/nifi/password-nifi";
-        description = "nitial password for Apache NiFi. Password must be at least 12 characters.";
+        description = lib.mdDoc "nitial password for Apache NiFi. Password must be at least 12 characters.";
       };
 
       initJavaHeapSize = lib.mkOption {
         type = lib.types.nullOr lib.types.int;
         default = null;
         example = 1024;
-        description = "Set the initial heap size for the JVM in MB.";
+        description = lib.mdDoc "Set the initial heap size for the JVM in MB.";
       };
 
       maxJavaHeapSize = lib.mkOption {
         type = lib.types.nullOr lib.types.int;
         default = null;
         example = 2048;
-        description = "Set the initial heap size for the JVM in MB.";
+        description = lib.mdDoc "Set the initial heap size for the JVM in MB.";
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/node-red.nix b/nixos/modules/services/web-apps/node-red.nix
index 4512907f027..1b9d14ecf4f 100644
--- a/nixos/modules/services/web-apps/node-red.nix
+++ b/nixos/modules/services/web-apps/node-red.nix
@@ -23,13 +23,13 @@ in
       default = pkgs.nodePackages.node-red;
       defaultText = literalExpression "pkgs.nodePackages.node-red";
       type = types.package;
-      description = "Node-RED package to use.";
+      description = lib.mdDoc "Node-RED package to use.";
     };
 
     openFirewall = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Open ports in the firewall for the server.
       '';
     };
@@ -37,7 +37,7 @@ in
     withNpmAndGcc = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Give Node-RED access to NPM and GCC at runtime, so 'Nodes' can be
         downloaded and managed imperatively via the 'Palette Manager'.
       '';
@@ -58,13 +58,13 @@ in
     port = mkOption {
       type = types.port;
       default = 1880;
-      description = "Listening port.";
+      description = lib.mdDoc "Listening port.";
     };
 
     user = mkOption {
       type = types.str;
       default = defaultUser;
-      description = ''
+      description = lib.mdDoc ''
         User under which Node-RED runs.If left as the default value this user
         will automatically be created on system activation, otherwise the
         sysadmin is responsible for ensuring the user exists.
@@ -74,7 +74,7 @@ in
     group = mkOption {
       type = types.str;
       default = defaultUser;
-      description = ''
+      description = lib.mdDoc ''
         Group under which Node-RED runs.If left as the default value this group
         will automatically be created on system activation, otherwise the
         sysadmin is responsible for ensuring the group exists.
@@ -84,7 +84,7 @@ in
     userDir = mkOption {
       type = types.path;
       default = "/var/lib/node-red";
-      description = ''
+      description = lib.mdDoc ''
         The directory to store all user data, such as flow and credential files and all library data. If left
         as the default value this directory will automatically be created before the node-red service starts,
         otherwise the sysadmin is responsible for ensuring the directory exists with appropriate ownership
@@ -95,13 +95,13 @@ in
     safe = mkOption {
       type = types.bool;
       default = false;
-      description = "Whether to launch Node-RED in --safe mode.";
+      description = lib.mdDoc "Whether to launch Node-RED in --safe mode.";
     };
 
     define = mkOption {
       type = types.attrs;
       default = {};
-      description = "List of settings.js overrides to pass via -D to Node-RED.";
+      description = lib.mdDoc "List of settings.js overrides to pass via -D to Node-RED.";
       example = literalExpression ''
         {
           "logging.console.level" = "trace";
diff --git a/nixos/modules/services/web-apps/onlyoffice.nix b/nixos/modules/services/web-apps/onlyoffice.nix
index ce6a3e835e3..15fc3b03a83 100644
--- a/nixos/modules/services/web-apps/onlyoffice.nix
+++ b/nixos/modules/services/web-apps/onlyoffice.nix
@@ -14,13 +14,13 @@ in
     hostname = mkOption {
       type = types.str;
       default = "localhost";
-      description = "FQDN for the onlyoffice instance.";
+      description = lib.mdDoc "FQDN for the onlyoffice instance.";
     };
 
     jwtSecretFile = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Path to a file that contains the secret to sign web requests using JSON Web Tokens.
         If left at the default value null signing is disabled.
       '';
@@ -30,37 +30,37 @@ in
       type = types.package;
       default = pkgs.onlyoffice-documentserver;
       defaultText = "pkgs.onlyoffice-documentserver";
-      description = "Which package to use for the OnlyOffice instance.";
+      description = lib.mdDoc "Which package to use for the OnlyOffice instance.";
     };
 
     port = mkOption {
       type = types.port;
       default = 8000;
-      description = "Port the OnlyOffice DocumentServer should listens on.";
+      description = lib.mdDoc "Port the OnlyOffice DocumentServer should listens on.";
     };
 
     examplePort = mkOption {
       type = types.port;
       default = null;
-      description = "Port the OnlyOffice Example server should listens on.";
+      description = lib.mdDoc "Port the OnlyOffice Example server should listens on.";
     };
 
     postgresHost = mkOption {
       type = types.str;
       default = "/run/postgresql";
-      description = "The Postgresql hostname or socket path OnlyOffice should connect to.";
+      description = lib.mdDoc "The Postgresql hostname or socket path OnlyOffice should connect to.";
     };
 
     postgresName = mkOption {
       type = types.str;
       default = "onlyoffice";
-      description = "The name of databse OnlyOffice should user.";
+      description = lib.mdDoc "The name of databse OnlyOffice should user.";
     };
 
     postgresPasswordFile = mkOption {
       type = types.nullOr types.str;
       default = null;
-      description = ''
+      description = lib.mdDoc ''
         Path to a file that contains the password OnlyOffice should use to connect to Postgresql.
         Unused when using socket authentication.
       '';
@@ -69,7 +69,7 @@ in
     postgresUser = mkOption {
       type = types.str;
       default = "onlyoffice";
-      description = ''
+      description = lib.mdDoc ''
         The username OnlyOffice should use to connect to Postgresql.
         Unused when using socket authentication.
       '';
@@ -78,7 +78,7 @@ in
     rabbitmqUrl = mkOption {
       type = types.str;
       default = "amqp://guest:guest@localhost:5672";
-      description = "The Rabbitmq in amqp URI style OnlyOffice should connect to.";
+      description = lib.mdDoc "The Rabbitmq in amqp URI style OnlyOffice should connect to.";
     };
   };
 
diff --git a/nixos/modules/services/web-apps/openwebrx.nix b/nixos/modules/services/web-apps/openwebrx.nix
index 8a7972a3fc6..c409adbc710 100644
--- a/nixos/modules/services/web-apps/openwebrx.nix
+++ b/nixos/modules/services/web-apps/openwebrx.nix
@@ -10,7 +10,7 @@ in
       type = types.package;
       default = pkgs.openwebrx;
       defaultText = literalExpression "pkgs.openwebrx";
-      description = "OpenWebRX package to use for the service";
+      description = lib.mdDoc "OpenWebRX package to use for the service";
     };
   };
 
diff --git a/nixos/modules/services/web-apps/peertube.nix b/nixos/modules/services/web-apps/peertube.nix
index e6b6aa273e7..2fb05209c5c 100644
--- a/nixos/modules/services/web-apps/peertube.nix
+++ b/nixos/modules/services/web-apps/peertube.nix
@@ -73,51 +73,51 @@ in {
     user = lib.mkOption {
       type = lib.types.str;
       default = "peertube";
-      description = "User account under which Peertube runs.";
+      description = lib.mdDoc "User account under which Peertube runs.";
     };
 
     group = lib.mkOption {
       type = lib.types.str;
       default = "peertube";
-      description = "Group under which Peertube runs.";
+      description = lib.mdDoc "Group under which Peertube runs.";
     };
 
     localDomain = lib.mkOption {
       type = lib.types.str;
       example = "peertube.example.com";
-      description = "The domain serving your PeerTube instance.";
+      description = lib.mdDoc "The domain serving your PeerTube instance.";
     };
 
     listenHttp = lib.mkOption {
       type = lib.types.int;
       default = 9000;
-      description = "listen port for HTTP server.";
+      description = lib.mdDoc "listen port for HTTP server.";
     };
 
     listenWeb = lib.mkOption {
       type = lib.types.int;
       default = 9000;
-      description = "listen port for WEB server.";
+      description = lib.mdDoc "listen port for WEB server.";
     };
 
     enableWebHttps = lib.mkOption {
       type = lib.types.bool;
       default = false;
-      description = "Enable or disable HTTPS protocol.";
+      description = lib.mdDoc "Enable or disable HTTPS protocol.";
     };
 
     dataDirs = lib.mkOption {
       type = lib.types.listOf lib.types.path;
       default = [ ];
       example = [ "/opt/peertube/storage" "/var/cache/peertube" ];
-      description = "Allow access to custom data locations.";
+      description = lib.mdDoc "Allow access to custom data locations.";
     };
 
     serviceEnvironmentFile = lib.mkOption {
       type = lib.types.nullOr lib.types.path;
       default = null;
       example = "/run/keys/peertube/password-init-root";
-      description = ''
+      description = lib.mdDoc ''
         Set environment variables for the service. Mainly useful for setting the initial root password.
         For example write to file:
         PT_INITIAL_ROOT_PASSWORD=changeme
@@ -141,14 +141,14 @@ in {
           };
         }
       '';
-      description = "Configuration for peertube.";
+      description = lib.mdDoc "Configuration for peertube.";
     };
 
     database = {
       createLocally = lib.mkOption {
         type = lib.types.bool;
         default = false;
-        description = "Configure local PostgreSQL database server for PeerTube.";
+        description = lib.mdDoc "Configure local PostgreSQL database server for PeerTube.";
       };
 
       host = lib.mkOption {
@@ -160,32 +160,32 @@ in {
           else null
         '';
         example = "192.168.15.47";
-        description = "Database host address or unix socket.";
+        description = lib.mdDoc "Database host address or unix socket.";
       };
 
       port = lib.mkOption {
         type = lib.types.int;
         default = 5432;
-        description = "Database host port.";
+        description = lib.mdDoc "Database host port.";
       };
 
       name = lib.mkOption {
         type = lib.types.str;
         default = "peertube";
-        description = "Database name.";
+        description = lib.mdDoc "Database name.";
       };
 
       user = lib.mkOption {
         type = lib.types.str;
         default = "peertube";
-        description = "Database user.";
+        description = lib.mdDoc "Database user.";
       };
 
       passwordFile = lib.mkOption {
         type = lib.types.nullOr lib.types.path;
         default = null;
         example = "/run/keys/peertube/password-posgressql-db";
-        description = "Password for PostgreSQL database.";
+        description = lib.mdDoc "Password for PostgreSQL database.";
       };
     };
 
@@ -193,7 +193,7 @@ in {
       createLocally = lib.mkOption {
         type = lib.types.bool;
         default = false;
-        description = "Configure local Redis server for PeerTube.";
+        description = lib.mdDoc "Configure local Redis server for PeerTube.";
       };
 
       host = lib.mkOption {
@@ -204,7 +204,7 @@ in {
           then "127.0.0.1"
           else null
         '';
-        description = "Redis host.";
+        description = lib.mdDoc "Redis host.";
       };
 
       port = lib.mkOption {
@@ -215,21 +215,21 @@ in {
           then null
           else 6379
         '';
-        description = "Redis port.";
+        description = lib.mdDoc "Redis port.";
       };
 
       passwordFile = lib.mkOption {
         type = lib.types.nullOr lib.types.path;
         default = null;
         example = "/run/keys/peertube/password-redis-db";
-        description = "Password for redis database.";
+        description = lib.mdDoc "Password for redis database.";
       };
 
       enableUnixSocket = lib.mkOption {
         type = lib.types.bool;
         default = cfg.redis.createLocally;
         defaultText = lib.literalExpression "config.${opt.redis.createLocally}";
-        description = "Use Unix socket.";
+        description = lib.mdDoc "Use Unix socket.";
       };
     };
 
@@ -237,14 +237,14 @@ in {
       createLocally = lib.mkOption {
         type = lib.types.bool;
         default = false;
-        description = "Configure local Postfix SMTP server for PeerTube.";
+        description = lib.mdDoc "Configure local Postfix SMTP server for PeerTube.";
       };
 
       passwordFile = lib.mkOption {
         type = lib.types.nullOr lib.types.path;
         default = null;
         example = "/run/keys/peertube/password-smtp";
-        description = "Password for smtp server.";
+        description = lib.mdDoc "Password for smtp server.";
       };
     };
 
@@ -252,7 +252,7 @@ in {
       type = lib.types.package;
       default = pkgs.peertube;
       defaultText = lib.literalExpression "pkgs.peertube";
-      description = "Peertube package to use.";
+      description = lib.mdDoc "Peertube package to use.";
     };
   };
 
diff --git a/nixos/modules/services/web-apps/phylactery.nix b/nixos/modules/services/web-apps/phylactery.nix
index f0e97da1f20..d512b48539b 100644
--- a/nixos/modules/services/web-apps/phylactery.nix
+++ b/nixos/modules/services/web-apps/phylactery.nix
@@ -9,24 +9,24 @@ in {
     host = mkOption {
       type = types.str;
       default = "localhost";
-      description = "Listen host for Phylactery";
+      description = lib.mdDoc "Listen host for Phylactery";
     };
 
     port = mkOption {
       type = types.port;
-      description = "Listen port for Phylactery";
+      description = lib.mdDoc "Listen port for Phylactery";
     };
 
     library = mkOption {
       type = types.path;
-      description = "Path to CBZ library";
+      description = lib.mdDoc "Path to CBZ library";
     };
 
     package = mkOption {
       type = types.package;
       default = pkgs.phylactery;
       defaultText = literalExpression "pkgs.phylactery";
-      description = "The Phylactery package to use";
+      description = lib.mdDoc "The Phylactery package to use";
     };
   };
 
diff --git a/nixos/modules/services/web-apps/pict-rs.nix b/nixos/modules/services/web-apps/pict-rs.nix
index e1847fbd531..ab5a9ed0735 100644
--- a/nixos/modules/services/web-apps/pict-rs.nix
+++ b/nixos/modules/services/web-apps/pict-rs.nix
@@ -14,21 +14,21 @@ in
     dataDir = mkOption {
       type = types.path;
       default = "/var/lib/pict-rs";
-      description = ''
+      description = lib.mdDoc ''
         The directory where to store the uploaded images.
       '';
     };
     address = mkOption {
       type = types.str;
       default = "127.0.0.1";
-      description = ''
+      description = lib.mdDoc ''
         The IPv4 address to deploy the service to.
       '';
     };
     port = mkOption {
       type = types.port;
       default = 8080;
-      description = ''
+      description = lib.mdDoc ''
         The port which to bind the service to.
       '';
     };
diff --git a/nixos/modules/services/web-apps/plantuml-server.nix b/nixos/modules/services/web-apps/plantuml-server.nix
index 9ea37b8a4ca..acd9292ceb4 100644
--- a/nixos/modules/services/web-apps/plantuml-server.nix
+++ b/nixos/modules/services/web-apps/plantuml-server.nix
@@ -17,7 +17,7 @@ in
         type = types.package;
         default = pkgs.plantuml-server;
         defaultText = literalExpression "pkgs.plantuml-server";
-        description = "PlantUML server package to use";
+        description = lib.mdDoc "PlantUML server package to use";
       };
 
       packages = {
@@ -25,75 +25,75 @@ in
           type = types.package;
           default = pkgs.jdk;
           defaultText = literalExpression "pkgs.jdk";
-          description = "JDK package to use for the server";
+          description = lib.mdDoc "JDK package to use for the server";
         };
         jetty = mkOption {
           type = types.package;
           default = pkgs.jetty;
           defaultText = literalExpression "pkgs.jetty";
-          description = "Jetty package to use for the server";
+          description = lib.mdDoc "Jetty package to use for the server";
         };
       };
 
       user = mkOption {
         type = types.str;
         default = "plantuml";
-        description = "User which runs PlantUML server.";
+        description = lib.mdDoc "User which runs PlantUML server.";
       };
 
       group = mkOption {
         type = types.str;
         default = "plantuml";
-        description = "Group which runs PlantUML server.";
+        description = lib.mdDoc "Group which runs PlantUML server.";
       };
 
       home = mkOption {
         type = types.str;
         default = "/var/lib/plantuml";
-        description = "Home directory of the PlantUML server instance.";
+        description = lib.mdDoc "Home directory of the PlantUML server instance.";
       };
 
       listenHost = mkOption {
         type = types.str;
         default = "127.0.0.1";
-        description = "Host to listen on.";
+        description = lib.mdDoc "Host to listen on.";
       };
 
       listenPort = mkOption {
         type = types.int;
         default = 8080;
-        description = "Port to listen on.";
+        description = lib.mdDoc "Port to listen on.";
       };
 
       plantumlLimitSize = mkOption {
         type = types.int;
         default = 4096;
-        description = "Limits image width and height.";
+        description = lib.mdDoc "Limits image width and height.";
       };
 
       graphvizPackage = mkOption {
         type = types.package;
         default = pkgs.graphviz;
         defaultText = literalExpression "pkgs.graphviz";
-        description = "Package containing the dot executable.";
+        description = lib.mdDoc "Package containing the dot executable.";
       };
 
       plantumlStats = mkOption {
         type = types.bool;
         default = false;
-        description = "Set it to on to enable statistics report (https://plantuml.com/statistics-report).";
+        description = lib.mdDoc "Set it to on to enable statistics report (https://plantuml.com/statistics-report).";
       };
 
       httpAuthorization = mkOption {
         type = types.nullOr types.str;
         default = null;
-        description = "When calling the proxy endpoint, the value of HTTP_AUTHORIZATION will be used to set the HTTP Authorization header.";
+        description = lib.mdDoc "When calling the proxy endpoint, the value of HTTP_AUTHORIZATION will be used to set the HTTP Authorization header.";
       };
 
       allowPlantumlInclude = mkOption {
         type = types.bool;
         default = false;
-        description = "Enables !include processing which can read files from the server into diagrams. Files are read relative to the current working directory.";
+        description = lib.mdDoc "Enables !include processing which can read files from the server into diagrams. Files are read relative to the current working directory.";
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/plausible.nix b/nixos/modules/services/web-apps/plausible.nix
index 5d550ae5ca8..6f098134c92 100644
--- a/nixos/modules/services/web-apps/plausible.nix
+++ b/nixos/modules/services/web-apps/plausible.nix
@@ -11,7 +11,7 @@ in {
 
     releaseCookiePath = mkOption {
       type = with types; either str path;
-      description = ''
+      description = lib.mdDoc ''
         The path to the file with release cookie. (used for remote connection to the running node).
       '';
     };
@@ -20,7 +20,7 @@ in {
       name = mkOption {
         default = "admin";
         type = types.str;
-        description = ''
+        description = lib.mdDoc ''
           Name of the admin user that plausible will created on initial startup.
         '';
       };
@@ -28,14 +28,14 @@ in {
       email = mkOption {
         type = types.str;
         example = "admin@localhost";
-        description = ''
+        description = lib.mdDoc ''
           Email-address of the admin-user.
         '';
       };
 
       passwordFile = mkOption {
         type = types.either types.str types.path;
-        description = ''
+        description = lib.mdDoc ''
           Path to the file which contains the password of the admin user.
         '';
       };
@@ -59,7 +59,7 @@ in {
         dbname = mkOption {
           default = "plausible";
           type = types.str;
-          description = ''
+          description = lib.mdDoc ''
             Name of the database to use.
           '';
         };
@@ -77,35 +77,35 @@ in {
       disableRegistration = mkOption {
         default = true;
         type = types.bool;
-        description = ''
+        description = lib.mdDoc ''
           Whether to prohibit creating an account in plausible's UI.
         '';
       };
       secretKeybaseFile = mkOption {
         type = types.either types.path types.str;
-        description = ''
-          Path to the secret used by the <literal>phoenix</literal>-framework. Instructions
+        description = lib.mdDoc ''
+          Path to the secret used by the `phoenix`-framework. Instructions
           how to generate one are documented in the
-          <link xlink:href="https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Secret.html#content">
-          framework docs</link>.
+          [
+          framework docs](https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Secret.html#content).
         '';
       };
       port = mkOption {
         default = 8000;
         type = types.port;
-        description = ''
+        description = lib.mdDoc ''
           Port where the service should be available.
         '';
       };
       baseUrl = mkOption {
         type = types.str;
-        description = ''
+        description = lib.mdDoc ''
           Public URL where plausible is available.
 
-          Note that <literal>/path</literal> components are currently ignored:
-          <link xlink:href="https://github.com/plausible/analytics/issues/1182">
+          Note that `/path` components are currently ignored:
+          [
             https://github.com/plausible/analytics/issues/1182
-          </link>.
+          ](https://github.com/plausible/analytics/issues/1182).
         '';
       };
     };
@@ -114,8 +114,8 @@ in {
       email = mkOption {
         default = "hello@plausible.local";
         type = types.str;
-        description = ''
-          The email id to use for as <emphasis>from</emphasis> address of all communications
+        description = lib.mdDoc ''
+          The email id to use for as *from* address of all communications
           from Plausible.
         '';
       };
@@ -123,28 +123,28 @@ in {
         hostAddr = mkOption {
           default = "localhost";
           type = types.str;
-          description = ''
+          description = lib.mdDoc ''
             The host address of your smtp server.
           '';
         };
         hostPort = mkOption {
           default = 25;
           type = types.port;
-          description = ''
+          description = lib.mdDoc ''
             The port of your smtp server.
           '';
         };
         user = mkOption {
           default = null;
           type = types.nullOr types.str;
-          description = ''
+          description = lib.mdDoc ''
             The username/email in case SMTP auth is enabled.
           '';
         };
         passwordFile = mkOption {
           default = null;
           type = with types; nullOr (either str path);
-          description = ''
+          description = lib.mdDoc ''
             The path to the file with the password in case SMTP auth is enabled.
           '';
         };
@@ -152,7 +152,7 @@ in {
         retries = mkOption {
           type = types.ints.unsigned;
           default = 2;
-          description = ''
+          description = lib.mdDoc ''
             Number of retries to make until mailer gives up.
           '';
         };
diff --git a/nixos/modules/services/web-apps/powerdns-admin.nix b/nixos/modules/services/web-apps/powerdns-admin.nix
index 4661ba80c5d..c2d65f59e4d 100644
--- a/nixos/modules/services/web-apps/powerdns-admin.nix
+++ b/nixos/modules/services/web-apps/powerdns-admin.nix
@@ -27,7 +27,7 @@ in
       example = literalExpression ''
         [ "-b" "127.0.0.1:8000" ]
       '';
-      description = ''
+      description = lib.mdDoc ''
         Extra arguments passed to powerdns-admin.
       '';
     };
@@ -40,9 +40,9 @@ in
         PORT = 8000
         SQLALCHEMY_DATABASE_URI = 'postgresql://powerdnsadmin@/powerdnsadmin?host=/run/postgresql'
       '';
-      description = ''
+      description = lib.mdDoc ''
         Configuration python file.
-        See <link xlink:href="https://github.com/ngoduykhanh/PowerDNS-Admin/blob/v${pkgs.powerdns-admin.version}/configs/development.py">the example configuration</link>
+        See [the example configuration](https://github.com/ngoduykhanh/PowerDNS-Admin/blob/v${pkgs.powerdns-admin.version}/configs/development.py)
         for options.
       '';
     };
@@ -50,7 +50,7 @@ in
     secretKeyFile = mkOption {
       type = types.nullOr types.path;
       example = "/etc/powerdns-admin/secret";
-      description = ''
+      description = lib.mdDoc ''
         The secret used to create cookies.
         This needs to be set, otherwise the default is used and everyone can forge valid login cookies.
         Set this to null to ignore this setting and configure it through another way.
@@ -60,7 +60,7 @@ in
     saltFile = mkOption {
       type = types.nullOr types.path;
       example = "/etc/powerdns-admin/salt";
-      description = ''
+      description = lib.mdDoc ''
         The salt used for serialization.
         This should be set, otherwise the default is used.
         Set this to null to ignore this setting and configure it through another way.
diff --git a/nixos/modules/services/web-apps/prosody-filer.nix b/nixos/modules/services/web-apps/prosody-filer.nix
index a901a95fd5f..1d40809c420 100644
--- a/nixos/modules/services/web-apps/prosody-filer.nix
+++ b/nixos/modules/services/web-apps/prosody-filer.nix
@@ -14,9 +14,9 @@ in {
       enable = mkEnableOption "Prosody Filer XMPP upload file server";
 
       settings = mkOption {
-        description = ''
+        description = lib.mdDoc ''
           Configuration for Prosody Filer.
-          Refer to <link xlink:href="https://github.com/ThomasLeister/prosody-filer#configure-prosody-filer"/> for details on supported values.
+          Refer to <https://github.com/ThomasLeister/prosody-filer#configure-prosody-filer> for details on supported values.
         '';
 
         type = settingsFormat.type;
diff --git a/nixos/modules/services/web-apps/restya-board.nix b/nixos/modules/services/web-apps/restya-board.nix
index 1a8199ab3b3..ae80a7866a1 100644
--- a/nixos/modules/services/web-apps/restya-board.nix
+++ b/nixos/modules/services/web-apps/restya-board.nix
@@ -30,7 +30,7 @@ in
       dataDir = mkOption {
         type = types.path;
         default = "/var/lib/restya-board";
-        description = ''
+        description = lib.mdDoc ''
           Data of the application.
         '';
       };
@@ -38,7 +38,7 @@ in
       user = mkOption {
         type = types.str;
         default = "restya-board";
-        description = ''
+        description = lib.mdDoc ''
           User account under which the web-application runs.
         '';
       };
@@ -46,7 +46,7 @@ in
       group = mkOption {
         type = types.str;
         default = "nginx";
-        description = ''
+        description = lib.mdDoc ''
           Group account under which the web-application runs.
         '';
       };
@@ -55,7 +55,7 @@ in
         serverName = mkOption {
           type = types.str;
           default = "restya.board";
-          description = ''
+          description = lib.mdDoc ''
             Name of the nginx virtualhost to use.
           '';
         };
@@ -63,7 +63,7 @@ in
         listenHost = mkOption {
           type = types.str;
           default = "localhost";
-          description = ''
+          description = lib.mdDoc ''
             Listen address for the virtualhost to use.
           '';
         };
@@ -71,7 +71,7 @@ in
         listenPort = mkOption {
           type = types.int;
           default = 3000;
-          description = ''
+          description = lib.mdDoc ''
             Listen port for the virtualhost to use.
           '';
         };
@@ -81,7 +81,7 @@ in
         host = mkOption {
           type = types.nullOr types.str;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             Host of the database. Leave 'null' to use a local PostgreSQL database.
             A local PostgreSQL database is initialized automatically.
           '';
@@ -90,7 +90,7 @@ in
         port = mkOption {
           type = types.nullOr types.int;
           default = 5432;
-          description = ''
+          description = lib.mdDoc ''
             The database's port.
           '';
         };
@@ -98,7 +98,7 @@ in
         name = mkOption {
           type = types.str;
           default = "restya_board";
-          description = ''
+          description = lib.mdDoc ''
             Name of the database. The database must exist.
           '';
         };
@@ -106,7 +106,7 @@ in
         user = mkOption {
           type = types.str;
           default = "restya_board";
-          description = ''
+          description = lib.mdDoc ''
             The database user. The user must exist and have access to
             the specified database.
           '';
@@ -115,7 +115,7 @@ in
         passwordFile = mkOption {
           type = types.nullOr types.path;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             The database user's password. 'null' if no password is set.
           '';
         };
@@ -126,7 +126,7 @@ in
           type = types.nullOr types.str;
           default = null;
           example = "localhost";
-          description = ''
+          description = lib.mdDoc ''
             Hostname to send outgoing mail. Null to use the system MTA.
           '';
         };
@@ -134,7 +134,7 @@ in
         port = mkOption {
           type = types.int;
           default = 25;
-          description = ''
+          description = lib.mdDoc ''
             Port used to connect to SMTP server.
           '';
         };
@@ -142,7 +142,7 @@ in
         login = mkOption {
           type = types.str;
           default = "";
-          description = ''
+          description = lib.mdDoc ''
             SMTP authentication login used when sending outgoing mail.
           '';
         };
@@ -150,7 +150,7 @@ in
         password = mkOption {
           type = types.str;
           default = "";
-          description = ''
+          description = lib.mdDoc ''
             SMTP authentication password used when sending outgoing mail.
 
             ATTENTION: The password is stored world-readable in the nix-store!
@@ -161,7 +161,7 @@ in
       timezone = mkOption {
         type = types.lines;
         default = "GMT";
-        description = ''
+        description = lib.mdDoc ''
           Timezone the web-app runs in.
         '';
       };
diff --git a/nixos/modules/services/web-apps/rss-bridge.nix b/nixos/modules/services/web-apps/rss-bridge.nix
index f2b6d955982..b1a3907d196 100644
--- a/nixos/modules/services/web-apps/rss-bridge.nix
+++ b/nixos/modules/services/web-apps/rss-bridge.nix
@@ -16,7 +16,7 @@ in
       user = mkOption {
         type = types.str;
         default = "nginx";
-        description = ''
+        description = lib.mdDoc ''
           User account under which both the service and the web-application run.
         '';
       };
@@ -24,7 +24,7 @@ in
       group = mkOption {
         type = types.str;
         default = "nginx";
-        description = ''
+        description = lib.mdDoc ''
           Group under which the web-application run.
         '';
       };
@@ -32,7 +32,7 @@ in
       pool = mkOption {
         type = types.str;
         default = poolName;
-        description = ''
+        description = lib.mdDoc ''
           Name of existing phpfpm pool that is used to run web-application.
           If not specified a pool will be created automatically with
           default values.
@@ -42,16 +42,16 @@ in
       dataDir = mkOption {
         type = types.str;
         default = "/var/lib/rss-bridge";
-        description = ''
+        description = lib.mdDoc ''
           Location in which cache directory will be created.
-          You can put <literal>config.ini.php</literal> in here.
+          You can put `config.ini.php` in here.
         '';
       };
 
       virtualHost = mkOption {
         type = types.nullOr types.str;
         default = "rss-bridge";
-        description = ''
+        description = lib.mdDoc ''
           Name of the nginx virtualhost to use and setup. If null, do not setup any virtualhost.
         '';
       };
diff --git a/nixos/modules/services/web-apps/selfoss.nix b/nixos/modules/services/web-apps/selfoss.nix
index 899976ac696..016e053c802 100644
--- a/nixos/modules/services/web-apps/selfoss.nix
+++ b/nixos/modules/services/web-apps/selfoss.nix
@@ -35,7 +35,7 @@ in
         user = mkOption {
           type = types.str;
           default = "nginx";
-          description = ''
+          description = lib.mdDoc ''
             User account under which both the service and the web-application run.
           '';
         };
@@ -43,7 +43,7 @@ in
         pool = mkOption {
           type = types.str;
           default = "${poolName}";
-          description = ''
+          description = lib.mdDoc ''
             Name of existing phpfpm pool that is used to run web-application.
             If not specified a pool will be created automatically with
             default values.
@@ -54,7 +54,7 @@ in
         type = mkOption {
           type = types.enum ["pgsql" "mysql" "sqlite"];
           default = "sqlite";
-          description = ''
+          description = lib.mdDoc ''
             Database to store feeds. Supported are sqlite, pgsql and mysql.
           '';
         };
@@ -62,7 +62,7 @@ in
         host = mkOption {
           type = types.str;
           default = "localhost";
-          description = ''
+          description = lib.mdDoc ''
             Host of the database (has no effect if type is "sqlite").
           '';
         };
@@ -70,7 +70,7 @@ in
         name = mkOption {
           type = types.str;
           default = "tt_rss";
-          description = ''
+          description = lib.mdDoc ''
             Name of the existing database (has no effect if type is "sqlite").
           '';
         };
@@ -78,7 +78,7 @@ in
         user = mkOption {
           type = types.str;
           default = "tt_rss";
-          description = ''
+          description = lib.mdDoc ''
             The database user. The user must exist and has access to
             the specified database (has no effect if type is "sqlite").
           '';
@@ -87,7 +87,7 @@ in
         password = mkOption {
           type = types.nullOr types.str;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             The database user's password (has no effect if type is "sqlite").
           '';
         };
@@ -95,7 +95,7 @@ in
         port = mkOption {
           type = types.nullOr types.int;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             The database's port. If not set, the default ports will be
             provided (5432 and 3306 for pgsql and mysql respectively)
             (has no effect if type is "sqlite").
@@ -105,7 +105,7 @@ in
       extraConfig = mkOption {
         type = types.lines;
         default = "";
-        description = ''
+        description = lib.mdDoc ''
           Extra configuration added to config.ini
         '';
       };
diff --git a/nixos/modules/services/web-apps/shiori.nix b/nixos/modules/services/web-apps/shiori.nix
index bb2fc684e83..494f8587306 100644
--- a/nixos/modules/services/web-apps/shiori.nix
+++ b/nixos/modules/services/web-apps/shiori.nix
@@ -12,13 +12,13 @@ in {
         type = types.package;
         default = pkgs.shiori;
         defaultText = literalExpression "pkgs.shiori";
-        description = "The Shiori package to use.";
+        description = lib.mdDoc "The Shiori package to use.";
       };
 
       address = mkOption {
         type = types.str;
         default = "";
-        description = ''
+        description = lib.mdDoc ''
           The IP address on which Shiori will listen.
           If empty, listens on all interfaces.
         '';
@@ -27,7 +27,7 @@ in {
       port = mkOption {
         type = types.port;
         default = 8080;
-        description = "The port of the Shiori web application";
+        description = lib.mdDoc "The port of the Shiori web application";
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/sogo.nix b/nixos/modules/services/web-apps/sogo.nix
index 4610bb96cb5..a134282de83 100644
--- a/nixos/modules/services/web-apps/sogo.nix
+++ b/nixos/modules/services/web-apps/sogo.nix
@@ -21,31 +21,31 @@ in {
     enable = mkEnableOption "SOGo groupware";
 
     vhostName = mkOption {
-      description = "Name of the nginx vhost";
+      description = lib.mdDoc "Name of the nginx vhost";
       type = str;
       default = "sogo";
     };
 
     timezone = mkOption {
-      description = "Timezone of your SOGo instance";
+      description = lib.mdDoc "Timezone of your SOGo instance";
       type = str;
       example = "America/Montreal";
     };
 
     language = mkOption {
-      description = "Language of SOGo";
+      description = lib.mdDoc "Language of SOGo";
       type = str;
       default = "English";
     };
 
     ealarmsCredFile = mkOption {
-      description = "Optional path to a credentials file for email alarms";
+      description = lib.mdDoc "Optional path to a credentials file for email alarms";
       type = nullOr str;
       default = null;
     };
 
     configReplaces = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         Replacement-filepath mapping for sogo.conf.
         Every key is replaced with the contents of the file specified as value.
 
@@ -60,7 +60,7 @@ in {
     };
 
     extraConfig = mkOption {
-      description = "Extra sogo.conf configuration lines";
+      description = lib.mdDoc "Extra sogo.conf configuration lines";
       type = lines;
       default = "";
     };
diff --git a/nixos/modules/services/web-apps/trilium.nix b/nixos/modules/services/web-apps/trilium.nix
index 35383c992fe..193c7944a64 100644
--- a/nixos/modules/services/web-apps/trilium.nix
+++ b/nixos/modules/services/web-apps/trilium.nix
@@ -28,7 +28,7 @@ in
     dataDir = mkOption {
       type = types.str;
       default = "/var/lib/trilium";
-      description = ''
+      description = lib.mdDoc ''
         The directory storing the notes database and the configuration.
       '';
     };
@@ -36,7 +36,7 @@ in
     instanceName = mkOption {
       type = types.str;
       default = "Trilium";
-      description = ''
+      description = lib.mdDoc ''
         Instance name used to distinguish between different instances
       '';
     };
@@ -44,7 +44,7 @@ in
     noBackup = mkOption {
       type = types.bool;
       default = false;
-      description = ''
+      description = lib.mdDoc ''
         Disable periodic database backups.
       '';
     };
@@ -52,7 +52,7 @@ in
     host = mkOption {
       type = types.str;
       default = "127.0.0.1";
-      description = ''
+      description = lib.mdDoc ''
         The host address to bind to (defaults to localhost).
       '';
     };
@@ -60,14 +60,14 @@ in
     port = mkOption {
       type = types.int;
       default = 8080;
-      description = ''
+      description = lib.mdDoc ''
         The port number to bind to.
       '';
     };
 
     nginx = mkOption {
       default = {};
-      description = ''
+      description = lib.mdDoc ''
         Configuration for nginx reverse proxy.
       '';
 
@@ -76,14 +76,14 @@ in
           enable = mkOption {
             type = types.bool;
             default = false;
-            description = ''
+            description = lib.mdDoc ''
               Configure the nginx reverse proxy settings.
             '';
           };
 
           hostName = mkOption {
             type = types.str;
-            description = ''
+            description = lib.mdDoc ''
               The hostname use to setup the virtualhost configuration
             '';
           };
diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix
index c441a2a7764..f105b0aa3f7 100644
--- a/nixos/modules/services/web-apps/tt-rss.nix
+++ b/nixos/modules/services/web-apps/tt-rss.nix
@@ -126,7 +126,7 @@ let
       root = mkOption {
         type = types.path;
         default = "/var/lib/tt-rss";
-        description = ''
+        description = lib.mdDoc ''
           Root of the application.
         '';
       };
@@ -134,7 +134,7 @@ let
       user = mkOption {
         type = types.str;
         default = "tt_rss";
-        description = ''
+        description = lib.mdDoc ''
           User account under which both the update daemon and the web-application run.
         '';
       };
@@ -142,7 +142,7 @@ let
       pool = mkOption {
         type = types.str;
         default = "${poolName}";
-        description = ''
+        description = lib.mdDoc ''
           Name of existing phpfpm pool that is used to run web-application.
           If not specified a pool will be created automatically with
           default values.
@@ -152,7 +152,7 @@ let
       virtualHost = mkOption {
         type = types.nullOr types.str;
         default = "tt-rss";
-        description = ''
+        description = lib.mdDoc ''
           Name of the nginx virtualhost to use and setup. If null, do not setup any virtualhost.
         '';
       };
@@ -161,7 +161,7 @@ let
         type = mkOption {
           type = types.enum ["pgsql" "mysql"];
           default = "pgsql";
-          description = ''
+          description = lib.mdDoc ''
             Database to store feeds. Supported are pgsql and mysql.
           '';
         };
@@ -169,7 +169,7 @@ let
         host = mkOption {
           type = types.nullOr types.str;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             Host of the database. Leave null to use Unix domain socket.
           '';
         };
@@ -177,7 +177,7 @@ let
         name = mkOption {
           type = types.str;
           default = "tt_rss";
-          description = ''
+          description = lib.mdDoc ''
             Name of the existing database.
           '';
         };
@@ -185,7 +185,7 @@ let
         user = mkOption {
           type = types.str;
           default = "tt_rss";
-          description = ''
+          description = lib.mdDoc ''
             The database user. The user must exist and has access to
             the specified database.
           '';
@@ -194,7 +194,7 @@ let
         password = mkOption {
           type = types.nullOr types.str;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             The database user's password.
           '';
         };
@@ -202,7 +202,7 @@ let
         passwordFile = mkOption {
           type = types.nullOr types.str;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             The database user's password.
           '';
         };
@@ -210,7 +210,7 @@ let
         port = mkOption {
           type = types.nullOr types.int;
           default = null;
-          description = ''
+          description = lib.mdDoc ''
             The database's port. If not set, the default ports will be provided (5432
             and 3306 for pgsql and mysql respectively).
           '';
@@ -219,7 +219,7 @@ let
         createLocally = mkOption {
           type = types.bool;
           default = true;
-          description = "Create the database and database user locally.";
+          description = lib.mdDoc "Create the database and database user locally.";
         };
       };
 
@@ -227,7 +227,7 @@ let
         autoCreate = mkOption {
           type = types.bool;
           default = true;
-          description = ''
+          description = lib.mdDoc ''
             Allow authentication modules to auto-create users in tt-rss internal
             database when authenticated successfully.
           '';
@@ -236,7 +236,7 @@ let
         autoLogin = mkOption {
           type = types.bool;
           default = true;
-          description = ''
+          description = lib.mdDoc ''
             Automatically login user on remote or other kind of externally supplied
             authentication, otherwise redirect to login form as normal.
             If set to true, users won't be able to set application language
@@ -249,7 +249,7 @@ let
         hub = mkOption {
           type = types.str;
           default = "";
-          description = ''
+          description = lib.mdDoc ''
             URL to a PubSubHubbub-compatible hub server. If defined, "Published
             articles" generated feed would automatically become PUSH-enabled.
           '';
@@ -258,7 +258,7 @@ let
         enable = mkOption {
           type = types.bool;
           default = false;
-          description = ''
+          description = lib.mdDoc ''
             Enable client PubSubHubbub support in tt-rss. When disabled, tt-rss
             won't try to subscribe to PUSH feed updates.
           '';
@@ -269,7 +269,7 @@ let
         server = mkOption {
           type = types.str;
           default = "localhost:9312";
-          description = ''
+          description = lib.mdDoc ''
             Hostname:port combination for the Sphinx server.
           '';
         };
@@ -277,7 +277,7 @@ let
         index = mkOption {
           type = types.listOf types.str;
           default = ["ttrss" "delta"];
-          description = ''
+          description = lib.mdDoc ''
             Index names in Sphinx configuration. Example configuration
             files are available on tt-rss wiki.
           '';
@@ -288,7 +288,7 @@ let
         enable = mkOption {
           type = types.bool;
           default = false;
-          description = ''
+          description = lib.mdDoc ''
             Allow users to register themselves. Please be aware that allowing
             random people to access your tt-rss installation is a security risk
             and potentially might lead to data loss or server exploit. Disabled
@@ -299,7 +299,7 @@ let
         notifyAddress = mkOption {
           type = types.str;
           default = "";
-          description = ''
+          description = lib.mdDoc ''
             Email address to send new user notifications to.
           '';
         };
@@ -307,7 +307,7 @@ let
         maxUsers = mkOption {
           type = types.int;
           default = 0;
-          description = ''
+          description = lib.mdDoc ''
             Maximum amount of users which will be allowed to register on this
             system. 0 - no limit.
           '';
@@ -319,7 +319,7 @@ let
           type = types.str;
           default = "";
           example = "localhost:25";
-          description = ''
+          description = lib.mdDoc ''
             Hostname:port combination to send outgoing mail. Blank - use system
             MTA.
           '';
@@ -328,7 +328,7 @@ let
         login = mkOption {
           type = types.str;
           default = "";
-          description = ''
+          description = lib.mdDoc ''
             SMTP authentication login used when sending outgoing mail.
           '';
         };
@@ -336,7 +336,7 @@ let
         password = mkOption {
           type = types.str;
           default = "";
-          description = ''
+          description = lib.mdDoc ''
             SMTP authentication password used when sending outgoing mail.
           '';
         };
@@ -344,7 +344,7 @@ let
         security = mkOption {
           type = types.enum ["" "ssl" "tls"];
           default = "";
-          description = ''
+          description = lib.mdDoc ''
             Used to select a secure SMTP connection. Allowed values: ssl, tls,
             or empty.
           '';
@@ -353,7 +353,7 @@ let
         fromName = mkOption {
           type = types.str;
           default = "Tiny Tiny RSS";
-          description = ''
+          description = lib.mdDoc ''
             Name for sending outgoing mail. This applies to password reset
             notifications, digest emails and any other mail.
           '';
@@ -362,7 +362,7 @@ let
         fromAddress = mkOption {
           type = types.str;
           default = "";
-          description = ''
+          description = lib.mdDoc ''
             Address for sending outgoing mail. This applies to password reset
             notifications, digest emails and any other mail.
           '';
@@ -371,7 +371,7 @@ let
         digestSubject = mkOption {
           type = types.str;
           default = "[tt-rss] New headlines for last 24 hours";
-          description = ''
+          description = lib.mdDoc ''
             Subject line for email digests.
           '';
         };
@@ -380,7 +380,7 @@ let
       sessionCookieLifetime = mkOption {
         type = types.int;
         default = 86400;
-        description = ''
+        description = lib.mdDoc ''
           Default lifetime of a session (e.g. login) cookie. In seconds,
           0 means cookie will be deleted when browser closes.
         '';
@@ -388,7 +388,7 @@ let
 
       selfUrlPath = mkOption {
         type = types.str;
-        description = ''
+        description = lib.mdDoc ''
           Full URL of your tt-rss installation. This should be set to the
           location of tt-rss directory, e.g. http://example.org/tt-rss/
           You need to set this option correctly otherwise several features
@@ -400,7 +400,7 @@ let
       feedCryptKey = mkOption {
         type = types.str;
         default = "";
-        description = ''
+        description = lib.mdDoc ''
           Key used for encryption of passwords for password-protected feeds
           in the database. A string of 24 random characters. If left blank, encryption
           is not used. Requires mcrypt functions.
@@ -413,7 +413,7 @@ let
         type = types.bool;
         default = false;
 
-        description = ''
+        description = lib.mdDoc ''
           Operate in single user mode, disables all functionality related to
           multiple users and authentication. Enabling this assumes you have
           your tt-rss directory protected by other means (e.g. http auth).
@@ -423,7 +423,7 @@ let
       simpleUpdateMode = mkOption {
         type = types.bool;
         default = false;
-        description = ''
+        description = lib.mdDoc ''
           Enables fallback update mode where tt-rss tries to update feeds in
           background while tt-rss is open in your browser.
           If you don't have a lot of feeds and don't want to or can't run
@@ -437,7 +437,7 @@ let
       forceArticlePurge = mkOption {
         type = types.int;
         default = 0;
-        description = ''
+        description = lib.mdDoc ''
           When this option is not 0, users ability to control feed purging
           intervals is disabled and all articles (which are not starred)
           older than this amount of days are purged.
@@ -447,7 +447,7 @@ let
       enableGZipOutput = mkOption {
         type = types.bool;
         default = true;
-        description = ''
+        description = lib.mdDoc ''
           Selectively gzip output to improve wire performance. This requires
           PHP Zlib extension on the server.
           Enabling this can break tt-rss in several httpd/php configurations,
@@ -459,7 +459,7 @@ let
       plugins = mkOption {
         type = types.listOf types.str;
         default = ["auth_internal" "note"];
-        description = ''
+        description = lib.mdDoc ''
           List of plugins to load automatically for all users.
           System plugins have to be specified here. Please enable at least one
           authentication plugin here (auth_*).
@@ -473,27 +473,27 @@ let
       pluginPackages = mkOption {
         type = types.listOf types.package;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           List of plugins to install. The list elements are expected to
           be derivations. All elements in this derivation are automatically
-          copied to the <literal>plugins.local</literal> directory.
+          copied to the `plugins.local` directory.
         '';
       };
 
       themePackages = mkOption {
         type = types.listOf types.package;
         default = [];
-        description = ''
+        description = lib.mdDoc ''
           List of themes to install. The list elements are expected to
           be derivations. All elements in this derivation are automatically
-          copied to the <literal>themes.local</literal> directory.
+          copied to the `themes.local` directory.
         '';
       };
 
       logDestination = mkOption {
         type = types.enum ["" "sql" "syslog"];
         default = "sql";
-        description = ''
+        description = lib.mdDoc ''
           Log destination to use. Possible values: sql (uses internal logging
           you can read in Preferences -> System), syslog - logs to system log.
           Setting this to blank uses PHP logging (usually to http server
@@ -504,8 +504,8 @@ let
       extraConfig = mkOption {
         type = types.lines;
         default = "";
-        description = ''
-          Additional lines to append to <literal>config.php</literal>.
+        description = lib.mdDoc ''
+          Additional lines to append to `config.php`.
         '';
       };
     };
diff --git a/nixos/modules/services/web-apps/vikunja.nix b/nixos/modules/services/web-apps/vikunja.nix
index 7575e96ca81..7db61015980 100644
--- a/nixos/modules/services/web-apps/vikunja.nix
+++ b/nixos/modules/services/web-apps/vikunja.nix
@@ -15,18 +15,18 @@ in {
       default = pkgs.vikunja-api;
       type = types.package;
       defaultText = literalExpression "pkgs.vikunja-api";
-      description = "vikunja-api derivation to use.";
+      description = lib.mdDoc "vikunja-api derivation to use.";
     };
     package-frontend = mkOption {
       default = pkgs.vikunja-frontend;
       type = types.package;
       defaultText = literalExpression "pkgs.vikunja-frontend";
-      description = "vikunja-frontend derivation to use.";
+      description = lib.mdDoc "vikunja-frontend derivation to use.";
     };
     environmentFiles = mkOption {
       type = types.listOf types.path;
       default = [ ];
-      description = ''
+      description = lib.mdDoc ''
         List of environment files set in the vikunja systemd service.
         For example passwords should be set in one of these files.
       '';
@@ -35,34 +35,34 @@ in {
       type = types.bool;
       default = config.services.nginx.enable;
       defaultText = literalExpression "config.services.nginx.enable";
-      description = ''
+      description = lib.mdDoc ''
         Whether to setup NGINX.
         Further nginx configuration can be done by changing
-        <option>services.nginx.virtualHosts.&lt;frontendHostname&gt;</option>.
+        {option}`services.nginx.virtualHosts.<frontendHostname>`.
         This does not enable TLS or ACME by default. To enable this, set the
-        <option>services.nginx.virtualHosts.&lt;frontendHostname&gt;.enableACME</option> to
-        <literal>true</literal> and if appropriate do the same for
-        <option>services.nginx.virtualHosts.&lt;frontendHostname&gt;.forceSSL</option>.
+        {option}`services.nginx.virtualHosts.<frontendHostname>.enableACME` to
+        `true` and if appropriate do the same for
+        {option}`services.nginx.virtualHosts.<frontendHostname>.forceSSL`.
       '';
     };
     frontendScheme = mkOption {
       type = types.enum [ "http" "https" ];
-      description = ''
+      description = lib.mdDoc ''
         Whether the site is available via http or https.
         This does not configure https or ACME in nginx!
       '';
     };
     frontendHostname = mkOption {
       type = types.str;
-      description = "The Hostname under which the frontend is running.";
+      description = lib.mdDoc "The Hostname under which the frontend is running.";
     };
 
     settings = mkOption {
       type = format.type;
       default = {};
-      description = ''
+      description = lib.mdDoc ''
         Vikunja configuration. Refer to
-        <link xlink:href="https://vikunja.io/docs/config-options/"/>
+        <https://vikunja.io/docs/config-options/>
         for details on supported values.
         '';
     };
@@ -71,27 +71,27 @@ in {
         type = types.enum [ "sqlite" "mysql" "postgres" ];
         example = "postgres";
         default = "sqlite";
-        description = "Database engine to use.";
+        description = lib.mdDoc "Database engine to use.";
       };
       host = mkOption {
         type = types.str;
         default = "localhost";
-        description = "Database host address. Can also be a socket.";
+        description = lib.mdDoc "Database host address. Can also be a socket.";
       };
       user = mkOption {
         type = types.str;
         default = "vikunja";
-        description = "Database user.";
+        description = lib.mdDoc "Database user.";
       };
       database = mkOption {
         type = types.str;
         default = "vikunja";
-        description = "Database name.";
+        description = lib.mdDoc "Database name.";
       };
       path = mkOption {
         type = types.str;
         default = "/var/lib/vikunja/vikunja.db";
-        description = "Path to the sqlite3 database file.";
+        description = lib.mdDoc "Path to the sqlite3 database file.";
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/virtlyst.nix b/nixos/modules/services/web-apps/virtlyst.nix
index 37bdbb0e3b4..5094367a493 100644
--- a/nixos/modules/services/web-apps/virtlyst.nix
+++ b/nixos/modules/services/web-apps/virtlyst.nix
@@ -35,7 +35,7 @@ in
 
     adminPassword = mkOption {
       type = types.str;
-      description = ''
+      description = lib.mdDoc ''
         Initial admin password with which the database will be seeded.
       '';
     };
@@ -43,7 +43,7 @@ in
     httpSocket = mkOption {
       type = types.str;
       default = "localhost:3000";
-      description = ''
+      description = lib.mdDoc ''
         IP and/or port to which to bind the http socket.
       '';
     };
diff --git a/nixos/modules/services/web-apps/whitebophir.nix b/nixos/modules/services/web-apps/whitebophir.nix
index f9db6fe379b..c4dee3c6eec 100644
--- a/nixos/modules/services/web-apps/whitebophir.nix
+++ b/nixos/modules/services/web-apps/whitebophir.nix
@@ -13,19 +13,19 @@ in {
         default = pkgs.whitebophir;
         defaultText = literalExpression "pkgs.whitebophir";
         type = types.package;
-        description = "Whitebophir package to use.";
+        description = lib.mdDoc "Whitebophir package to use.";
       };
 
       listenAddress = mkOption {
         type = types.str;
         default = "0.0.0.0";
-        description = "Address to listen on (use 0.0.0.0 to allow access from any address).";
+        description = lib.mdDoc "Address to listen on (use 0.0.0.0 to allow access from any address).";
       };
 
       port = mkOption {
         type = types.port;
         default = 5001;
-        description = "Port to bind to.";
+        description = lib.mdDoc "Port to bind to.";
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/wiki-js.nix b/nixos/modules/services/web-apps/wiki-js.nix
index 1a6259dffee..474fbb8f13c 100644
--- a/nixos/modules/services/web-apps/wiki-js.nix
+++ b/nixos/modules/services/web-apps/wiki-js.nix
@@ -16,7 +16,7 @@ in {
       type = types.nullOr types.path;
       default = null;
       example = "/root/wiki-js.env";
-      description = ''
+      description = lib.mdDoc ''
         Environment fiel to inject e.g. secrets into the configuration.
       '';
     };
@@ -24,8 +24,8 @@ in {
     stateDirectoryName = mkOption {
       default = "wiki-js";
       type = types.str;
-      description = ''
-        Name of the directory in <filename>/var/lib</filename>.
+      description = lib.mdDoc ''
+        Name of the directory in {file}`/var/lib`.
       '';
     };
 
@@ -37,7 +37,7 @@ in {
           port = mkOption {
             type = types.port;
             default = 3000;
-            description = ''
+            description = lib.mdDoc ''
               TCP port the process should listen to.
             '';
           };
@@ -45,7 +45,7 @@ in {
           bindIP = mkOption {
             default = "0.0.0.0";
             type = types.str;
-            description = ''
+            description = lib.mdDoc ''
               IPs the service should listen to.
             '';
           };
@@ -64,14 +64,14 @@ in {
             host = mkOption {
               type = types.str;
               example = "/run/postgresql";
-              description = ''
+              description = lib.mdDoc ''
                 Hostname or socket-path to connect to.
               '';
             };
             db = mkOption {
               default = "wiki";
               type = types.str;
-              description = ''
+              description = lib.mdDoc ''
                 Name of the database to use.
               '';
             };
@@ -80,7 +80,7 @@ in {
           logLevel = mkOption {
             default = "info";
             type = types.enum [ "error" "warn" "info" "verbose" "debug" "silly" ];
-            description = ''
+            description = lib.mdDoc ''
               Define how much detail is supposed to be logged at runtime.
             '';
           };
diff --git a/nixos/modules/services/web-apps/youtrack.nix b/nixos/modules/services/web-apps/youtrack.nix
index b83265ffeab..789880d61f6 100644
--- a/nixos/modules/services/web-apps/youtrack.nix
+++ b/nixos/modules/services/web-apps/youtrack.nix
@@ -24,7 +24,7 @@ in
     enable = mkEnableOption "YouTrack service";
 
     address = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         The interface youtrack will listen on.
       '';
       default = "127.0.0.1";
@@ -32,7 +32,7 @@ in
     };
 
     baseUrl = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         Base URL for youtrack. Will be auto-detected and stored in database.
       '';
       type = types.nullOr types.str;
@@ -41,7 +41,7 @@ in
 
     extraParams = mkOption {
       default = {};
-      description = ''
+      description = lib.mdDoc ''
         Extra parameters to pass to youtrack. See
         https://www.jetbrains.com/help/youtrack/standalone/YouTrack-Java-Start-Parameters.html
         for more information.
@@ -55,7 +55,7 @@ in
     };
 
     package = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         Package to use.
       '';
       type = types.package;
@@ -64,7 +64,7 @@ in
     };
 
     port = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         The port youtrack will listen on.
       '';
       default = 8080;
@@ -72,7 +72,7 @@ in
     };
 
     statePath = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         Where to keep the youtrack database.
       '';
       type = types.path;
@@ -80,7 +80,7 @@ in
     };
 
     virtualHost = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         Name of the nginx virtual host to use and setup.
         If null, do not setup anything.
       '';
@@ -89,7 +89,7 @@ in
     };
 
     jvmOpts = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         Extra options to pass to the JVM.
         See https://www.jetbrains.com/help/youtrack/standalone/Configure-JVM-Options.html
         for more information.
@@ -100,7 +100,7 @@ in
     };
 
     maxMemory = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         Maximum Java heap size
       '';
       type = types.str;
@@ -108,7 +108,7 @@ in
     };
 
     maxMetaspaceSize = mkOption {
-      description = ''
+      description = lib.mdDoc ''
         Maximum java Metaspace memory.
       '';
       type = types.str;