about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/configuration/xfce.chapter.md11
-rw-r--r--nixos/doc/manual/from_md/configuration/xfce.chapter.xml14
-rw-r--r--nixos/doc/manual/from_md/release-notes/rl-2205.section.xml8
-rw-r--r--nixos/doc/manual/from_md/release-notes/rl-2211.section.xml46
-rw-r--r--nixos/doc/manual/release-notes/rl-2205.section.md2
-rw-r--r--nixos/doc/manual/release-notes/rl-2211.section.md12
-rw-r--r--nixos/modules/config/fonts/fontconfig.nix17
-rw-r--r--nixos/modules/config/i18n.nix13
-rw-r--r--nixos/modules/misc/ids.nix4
-rw-r--r--nixos/modules/misc/nixpkgs.nix6
-rw-r--r--nixos/modules/module-list.nix5
-rw-r--r--nixos/modules/profiles/minimal.nix3
-rw-r--r--nixos/modules/programs/thunar.nix44
-rw-r--r--nixos/modules/rename.nix1
-rw-r--r--nixos/modules/services/audio/navidrome.nix1
-rw-r--r--nixos/modules/services/databases/riak.nix162
-rw-r--r--nixos/modules/services/hardware/argonone.nix58
-rw-r--r--nixos/modules/services/logging/logrotate.nix2
-rw-r--r--nixos/modules/services/mail/schleuder.nix162
-rw-r--r--nixos/modules/services/matrix/appservice-irc.nix3
-rw-r--r--nixos/modules/services/misc/gitlab.nix28
-rw-r--r--nixos/modules/services/misc/paperless.nix2
-rw-r--r--nixos/modules/services/misc/radarr.nix10
-rw-r--r--nixos/modules/services/networking/prosody.nix79
-rw-r--r--nixos/modules/services/networking/routedns.nix84
-rw-r--r--nixos/modules/services/web-apps/hedgedoc.nix3
-rw-r--r--nixos/modules/services/web-apps/tt-rss.nix1
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix4
-rw-r--r--nixos/modules/services/web-servers/nginx/location-options.nix11
-rw-r--r--nixos/modules/services/web-servers/nginx/vhost-options.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix20
-rw-r--r--nixos/tests/all-tests.nix3
-rw-r--r--nixos/tests/containers-custom-pkgs.nix2
-rw-r--r--nixos/tests/matrix/appservice-irc.nix3
-rw-r--r--nixos/tests/paperless.nix2
-rw-r--r--nixos/tests/pykms.nix14
-rw-r--r--nixos/tests/riak.nix18
-rw-r--r--nixos/tests/schleuder.nix128
-rw-r--r--nixos/tests/systemd-networkd-vrf.nix50
-rw-r--r--nixos/tests/traefik.nix22
-rw-r--r--nixos/tests/vengi-tools.nix2
41 files changed, 778 insertions, 284 deletions
diff --git a/nixos/doc/manual/configuration/xfce.chapter.md b/nixos/doc/manual/configuration/xfce.chapter.md
index b0ef6682aae86..ee60d465e3b30 100644
--- a/nixos/doc/manual/configuration/xfce.chapter.md
+++ b/nixos/doc/manual/configuration/xfce.chapter.md
@@ -24,11 +24,16 @@ Some Xfce programs are not installed automatically. To install them
 manually (system wide), put them into your
 [](#opt-environment.systemPackages) from `pkgs.xfce`.
 
-## Thunar Plugins {#sec-xfce-thunar-plugins .unnumbered}
+## Thunar {#sec-xfce-thunar-plugins .unnumbered}
+
+Thunar (the Xfce file manager) is automatically enabled when Xfce is
+enabled. To enable Thunar without enabling Xfce, use the configuration
+option [](#opt-programs.thunar.enable) instead of simply adding
+`pkgs.xfce.thunar` to [](#opt-environment.systemPackages).
 
 If you\'d like to add extra plugins to Thunar, add them to
-[](#opt-services.xserver.desktopManager.xfce.thunarPlugins).
-You shouldn\'t just add them to [](#opt-environment.systemPackages).
+[](#opt-programs.thunar.plugins). You shouldn\'t just add them to
+[](#opt-environment.systemPackages).
 
 ## Troubleshooting {#sec-xfce-troubleshooting .unnumbered}
 
diff --git a/nixos/doc/manual/from_md/configuration/xfce.chapter.xml b/nixos/doc/manual/from_md/configuration/xfce.chapter.xml
index f96ef2e8c483c..42e70d1d81d30 100644
--- a/nixos/doc/manual/from_md/configuration/xfce.chapter.xml
+++ b/nixos/doc/manual/from_md/configuration/xfce.chapter.xml
@@ -27,13 +27,19 @@ services.picom = {
     <literal>pkgs.xfce</literal>.
   </para>
   <section xml:id="sec-xfce-thunar-plugins">
-    <title>Thunar Plugins</title>
+    <title>Thunar</title>
     <para>
-      If you'd like to add extra plugins to Thunar, add them to
-      <xref linkend="opt-services.xserver.desktopManager.xfce.thunarPlugins" />.
-      You shouldn't just add them to
+      Thunar (the Xfce file manager) is automatically enabled when Xfce
+      is enabled. To enable Thunar without enabling Xfce, use the
+      configuration option <xref linkend="opt-programs.thunar.enable" />
+      instead of simply adding <literal>pkgs.xfce.thunar</literal> to
       <xref linkend="opt-environment.systemPackages" />.
     </para>
+    <para>
+      If you'd like to add extra plugins to Thunar, add them to
+      <xref linkend="opt-programs.thunar.plugins" />. You shouldn't just
+      add them to <xref linkend="opt-environment.systemPackages" />.
+    </para>
   </section>
   <section xml:id="sec-xfce-troubleshooting">
     <title>Troubleshooting</title>
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
index 678c73bcb412e..245250e709147 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
@@ -148,6 +148,14 @@
       </listitem>
       <listitem>
         <para>
+          <link xlink:href="https://gitlab.com/DarkElvenAngel/argononed">argonone</link>,
+          a replacement daemon for the Raspberry Pi Argon One power
+          button and cooler. Available at
+          <link xlink:href="options.html#opt-services.hardware.argonone.enable">services.hardware.argonone</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           <link xlink:href="https://github.com/JustArchiNET/ArchiSteamFarm">ArchiSteamFarm</link>,
           a C# application with primary purpose of idling Steam cards
           from multiple accounts simultaneously. Available as
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
index c62efadbbf1ad..a11c2bb61ffb4 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
@@ -144,6 +144,13 @@
       </listitem>
       <listitem>
         <para>
+          <link xlink:href="https://schleuder.org/">schleuder</link>, a
+          mailing list manager with PGP support. Enable using
+          <link linkend="opt-services.schleuder.enable">services.schleuder</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           <link xlink:href="https://www.expressvpn.com">expressvpn</link>,
           the CLI client for ExpressVPN. Available as
           <link linkend="opt-services.expressvpn.enable">services.expressvpn</link>.
@@ -184,6 +191,18 @@
       </listitem>
       <listitem>
         <para>
+          <literal>i18n.supportedLocales</literal> is now by default
+          only generated with the locales set in
+          <literal>i18n.defaultLocale</literal> and
+          <literal>i18n.extraLocaleSettings</literal>. This got
+          partially copied over from the minimal profile and reduces the
+          final system size by up to 200MB. If you require all locales
+          installed set the option to
+          <literal>[ &quot;all&quot; ]</literal>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           The <literal>isPowerPC</literal> predicate, found on
           <literal>platform</literal> attrsets
           (<literal>hostPlatform</literal>,
@@ -199,6 +218,14 @@
       </listitem>
       <listitem>
         <para>
+          <literal>bsp-layout</literal> no longer uses the command
+          <literal>cycle</literal> to switch to other window layouts, as
+          it got replaced by the commands <literal>previous</literal>
+          and <literal>next</literal>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           The Barco ClickShare driver/client package
           <literal>pkgs.clickshare-csc1</literal> and the option
           <literal>programs.clickshare-csc1.enable</literal> have been
@@ -218,6 +245,13 @@
       </listitem>
       <listitem>
         <para>
+          riak package removed along with
+          <literal>services.riak</literal> module, due to lack of
+          maintainer to update the package.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           (Neo)Vim can not be configured with
           <literal>configure.pathogen</literal> anymore to reduce
           maintainance burden. Use <literal>configure.packages</literal>
@@ -269,6 +303,18 @@
           as coreboot’s fork is no longer available.
         </para>
       </listitem>
+      <listitem>
+        <para>
+          There is a new module for the <literal>thunar</literal>
+          program (the Xfce file manager), which depends on the
+          <literal>xfconf</literal> dbus service, and also has a dbus
+          service and a systemd unit. The option
+          <literal>services.xserver.desktopManager.xfce.thunarPlugins</literal>
+          has been renamed to
+          <literal>programs.thunar.plugins</literal>, and in a future
+          release it may be removed.
+        </para>
+      </listitem>
     </itemizedlist>
   </section>
 </section>
diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md
index 9c2f9bcff572a..e83a7cd43b876 100644
--- a/nixos/doc/manual/release-notes/rl-2205.section.md
+++ b/nixos/doc/manual/release-notes/rl-2205.section.md
@@ -61,6 +61,8 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - [apfs](https://github.com/linux-apfs/linux-apfs-rw), a kernel module for mounting the Apple File System (APFS).
 
+- [argonone](https://gitlab.com/DarkElvenAngel/argononed), a replacement daemon for the Raspberry Pi Argon One power button and cooler. Available at [services.hardware.argonone](options.html#opt-services.hardware.argonone.enable).
+
 - [ArchiSteamFarm](https://github.com/JustArchiNET/ArchiSteamFarm), a C# application with primary purpose of idling Steam cards from multiple accounts simultaneously. Available as [services.archisteamfarm](#opt-services.archisteamfarm.enable).
 
 - [BaGet](https://loic-sharma.github.io/BaGet/), a lightweight NuGet and symbol server. Available at [services.baget](#opt-services.baget.enable).
diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md
index f6366c14cf48b..275c522a54f1a 100644
--- a/nixos/doc/manual/release-notes/rl-2211.section.md
+++ b/nixos/doc/manual/release-notes/rl-2211.section.md
@@ -60,6 +60,8 @@ In addition to numerous new and upgraded packages, this release has the followin
   Available as [services.infnoise](options.html#opt-services.infnoise.enable).
 - [persistent-evdev](https://github.com/aiberia/persistent-evdev), a daemon to add virtual proxy devices that mirror a physical input device but persist even if the underlying hardware is hot-plugged. Available as [services.persistent-evdev](#opt-services.persistent-evdev.enable).
 
+- [schleuder](https://schleuder.org/), a mailing list manager with PGP support. Enable using [services.schleuder](#opt-services.schleuder.enable).
+
 - [expressvpn](https://www.expressvpn.com), the CLI client for ExpressVPN. Available as [services.expressvpn](#opt-services.expressvpn.enable).
 
 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
@@ -78,8 +80,14 @@ In addition to numerous new and upgraded packages, this release has the followin
   and [changelog](https://ngrok.com/docs/ngrok-agent/changelog). Notably, breaking changes are that the config file format has
   changed and support for single hypen arguments was dropped.
 
+- `i18n.supportedLocales` is now by default only generated with the locales set in `i18n.defaultLocale` and `i18n.extraLocaleSettings`.
+  This got partially copied over from the minimal profile and reduces the final system size by up to 200MB.
+  If you require all locales installed set the option to ``[ "all" ]``.
+
 - The `isPowerPC` predicate, found on `platform` attrsets (`hostPlatform`, `buildPlatform`, `targetPlatform`, etc) has been removed in order to reduce confusion.  The predicate was was defined such that it matches only the 32-bit big-endian members of the POWER/PowerPC family, despite having a name which would imply a broader set of systems.  If you were using this predicate, you can replace `foo.isPowerPC` with `(with foo; isPower && is32bit && isBigEndian)`.
 
+- `bsp-layout` no longer uses the command `cycle` to switch to other window layouts, as it got replaced by the commands `previous` and `next`.
+
 - The Barco ClickShare driver/client package `pkgs.clickshare-csc1` and the option `programs.clickshare-csc1.enable` have been removed,
   as it requires `qt4`, which reached its end-of-life 2015 and will no longer be supported by nixpkgs.
   [According to Barco](https://www.barco.com/de/support/knowledge-base/4380-can-i-use-linux-os-with-clickshare-base-units) many of their base unit models can be used with Google Chrome and the Google Cast extension.
@@ -87,6 +95,8 @@ In addition to numerous new and upgraded packages, this release has the followin
 - PHP 7.4 is no longer supported due to upstream not supporting this
   version for the entire lifecycle of the 22.11 release.
 
+- riak package removed along with `services.riak` module, due to lack of maintainer to update the package.
+
 - (Neo)Vim can not be configured with `configure.pathogen` anymore to reduce maintainance burden.
 Use `configure.packages` instead.
 
@@ -104,4 +114,6 @@ Use `configure.packages` instead.
 
 - memtest86+ was updated from 5.00-coreboot-002 to 6.00-beta2. It is now the upstream version from https://www.memtest.org/, as coreboot's fork is no longer available.
 
+- There is a new module for the `thunar` program (the Xfce file manager), which depends on the `xfconf` dbus service, and also has a dbus service and a systemd unit. The option `services.xserver.desktopManager.xfce.thunarPlugins` has been renamed to `programs.thunar.plugins`, and in a future release it may be removed.
+
 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix
index 1e68fef7ce74c..a10a8c6428a10 100644
--- a/nixos/modules/config/fonts/fontconfig.nix
+++ b/nixos/modules/config/fonts/fontconfig.nix
@@ -65,7 +65,7 @@ let
           ${fcBool cfg.hinting.autohint}
         </edit>
         <edit mode="append" name="hintstyle">
-          <const>hintslight</const>
+          <const>${cfg.hinting.style}</const>
         </edit>
         <edit mode="append" name="antialias">
           ${fcBool cfg.antialias}
@@ -226,7 +226,6 @@ in
     (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "useEmbeddedBitmaps" ] [ "fonts" "fontconfig" "useEmbeddedBitmaps" ])
     (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "forceAutohint" ] [ "fonts" "fontconfig" "forceAutohint" ])
     (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "renderMonoTTFAsBitmap" ] [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ])
-    (mkRemovedOptionModule [ "fonts" "fontconfig" "hinting" "style" ] "")
     (mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "")
     (mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "")
     (mkRemovedOptionModule [ "fonts" "fontconfig" "dpi" ] "Use display server-specific options")
@@ -349,6 +348,20 @@ in
               fonts, but better than unhinted fonts.
             '';
           };
+
+          style = mkOption {
+            type = types.enum [ "hintnone" "hintslight" "hintmedium" "hintfull" ];
+            default = "hintslight";
+            description = ''
+              Hintstyle is the amount of font reshaping done to line up
+              to the grid.
+
+              hintslight will make the font more fuzzy to line up to the grid
+              but will be better in retaining font shape, while hintfull will
+              be a crisp font that aligns well to the pixel grid but will lose
+              a greater amount of font shape.
+            '';
+          };
         };
 
         includeUserConf = mkOption {
diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix
index 5b8d5b214496b..c55726d09c608 100644
--- a/nixos/modules/config/i18n.nix
+++ b/nixos/modules/config/i18n.nix
@@ -53,7 +53,18 @@ with lib;
 
       supportedLocales = mkOption {
         type = types.listOf types.str;
-        default = ["all"];
+        default = builtins.map (l: l + "/UTF-8")
+          (unique (
+            [ config.i18n.defaultLocale ] ++
+            (attrValues (filterAttrs (n: v: n != "LANGUAGE") config.i18n.extraLocaleSettings))
+          ));
+        defaultText = literalExpression ''
+          builtins.map (l: l + "/UTF-8")
+            (unique (
+              [ config.i18n.defaultLocale ] ++
+              (attrValues (filterAttrs (n: v: n != "LANGUAGE") config.i18n.extraLocaleSettings))
+            ))
+        '';
         example = ["en_US.UTF-8/UTF-8" "nl_NL.UTF-8/UTF-8" "nl_NL/ISO-8859-1"];
         description = ''
           List of locales that the system should support.  The value
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 7d1faa50f4bfa..05d483af3c2e4 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -236,7 +236,7 @@ in
       gitit = 202;
       riemanntools = 203;
       subsonic = 204;
-      riak = 205;
+      # riak = 205; # unused, remove 2022-07-22
       #shout = 206; # dynamically allocated as of 2021-09-18
       gateone = 207;
       namecoin = 208;
@@ -553,7 +553,7 @@ in
       gitit = 202;
       riemanntools = 203;
       subsonic = 204;
-      riak = 205;
+      # riak = 205;#unused, removed 2022-06-22
       #shout = 206; #unused
       gateone = 207;
       namecoin = 208;
diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix
index 132a9b68ceb49..ad017aff816c7 100644
--- a/nixos/modules/misc/nixpkgs.nix
+++ b/nixos/modules/misc/nixpkgs.nix
@@ -69,9 +69,9 @@ let
     }'';
 
   legacyOptionsDefined =
-    optional opt.system.isDefined opt.system
-    ++ (optional (opt.localSystem.highestPrio < (mkOptionDefault {}).priority) opt.localSystem)
-    ++ (optional (opt.crossSystem.highestPrio < (mkOptionDefault {}).priority) opt.crossSystem)
+    optional (opt.localSystem.highestPrio < (mkDefault {}).priority) opt.system
+    ++ optional (opt.localSystem.highestPrio < (mkOptionDefault {}).priority) opt.localSystem
+    ++ optional (opt.crossSystem.highestPrio < (mkOptionDefault {}).priority) opt.crossSystem
     ;
 
   defaultPkgs =
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 40a84730dfc1e..b757e05edce3a 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -217,6 +217,7 @@
   ./programs/sway.nix
   ./programs/system-config-printer.nix
   ./programs/thefuck.nix
+  ./programs/thunar.nix
   ./programs/tmux.nix
   ./programs/traceroute.nix
   ./programs/tsm-client.nix
@@ -365,7 +366,6 @@
   ./services/databases/pgmanage.nix
   ./services/databases/postgresql.nix
   ./services/databases/redis.nix
-  ./services/databases/riak.nix
   ./services/databases/victoriametrics.nix
   ./services/desktops/accountsservice.nix
   ./services/desktops/bamf.nix
@@ -430,6 +430,7 @@
   ./services/games/terraria.nix
   ./services/hardware/acpid.nix
   ./services/hardware/actkbd.nix
+  ./services/hardware/argonone.nix
   ./services/hardware/auto-cpufreq.nix
   ./services/hardware/bluetooth.nix
   ./services/hardware/bolt.nix
@@ -515,6 +516,7 @@
   ./services/mail/rspamd.nix
   ./services/mail/rss2email.nix
   ./services/mail/roundcube.nix
+  ./services/mail/schleuder.nix
   ./services/mail/sympa.nix
   ./services/mail/nullmailer.nix
   ./services/matrix/appservice-discord.nix
@@ -893,6 +895,7 @@
   ./services/networking/redsocks.nix
   ./services/networking/resilio.nix
   ./services/networking/robustirc-bridge.nix
+  ./services/networking/routedns.nix
   ./services/networking/rpcbind.nix
   ./services/networking/rxe.nix
   ./services/networking/sabnzbd.nix
diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix
index e79b927238419..0e65989214a18 100644
--- a/nixos/modules/profiles/minimal.nix
+++ b/nixos/modules/profiles/minimal.nix
@@ -8,9 +8,6 @@ with lib;
 {
   environment.noXlibs = mkDefault true;
 
-  # This isn't perfect, but let's expect the user specifies an UTF-8 defaultLocale
-  i18n.supportedLocales = [ (config.i18n.defaultLocale + "/UTF-8") ];
-
   documentation.enable = mkDefault false;
 
   documentation.nixos.enable = mkDefault false;
diff --git a/nixos/modules/programs/thunar.nix b/nixos/modules/programs/thunar.nix
new file mode 100644
index 0000000000000..343f84698672a
--- /dev/null
+++ b/nixos/modules/programs/thunar.nix
@@ -0,0 +1,44 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let cfg = config.programs.thunar;
+
+in {
+  meta = {
+    maintainers = teams.xfce.members;
+  };
+
+  options = {
+    programs.thunar = {
+      enable = mkEnableOption "Thunar, the Xfce file manager";
+
+      plugins = mkOption {
+        default = [];
+        type = types.listOf types.package;
+        description = "List of thunar plugins to install.";
+        example = literalExpression "with pkgs.xfce; [ thunar-archive-plugin thunar-volman ]";
+      };
+
+    };
+  };
+
+  config = mkIf cfg.enable (
+    let package = pkgs.xfce.thunar.override { thunarPlugins = cfg.plugins; };
+
+    in {
+      environment.systemPackages = [
+        package
+      ];
+
+      services.dbus.packages = [
+        package
+        pkgs.xfce.xfconf
+      ];
+
+      systemd.packages = [
+        package
+      ];
+    }
+  );
+}
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 1d22627649304..7a6a6b5ed30bb 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -97,6 +97,7 @@ with lib;
     (mkRemovedOptionModule [ "services" "gogoclient" ] "The corresponding package was removed from nixpkgs.")
     (mkRemovedOptionModule [ "services" "virtuoso" ] "The corresponding package was removed from nixpkgs.")
     (mkRemovedOptionModule [ "services" "openfire" ] "The corresponding package was removed from nixpkgs.")
+    (mkRemovedOptionModule [ "services" "riak" ] "The corresponding package was removed from nixpkgs.")
 
     # Do NOT add any option renames here, see top of the file
   ];
diff --git a/nixos/modules/services/audio/navidrome.nix b/nixos/modules/services/audio/navidrome.nix
index b50cb04155697..319212c020777 100644
--- a/nixos/modules/services/audio/navidrome.nix
+++ b/nixos/modules/services/audio/navidrome.nix
@@ -48,6 +48,7 @@ in {
           # navidrome uses online services to download additional album metadata / covers
           "${config.environment.etc."ssl/certs/ca-certificates.crt".source}:/etc/ssl/certs/ca-certificates.crt"
           builtins.storeDir
+          "/etc"
         ] ++ lib.optional (cfg.settings ? MusicFolder) cfg.settings.MusicFolder;
         CapabilityBoundingSet = "";
         RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
diff --git a/nixos/modules/services/databases/riak.nix b/nixos/modules/services/databases/riak.nix
deleted file mode 100644
index cc4237d038cdb..0000000000000
--- a/nixos/modules/services/databases/riak.nix
+++ /dev/null
@@ -1,162 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  cfg = config.services.riak;
-
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    services.riak = {
-
-      enable = mkEnableOption "riak";
-
-      package = mkOption {
-        type = types.package;
-        default = pkgs.riak;
-        defaultText = literalExpression "pkgs.riak";
-        description = ''
-          Riak package to use.
-        '';
-      };
-
-      nodeName = mkOption {
-        type = types.str;
-        default = "riak@127.0.0.1";
-        description = ''
-          Name of the Erlang node.
-        '';
-      };
-
-      distributedCookie = mkOption {
-        type = types.str;
-        default = "riak";
-        description = ''
-          Cookie for distributed node communication.  All nodes in the
-          same cluster should use the same cookie or they will not be able to
-          communicate.
-        '';
-      };
-
-      dataDir = mkOption {
-        type = types.path;
-        default = "/var/db/riak";
-        description = ''
-          Data directory for Riak.
-        '';
-      };
-
-      logDir = mkOption {
-        type = types.path;
-        default = "/var/log/riak";
-        description = ''
-          Log directory for Riak.
-        '';
-      };
-
-      extraConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = ''
-          Additional text to be appended to <filename>riak.conf</filename>.
-        '';
-      };
-
-      extraAdvancedConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = ''
-          Additional text to be appended to <filename>advanced.config</filename>.
-        '';
-      };
-
-    };
-
-  };
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-
-    environment.systemPackages = [ cfg.package ];
-    environment.etc."riak/riak.conf".text = ''
-      nodename = ${cfg.nodeName}
-      distributed_cookie = ${cfg.distributedCookie}
-
-      platform_log_dir = ${cfg.logDir}
-      platform_etc_dir = /etc/riak
-      platform_data_dir = ${cfg.dataDir}
-
-      ${cfg.extraConfig}
-    '';
-
-    environment.etc."riak/advanced.config".text = ''
-      ${cfg.extraAdvancedConfig}
-    '';
-
-    users.users.riak = {
-      name = "riak";
-      uid = config.ids.uids.riak;
-      group = "riak";
-      description = "Riak server user";
-    };
-
-    users.groups.riak.gid = config.ids.gids.riak;
-
-    systemd.services.riak = {
-      description = "Riak Server";
-
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
-
-      path = [
-        pkgs.util-linux # for `logger`
-        pkgs.bash
-      ];
-
-      environment.HOME = "${cfg.dataDir}";
-      environment.RIAK_DATA_DIR = "${cfg.dataDir}";
-      environment.RIAK_LOG_DIR = "${cfg.logDir}";
-      environment.RIAK_ETC_DIR = "/etc/riak";
-
-      preStart = ''
-        if ! test -e ${cfg.logDir}; then
-          mkdir -m 0755 -p ${cfg.logDir}
-          chown -R riak ${cfg.logDir}
-        fi
-
-        if ! test -e ${cfg.dataDir}; then
-          mkdir -m 0700 -p ${cfg.dataDir}
-          chown -R riak ${cfg.dataDir}
-        fi
-      '';
-
-      serviceConfig = {
-        ExecStart = "${cfg.package}/bin/riak console";
-        ExecStop = "${cfg.package}/bin/riak stop";
-        StandardInput = "tty";
-        User = "riak";
-        Group = "riak";
-        PermissionsStartOnly = true;
-        # Give Riak a decent amount of time to clean up.
-        TimeoutStopSec = 120;
-        LimitNOFILE = 65536;
-      };
-
-      unitConfig.RequiresMountsFor = [
-        "${cfg.dataDir}"
-        "${cfg.logDir}"
-        "/etc/riak"
-      ];
-    };
-
-  };
-
-}
diff --git a/nixos/modules/services/hardware/argonone.nix b/nixos/modules/services/hardware/argonone.nix
new file mode 100644
index 0000000000000..638181b1b12e2
--- /dev/null
+++ b/nixos/modules/services/hardware/argonone.nix
@@ -0,0 +1,58 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.hardware.argonone;
+in
+{
+  options.services.hardware.argonone = {
+    enable = lib.mkEnableOption "the driver for Argon One Raspberry Pi case fan and power button";
+    package = lib.mkOption {
+      type = lib.types.package;
+      default = pkgs.argononed;
+      defaultText = "pkgs.argononed";
+      description = ''
+        The package implementing the Argon One driver
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    hardware.i2c.enable = true;
+    hardware.deviceTree.overlays = [
+      {
+        name = "argononed";
+        dtboFile = "${cfg.package}/boot/overlays/argonone.dtbo";
+      }
+      {
+        name = "i2c1-okay-overlay";
+        dtsText = ''
+          /dts-v1/;
+          /plugin/;
+          / {
+            compatible = "brcm,bcm2711";
+            fragment@0 {
+              target = <&i2c1>;
+              __overlay__ {
+                status = "okay";
+              };
+            };
+          };
+        '';
+      }
+    ];
+    environment.systemPackages = [ cfg.package ];
+    systemd.services.argononed = {
+      description = "Argon One Raspberry Pi case Daemon Service";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        Type = "forking";
+        ExecStart = "${cfg.package}/bin/argononed";
+        PIDFile = "/run/argononed.pid";
+        Restart = "on-failure";
+      };
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ misterio77 ];
+
+}
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
index e6eb0552c9e95..dfc58d7d539c4 100644
--- a/nixos/modules/services/logging/logrotate.nix
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -193,7 +193,7 @@ let
   };
 
   mailOption =
-    if foldr (n: a: a || n ? mail) false (attrValues cfg.settings)
+    if foldr (n: a: a || (n.mail or false) != false) false (attrValues cfg.settings)
     then "--mail=${pkgs.mailutils}/bin/mail"
     else "";
 in
diff --git a/nixos/modules/services/mail/schleuder.nix b/nixos/modules/services/mail/schleuder.nix
new file mode 100644
index 0000000000000..7ba15f1070bde
--- /dev/null
+++ b/nixos/modules/services/mail/schleuder.nix
@@ -0,0 +1,162 @@
+{ config, pkgs, lib, ... }:
+let
+  cfg = config.services.schleuder;
+  settingsFormat = pkgs.formats.yaml { };
+  postfixMap = entries: lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "${name} ${value}") entries);
+  writePostfixMap = name: entries: pkgs.writeText name (postfixMap entries);
+  configScript = pkgs.writeScript "schleuder-cfg" ''
+    #!${pkgs.runtimeShell}
+    set -exuo pipefail
+    umask 0077
+    ${pkgs.yq}/bin/yq \
+      --slurpfile overrides <(${pkgs.yq}/bin/yq . <${lib.escapeShellArg cfg.extraSettingsFile}) \
+      < ${settingsFormat.generate "schleuder.yml" cfg.settings} \
+      '. * $overrides[0]' \
+      > /etc/schleuder/schleuder.yml
+    chown schleuder: /etc/schleuder/schleuder.yml
+  '';
+in
+{
+  options.services.schleuder = {
+    enable = lib.mkEnableOption "Schleuder secure remailer";
+    enablePostfix = lib.mkEnableOption "automatic postfix integration" // { default = true; };
+    lists = lib.mkOption {
+      description = ''
+        List of list addresses that should be handled by Schleuder.
+
+        Note that this is only handled by the postfix integration, and
+        the setup of the lists, their members and their keys has to be
+        performed separately via schleuder's API, using a tool such as
+        schleuder-cli.
+      '';
+      type = lib.types.listOf lib.types.str;
+      default = [ ];
+      example = [ "widget-team@example.com" "security@example.com" ];
+    };
+    /* maybe one day....
+      domains = lib.mkOption {
+      description = "Domains for which all mail should be handled by Schleuder.";
+      type = lib.types.listOf lib.types.str;
+      default = [];
+      example = ["securelists.example.com"];
+      };
+    */
+    settings = lib.mkOption {
+      description = ''
+        Settings for schleuder.yml.
+
+        Check the <link xlink:href="https://0xacab.org/schleuder/schleuder/blob/master/etc/schleuder.yml">example configuration</link> for possible values.
+      '';
+      type = lib.types.submodule {
+        freeformType = settingsFormat.type;
+        options.keyserver = lib.mkOption {
+          type = lib.types.str;
+          description = ''
+            Key server from which to fetch and update keys.
+
+            Note that NixOS uses a different default from upstream, since the upstream default sks-keyservers.net is deprecated.
+          '';
+          default = "keys.openpgp.org";
+        };
+      };
+      default = { };
+    };
+    extraSettingsFile = lib.mkOption {
+      description = "YAML file to merge into the schleuder config at runtime. This can be used for secrets such as API keys.";
+      type = lib.types.nullOr lib.types.path;
+      default = null;
+    };
+    listDefaults = lib.mkOption {
+      description = ''
+        Default settings for lists (list-defaults.yml).
+
+        Check the <link xlink:href="https://0xacab.org/schleuder/schleuder/-/blob/master/etc/list-defaults.yml">example configuration</link> for possible values.
+      '';
+      type = settingsFormat.type;
+      default = { };
+    };
+  };
+  config = lib.mkIf cfg.enable {
+    assertions = [
+      {
+        assertion = !(cfg.settings.api ? valid_api_keys);
+        message = ''
+          services.schleuder.settings.api.valid_api_keys is set. Defining API keys via NixOS config results in them being copied to the world-readable Nix store. Please use the extraSettingsFile option to store API keys in a non-public location.
+        '';
+      }
+      {
+        assertion = !(lib.any (db: db ? password) (lib.attrValues cfg.settings.database or {}));
+        message = ''
+          A password is defined for at least one database in services.schleuder.settings.database. Defining passwords via NixOS config results in them being copied to the world-readable Nix store. Please use the extraSettingsFile option to store database passwords in a non-public location.
+        '';
+      }
+    ];
+    users.users.schleuder.isSystemUser = true;
+    users.users.schleuder.group = "schleuder";
+    users.groups.schleuder = {};
+    environment.systemPackages = [
+      pkgs.schleuder-cli
+    ];
+    services.postfix = lib.mkIf cfg.enablePostfix {
+      extraMasterConf = ''
+        schleuder  unix  -       n       n       -       -       pipe
+          flags=DRhu user=schleuder argv=/${pkgs.schleuder}/bin/schleuder work ''${recipient}
+      '';
+      transport = lib.mkIf (cfg.lists != [ ]) (postfixMap (lib.genAttrs cfg.lists (_: "schleuder:")));
+      extraConfig = ''
+        schleuder_destination_recipient_limit = 1
+      '';
+      # review: does this make sense?
+      localRecipients = lib.mkIf (cfg.lists != [ ]) cfg.lists;
+    };
+    systemd.services = let commonServiceConfig = {
+      # We would have liked to use DynamicUser, but since the default
+      # database is SQLite and lives in StateDirectory, and that same
+      # database needs to be readable from the postfix service, this
+      # isn't trivial to do.
+      User = "schleuder";
+      StateDirectory = "schleuder";
+      StateDirectoryMode = "0700";
+    }; in
+      {
+        schleuder-init = {
+          serviceConfig = commonServiceConfig // {
+            ExecStartPre = lib.mkIf (cfg.extraSettingsFile != null) [
+              "+${configScript}"
+            ];
+            ExecStart = [ "${pkgs.schleuder}/bin/schleuder install" ];
+            Type = "oneshot";
+          };
+        };
+        schleuder-api-daemon = {
+          after = [ "local-fs.target" "network.target" "schleuder-init.service" ];
+          wantedBy = [ "multi-user.target" ];
+          requires = [ "schleuder-init.service" ];
+          serviceConfig = commonServiceConfig // {
+            ExecStart = [ "${pkgs.schleuder}/bin/schleuder-api-daemon" ];
+          };
+        };
+        schleuder-weekly-key-maintenance = {
+          after = [ "local-fs.target" "network.target" ];
+          startAt = "weekly";
+          serviceConfig = commonServiceConfig // {
+            ExecStart = [
+              "${pkgs.schleuder}/bin/schleuder refresh_keys"
+              "${pkgs.schleuder}/bin/schleuder check_keys"
+            ];
+          };
+        };
+      };
+
+    environment.etc."schleuder/schleuder.yml" = lib.mkIf (cfg.extraSettingsFile == null) {
+      source = settingsFormat.generate "schleuder.yml" cfg.settings;
+    };
+    environment.etc."schleuder/list-defaults.yml".source = settingsFormat.generate "list-defaults.yml" cfg.listDefaults;
+
+    services.schleuder = {
+      #lists_dir = "/var/lib/schleuder.lists";
+      settings.filters_dir = lib.mkDefault "/var/lib/schleuder/filters";
+      settings.keyword_handlers_dir = lib.mkDefault "/var/lib/schleuder/keyword_handlers";
+    };
+  };
+}
diff --git a/nixos/modules/services/matrix/appservice-irc.nix b/nixos/modules/services/matrix/appservice-irc.nix
index b041c9c82c56e..ff938527ed58a 100644
--- a/nixos/modules/services/matrix/appservice-irc.nix
+++ b/nixos/modules/services/matrix/appservice-irc.nix
@@ -153,6 +153,9 @@ in {
     systemd.services.matrix-appservice-irc = {
       description = "Matrix-IRC bridge";
       before = [ "matrix-synapse.service" ]; # So the registration can be used by Synapse
+      after = lib.optionals (cfg.settings.database.engine == "postgres") [
+        "postgresql.service"
+      ];
       wantedBy = [ "multi-user.target" ];
 
       preStart = ''
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 24eefb7bf302c..0b8bd08a22bc5 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -13,6 +13,22 @@ let
                       else
                         pkgs.postgresql_12;
 
+  # Git 2.36.1 seemingly contains a commit-graph related bug which is
+  # easily triggered through GitLab, so we downgrade it to 2.35.x
+  # until this issue is solved. See
+  # https://gitlab.com/gitlab-org/gitlab/-/issues/360783#note_992870101.
+  gitPackage =
+    let
+      version = "2.35.3";
+    in
+      pkgs.git.overrideAttrs (oldAttrs: rec {
+        inherit version;
+        src = pkgs.fetchurl {
+          url = "https://www.kernel.org/pub/software/scm/git/git-${version}.tar.xz";
+          sha256 = "sha256-FenbT5vy7Z//MMtioAxcfAkBAV9asEjNtOiwTd7gD6I=";
+        };
+      });
+
   gitlabSocket = "${cfg.statePath}/tmp/sockets/gitlab.socket";
   gitalySocket = "${cfg.statePath}/tmp/sockets/gitaly.socket";
   pathUrlQuote = url: replaceStrings ["/"] ["%2F"] url;
@@ -41,7 +57,7 @@ let
     prometheus_listen_addr = "localhost:9236"
 
     [git]
-    bin_path = "${pkgs.git}/bin/git"
+    bin_path = "${gitPackage}/bin/git"
 
     [gitaly-ruby]
     dir = "${cfg.packages.gitaly.ruby}"
@@ -137,7 +153,7 @@ let
       };
       workhorse.secret_file = "${cfg.statePath}/.gitlab_workhorse_secret";
       gitlab_kas.secret_file = "${cfg.statePath}/.gitlab_kas_secret";
-      git.bin_path = "git";
+      git.bin_path = "${gitPackage}/bin/git";
       monitoring = {
         ip_whitelist = [ "127.0.0.0/8" "::1/128" ];
         sidekiq_exporter = {
@@ -1275,7 +1291,7 @@ in {
       });
       path = with pkgs; [
         postgresqlPackage
-        git
+        gitPackage
         ruby
         openssh
         nodejs
@@ -1306,7 +1322,7 @@ in {
       path = with pkgs; [
         openssh
         procps  # See https://gitlab.com/gitlab-org/gitaly/issues/1562
-        git
+        gitPackage
         cfg.packages.gitaly.rubyEnv
         cfg.packages.gitaly.rubyEnv.wrappedRuby
         gzip
@@ -1351,7 +1367,7 @@ in {
       partOf = [ "gitlab.target" ];
       path = with pkgs; [
         exiftool
-        git
+        gitPackage
         gnutar
         gzip
         openssh
@@ -1412,7 +1428,7 @@ in {
       environment = gitlabEnv;
       path = with pkgs; [
         postgresqlPackage
-        git
+        gitPackage
         openssh
         nodejs
         procps
diff --git a/nixos/modules/services/misc/paperless.nix b/nixos/modules/services/misc/paperless.nix
index bfaf842fb464f..17cd555d7e1bd 100644
--- a/nixos/modules/services/misc/paperless.nix
+++ b/nixos/modules/services/misc/paperless.nix
@@ -83,7 +83,7 @@ let
   };
 in
 {
-  meta.maintainers = with maintainers; [ earvstedt Flakebi ];
+  meta.maintainers = with maintainers; [ erikarvstedt Flakebi ];
 
   imports = [
     (mkRenamedOptionModule [ "services" "paperless-ng" ] [ "services" "paperless" ])
diff --git a/nixos/modules/services/misc/radarr.nix b/nixos/modules/services/misc/radarr.nix
index 74444e24043f9..826d59da0af14 100644
--- a/nixos/modules/services/misc/radarr.nix
+++ b/nixos/modules/services/misc/radarr.nix
@@ -11,6 +11,14 @@ in
     services.radarr = {
       enable = mkEnableOption "Radarr";
 
+      package = mkOption {
+        description = "Radarr package to use";
+        default = pkgs.radarr;
+        defaultText = literalExpression "pkgs.radarr";
+        example = literalExpression "pkgs.radarr";
+        type = types.package;
+      };
+
       dataDir = mkOption {
         type = types.str;
         default = "/var/lib/radarr/.config/Radarr";
@@ -51,7 +59,7 @@ in
         Type = "simple";
         User = cfg.user;
         Group = cfg.group;
-        ExecStart = "${pkgs.radarr}/bin/Radarr -nobrowser -data='${cfg.dataDir}'";
+        ExecStart = "${cfg.package}/bin/Radarr -nobrowser -data='${cfg.dataDir}'";
         Restart = "on-failure";
       };
     };
diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix
index 7920e4b263457..9e8db04e62241 100644
--- a/nixos/modules/services/networking/prosody.nix
+++ b/nixos/modules/services/networking/prosody.nix
@@ -511,8 +511,13 @@ in
 
       dataDir = mkOption {
         type = types.path;
-        description = "Directory where Prosody stores its data";
         default = "/var/lib/prosody";
+        description = ''
+          The prosody home directory used to store all data. If left as the default value
+          this directory will automatically be created before the prosody server starts, otherwise
+          you are responsible for ensuring the directory exists with appropriate ownership
+          and permissions.
+        '';
       };
 
       disco_items = mkOption {
@@ -524,13 +529,29 @@ in
       user = mkOption {
         type = types.str;
         default = "prosody";
-        description = "User account under which prosody runs.";
+        description = ''
+          User account under which prosody runs.
+
+          <note><para>
+          If left as the default value this user will automatically be created
+          on system activation, otherwise you are responsible for
+          ensuring the user exists before the prosody service starts.
+          </para></note>
+        '';
       };
 
       group = mkOption {
         type = types.str;
         default = "prosody";
-        description = "Group account under which prosody runs.";
+        description = ''
+          Group account under which prosody runs.
+
+          <note><para>
+          If left as the default value this group will automatically be created
+          on system activation, otherwise you are responsible for
+          ensuring the group exists before the prosody service starts.
+          </para></note>
+        '';
       };
 
       allowRegistration = mkOption {
@@ -839,9 +860,8 @@ in
     users.users.prosody = mkIf (cfg.user == "prosody") {
       uid = config.ids.uids.prosody;
       description = "Prosody user";
-      createHome = true;
       inherit (cfg) group;
-      home = "${cfg.dataDir}";
+      home = cfg.dataDir;
     };
 
     users.groups.prosody = mkIf (cfg.group == "prosody") {
@@ -854,28 +874,33 @@ in
       wants = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
       restartTriggers = [ config.environment.etc."prosody/prosody.cfg.lua".source ];
-      serviceConfig = {
-        User = cfg.user;
-        Group = cfg.group;
-        Type = "forking";
-        RuntimeDirectory = [ "prosody" ];
-        PIDFile = "/run/prosody/prosody.pid";
-        ExecStart = "${cfg.package}/bin/prosodyctl start";
-        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-
-        MemoryDenyWriteExecute = true;
-        PrivateDevices = true;
-        PrivateMounts = true;
-        PrivateTmp = true;
-        ProtectControlGroups = true;
-        ProtectHome = true;
-        ProtectHostname = true;
-        ProtectKernelModules = true;
-        ProtectKernelTunables = true;
-        RestrictNamespaces = true;
-        RestrictRealtime = true;
-        RestrictSUIDSGID = true;
-      };
+      serviceConfig = mkMerge [
+        {
+          User = cfg.user;
+          Group = cfg.group;
+          Type = "forking";
+          RuntimeDirectory = [ "prosody" ];
+          PIDFile = "/run/prosody/prosody.pid";
+          ExecStart = "${cfg.package}/bin/prosodyctl start";
+          ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+
+          MemoryDenyWriteExecute = true;
+          PrivateDevices = true;
+          PrivateMounts = true;
+          PrivateTmp = true;
+          ProtectControlGroups = true;
+          ProtectHome = true;
+          ProtectHostname = true;
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          RestrictNamespaces = true;
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+        }
+        (mkIf (cfg.dataDir == "/var/lib/prosody") {
+          StateDirectory = "prosody";
+        })
+      ];
     };
 
   };
diff --git a/nixos/modules/services/networking/routedns.nix b/nixos/modules/services/networking/routedns.nix
new file mode 100644
index 0000000000000..e0f5eedd2c8e5
--- /dev/null
+++ b/nixos/modules/services/networking/routedns.nix
@@ -0,0 +1,84 @@
+{ config
+, lib
+, pkgs
+, ...
+}:
+
+with lib;
+
+let
+  cfg = config.services.routedns;
+  settingsFormat = pkgs.formats.toml { };
+in
+{
+  options.services.routedns = {
+    enable = mkEnableOption "RouteDNS - DNS stub resolver, proxy and router";
+
+    settings = mkOption {
+      type = settingsFormat.type;
+      example = literalExpression ''
+        {
+          resolvers.cloudflare-dot = {
+            address = "1.1.1.1:853";
+            protocol = "dot";
+          };
+          groups.cloudflare-cached = {
+            type = "cache";
+            resolvers = ["cloudflare-dot"];
+          };
+          listeners.local-udp = {
+            address = "127.0.0.1:53";
+            protocol = "udp";
+            resolver = "cloudflare-cached";
+          };
+          listeners.local-tcp = {
+            address = "127.0.0.1:53";
+            protocol = "tcp";
+            resolver = "cloudflare-cached";
+          };
+        }
+      '';
+      description = ''
+        Configuration for RouteDNS, see <link xlink:href="https://github.com/folbricht/routedns/blob/master/doc/configuration.md"/>
+        for more information.
+      '';
+    };
+
+    configFile = mkOption {
+      default = settingsFormat.generate "routedns.toml" cfg.settings;
+      defaultText = "A RouteDNS configuration file automatically generated by values from services.routedns.*";
+      type = types.path;
+      example = literalExpression ''"''${pkgs.routedns}/cmd/routedns/example-config/use-case-1.toml"'';
+      description = "Path to RouteDNS TOML configuration file.";
+    };
+
+    package = mkOption {
+      default = pkgs.routedns;
+      defaultText = literalExpression "pkgs.routedns";
+      type = types.package;
+      description = "RouteDNS package to use.";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.routedns = {
+      description = "RouteDNS - DNS stub resolver, proxy and router";
+      after = [ "network.target" ]; # in case a bootstrap resolver is used, this might fail a few times until the respective server is actually reachable
+      wantedBy = [ "multi-user.target" ];
+      wants = [ "network.target" ];
+      startLimitIntervalSec = 30;
+      startLimitBurst = 5;
+      serviceConfig = {
+        Restart = "on-failure";
+        RestartSec = "5s";
+        LimitNPROC = 512;
+        LimitNOFILE = 1048576;
+        DynamicUser = true;
+        AmbientCapabilities = "CAP_NET_BIND_SERVICE";
+        NoNewPrivileges = true;
+        ExecStart = "${getBin cfg.package}/bin/routedns -l 4 ${cfg.configFile}";
+      };
+    };
+  };
+  meta.maintainers = with maintainers; [ jsimonetti ];
+}
diff --git a/nixos/modules/services/web-apps/hedgedoc.nix b/nixos/modules/services/web-apps/hedgedoc.nix
index 0310c15a4d27e..22270609dbccb 100644
--- a/nixos/modules/services/web-apps/hedgedoc.nix
+++ b/nixos/modules/services/web-apps/hedgedoc.nix
@@ -1031,8 +1031,7 @@ in
       '';
       serviceConfig = {
         WorkingDirectory = cfg.workDir;
-        StateDirectory = [ (builtins.replaceStrings [ "/var/lib/"  ] [ "" ] cfg.workDir) ];
-        ReadWritePaths = [ cfg.configuration.uploadsPath ];
+        StateDirectory = [ cfg.workDir cfg.configuration.uploadsPath ];
         ExecStart = "${cfg.package}/bin/hedgedoc";
         EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ];
         Environment = [
diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix
index 9aa38ab25c9a3..c441a2a7764e2 100644
--- a/nixos/modules/services/web-apps/tt-rss.nix
+++ b/nixos/modules/services/web-apps/tt-rss.nix
@@ -534,6 +534,7 @@ let
     services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
       ${poolName} = {
         inherit (cfg) user;
+        phpPackage = pkgs.php80;
         settings = mapAttrs (name: mkDefault) {
           "listen.owner" = "nginx";
           "listen.group" = "nginx";
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 160d76597c889..5ccbaf77481b7 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -360,7 +360,7 @@ let
       ${optionalString (config.alias != null) "alias ${config.alias};"}
       ${optionalString (config.return != null) "return ${config.return};"}
       ${config.extraConfig}
-      ${optionalString (config.proxyPass != null && cfg.recommendedProxySettings) "include ${recommendedProxyConfig};"}
+      ${optionalString (config.proxyPass != null && config.recommendedProxySettings) "include ${recommendedProxyConfig};"}
       ${mkBasicAuth "sublocation" config}
     }
   '') (sortProperties (mapAttrsToList (k: v: v // { location = k; }) locations)));
@@ -423,7 +423,7 @@ in
         default = false;
         type = types.bool;
         description = "
-          Enable recommended proxy settings.
+          Whether to enable recommended proxy settings if a vhost does not specify the option manually.
         ";
       };
 
diff --git a/nixos/modules/services/web-servers/nginx/location-options.nix b/nixos/modules/services/web-servers/nginx/location-options.nix
index 6fd00b3869745..49dd8893015af 100644
--- a/nixos/modules/services/web-servers/nginx/location-options.nix
+++ b/nixos/modules/services/web-servers/nginx/location-options.nix
@@ -3,7 +3,7 @@
 # has additional options that affect the web server as a whole, like
 # the user/group to run under.)
 
-{ lib }:
+{ lib, config }:
 
 with lib;
 
@@ -128,5 +128,14 @@ with lib;
         a greater priority.
       '';
     };
+
+    recommendedProxySettings = mkOption {
+      type = types.bool;
+      default = config.services.nginx.recommendedProxySettings;
+      defaultText = literalExpression "config.services.nginx.recommendedProxySettings";
+      description = ''
+        Enable recommended proxy settings.
+      '';
+    };
   };
 }
diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix
index 2c77d6ee81622..a9929297a2480 100644
--- a/nixos/modules/services/web-servers/nginx/vhost-options.nix
+++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix
@@ -281,7 +281,7 @@ with lib;
 
     locations = mkOption {
       type = types.attrsOf (types.submodule (import ./location-options.nix {
-        inherit lib;
+        inherit lib config;
       }));
       default = {};
       example = literalExpression ''
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index 88b21e59aaa6b..3c2dac386f5db 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -36,6 +36,12 @@ in
       [ "services" "xserver" "desktopManager" "xfce" "extraSessionCommands" ]
       [ "services" "xserver" "displayManager" "sessionCommands" ])
     (mkRemovedOptionModule [ "services" "xserver" "desktopManager" "xfce" "screenLock" ] "")
+
+    # added 2022-06-26
+    # thunar has its own module
+    (mkRenamedOptionModule
+      [ "services" "xserver" "desktopManager" "xfce" "thunarPlugins" ]
+      [ "programs" "thunar" "plugins" ])
   ];
 
   options = {
@@ -46,15 +52,6 @@ in
         description = "Enable the Xfce desktop environment.";
       };
 
-      thunarPlugins = mkOption {
-        default = [];
-        type = types.listOf types.package;
-        example = literalExpression "[ pkgs.xfce.thunar-archive-plugin ]";
-        description = ''
-          A list of plugin that should be installed with Thunar.
-        '';
-      };
-
       noDesktop = mkOption {
         type = types.bool;
         default = false;
@@ -110,8 +107,6 @@ in
       xfce4-settings
       xfce4-taskmanager
       xfce4-terminal
-
-      (thunar.override { thunarPlugins = cfg.thunarPlugins; })
     ] # TODO: NetworkManager doesn't belong here
       ++ optional config.networking.networkmanager.enable networkmanagerapplet
       ++ optional config.powerManagement.enable xfce4-power-manager
@@ -130,6 +125,8 @@ in
         xfdesktop
       ] ++ optional cfg.enableScreensaver xfce4-screensaver;
 
+    programs.thunar.enable = true;
+
     environment.pathsToLink = [
       "/share/xfce4"
       "/lib/xfce4"
@@ -170,7 +167,6 @@ in
 
     # Systemd services
     systemd.packages = with pkgs.xfce; [
-      (thunar.override { thunarPlugins = cfg.thunarPlugins; })
       xfce4-notifyd
     ];
 
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index fa88ad524070c..e625fa7f2c284 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -458,6 +458,7 @@ in {
   proxy = handleTest ./proxy.nix {};
   prowlarr = handleTest ./prowlarr.nix {};
   pt2-clone = handleTest ./pt2-clone.nix {};
+  pykms = handleTest ./pykms.nix {};
   public-inbox = handleTest ./public-inbox.nix {};
   pulseaudio = discoverTests (import ./pulseaudio.nix);
   qboot = handleTestOn ["x86_64-linux" "i686-linux"] ./qboot.nix {};
@@ -472,7 +473,6 @@ in {
   restartByActivationScript = handleTest ./restart-by-activation-script.nix {};
   restic = handleTest ./restic.nix {};
   retroarch = handleTest ./retroarch.nix {};
-  riak = handleTest ./riak.nix {};
   robustirc-bridge = handleTest ./robustirc-bridge.nix {};
   roundcube = handleTest ./roundcube.nix {};
   rspamd = handleTest ./rspamd.nix {};
@@ -485,6 +485,7 @@ in {
   samba = handleTest ./samba.nix {};
   samba-wsdd = handleTest ./samba-wsdd.nix {};
   sanoid = handleTest ./sanoid.nix {};
+  schleuder = handleTest ./schleuder.nix {};
   sddm = handleTest ./sddm.nix {};
   seafile = handleTest ./seafile.nix {};
   searx = handleTest ./searx.nix {};
diff --git a/nixos/tests/containers-custom-pkgs.nix b/nixos/tests/containers-custom-pkgs.nix
index 9894e6643762e..e8740ac631345 100644
--- a/nixos/tests/containers-custom-pkgs.nix
+++ b/nixos/tests/containers-custom-pkgs.nix
@@ -9,7 +9,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: let
 in {
   name = "containers-custom-pkgs";
   meta = {
-    maintainers = with lib.maintainers; [ adisbladis earvstedt ];
+    maintainers = with lib.maintainers; [ adisbladis erikarvstedt ];
   };
 
   nodes.machine = { config, ... }: {
diff --git a/nixos/tests/matrix/appservice-irc.nix b/nixos/tests/matrix/appservice-irc.nix
index 7dd44da8305e0..78c53024ca6c4 100644
--- a/nixos/tests/matrix/appservice-irc.nix
+++ b/nixos/tests/matrix/appservice-irc.nix
@@ -193,6 +193,7 @@ import ../make-test-python.nix ({ pkgs, ... }:
 
     testScript = ''
       import pathlib
+      import os
 
       start_all()
 
@@ -206,7 +207,7 @@ import ../make-test-python.nix ({ pkgs, ... }:
       with subtest("copy the registration file"):
           appservice.copy_from_vm("/var/lib/matrix-appservice-irc/registration.yml")
           homeserver.copy_from_host(
-              pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml", "/"
+              str(pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml"), "/"
           )
           homeserver.succeed("chmod 444 /registration.yml")
 
diff --git a/nixos/tests/paperless.nix b/nixos/tests/paperless.nix
index 51fe7c2078514..12883cd62c60c 100644
--- a/nixos/tests/paperless.nix
+++ b/nixos/tests/paperless.nix
@@ -1,6 +1,6 @@
 import ./make-test-python.nix ({ lib, ... }: {
   name = "paperless";
-  meta.maintainers = with lib.maintainers; [ earvstedt Flakebi ];
+  meta.maintainers = with lib.maintainers; [ erikarvstedt Flakebi ];
 
   nodes.machine = { pkgs, ... }: {
     environment.systemPackages = with pkgs; [ imagemagick jq ];
diff --git a/nixos/tests/pykms.nix b/nixos/tests/pykms.nix
new file mode 100644
index 0000000000000..14d776a2f113e
--- /dev/null
+++ b/nixos/tests/pykms.nix
@@ -0,0 +1,14 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+  {
+    name = "pykms-test";
+    meta.maintainers = with pkgs.lib.maintainers; [ zopieux ];
+
+    nodes.machine = { config, lib, pkgs, ... }: {
+      services.pykms.enable = true;
+    };
+
+    testScript = ''
+      machine.wait_for_unit("pykms.service")
+      machine.succeed("${pkgs.pykms}/bin/client")
+    '';
+  })
diff --git a/nixos/tests/riak.nix b/nixos/tests/riak.nix
deleted file mode 100644
index e75d40fa25695..0000000000000
--- a/nixos/tests/riak.nix
+++ /dev/null
@@ -1,18 +0,0 @@
-import ./make-test-python.nix ({ lib, pkgs, ... }: {
-  name = "riak";
-  meta = with lib.maintainers; {
-    maintainers = [ Br1ght0ne ];
-  };
-
-  nodes.machine = {
-    services.riak.enable = true;
-    services.riak.package = pkgs.riak;
-  };
-
-  testScript = ''
-    machine.start()
-
-    machine.wait_for_unit("riak")
-    machine.wait_until_succeeds("riak ping 2>&1")
-  '';
-})
diff --git a/nixos/tests/schleuder.nix b/nixos/tests/schleuder.nix
new file mode 100644
index 0000000000000..a9e4cc325bc76
--- /dev/null
+++ b/nixos/tests/schleuder.nix
@@ -0,0 +1,128 @@
+let
+  certs = import ./common/acme/server/snakeoil-certs.nix;
+  domain = certs.domain;
+in
+import ./make-test-python.nix {
+  name = "schleuder";
+  nodes.machine = { pkgs, ... }: {
+    imports = [ ./common/user-account.nix ];
+    services.postfix = {
+      enable = true;
+      enableSubmission = true;
+      tlsTrustedAuthorities = "${certs.ca.cert}";
+      sslCert = "${certs.${domain}.cert}";
+      sslKey = "${certs.${domain}.key}";
+      inherit domain;
+      destination = [ domain ];
+      localRecipients = [ "root" "alice" "bob" ];
+    };
+    services.schleuder = {
+      enable = true;
+      # Don't do it like this in production! The point of this setting
+      # is to allow loading secrets from _outside_ the world-readable
+      # Nix store.
+      extraSettingsFile = pkgs.writeText "schleuder-api-keys.yml" ''
+        api:
+          valid_api_keys:
+            - fnord
+      '';
+      lists = [ "security@${domain}" ];
+      settings.api = {
+        tls_cert_file = "${certs.${domain}.cert}";
+        tls_key_file = "${certs.${domain}.key}";
+      };
+    };
+
+    environment.systemPackages = [
+      pkgs.gnupg
+      pkgs.msmtp
+      (pkgs.writeScriptBin "do-test" ''
+        #!${pkgs.runtimeShell}
+        set -exuo pipefail
+
+        # Generate a GPG key with no passphrase and export it
+        sudo -u alice gpg --passphrase-fd 0 --batch --yes --quick-generate-key 'alice@${domain}' rsa4096 sign,encr < <(echo)
+        sudo -u alice gpg --armor --export alice@${domain} > alice.asc
+        # Create a new mailing list with alice as the owner, and alice's key
+        schleuder-cli list new security@${domain} alice@${domain} alice.asc
+
+        # Send an email from a non-member of the list. Use --auto-from so we don't have to specify who it's from twice.
+        msmtp --auto-from security@${domain} --host=${domain} --port=25 --tls --tls-starttls <<EOF
+          Subject: really big security issue!!
+          From: root@${domain}
+
+          I found a big security problem!
+        EOF
+
+        # Wait for delivery
+        (set +o pipefail; journalctl -f -n 1000 -u postfix | grep -m 1 'delivered to maildir')
+
+        # There should be exactly one email
+        mail=(/var/spool/mail/alice/new/*)
+        [[ "''${#mail[@]}" = 1 ]]
+
+        # Find the fingerprint of the mailing list key
+        read list_key_fp address < <(schleuder-cli keys list security@${domain} | grep security@)
+        schleuder-cli keys export security@${domain} $list_key_fp > list.asc
+
+        # Import the key into alice's keyring, so we can verify it as well as decrypting
+        sudo -u alice gpg --import <list.asc
+        # And perform the decryption.
+        sudo -u alice gpg -d $mail >decrypted
+        # And check that the text matches.
+        grep "big security problem" decrypted
+      '')
+
+      # For debugging:
+      # pkgs.vim pkgs.openssl pkgs.sqliteinteractive
+    ];
+
+    security.pki.certificateFiles = [ certs.ca.cert ];
+
+    # Since we don't have internet here, use dnsmasq to provide MX records from /etc/hosts
+    services.dnsmasq = {
+      enable = true;
+      extraConfig = ''
+        selfmx
+      '';
+    };
+
+    networking.extraHosts = ''
+      127.0.0.1 ${domain}
+    '';
+
+    # schleuder-cli's config is not quite optimal in several ways:
+    # - A fingerprint _must_ be pinned, it doesn't even have an option
+    #   to trust the PKI
+    # - It compares certificate fingerprints rather than key
+    #   fingerprints, so renewals break the pin (though that's not
+    #   relevant for this test)
+    # - It compares them as strings, which means we need to match the
+    #   expected format exactly. This means removing the :s and
+    #   lowercasing it.
+    # Refs:
+    # https://0xacab.org/schleuder/schleuder-cli/-/issues/16
+    # https://0xacab.org/schleuder/schleuder-cli/-/blob/f8895b9f47083d8c7b99a2797c93f170f3c6a3c0/lib/schleuder-cli/helper.rb#L230-238
+    systemd.tmpfiles.rules = let cliconfig = pkgs.runCommand "schleuder-cli.yml"
+      {
+        nativeBuildInputs = [ pkgs.jq pkgs.openssl ];
+      } ''
+      fp=$(openssl x509 -in ${certs.${domain}.cert} -noout -fingerprint -sha256 | cut -d = -f 2 | tr -d : | tr 'A-Z' 'a-z')
+      cat > $out <<EOF
+      host: localhost
+      port: 4443
+      tls_fingerprint: "$fp"
+      api_key: fnord
+      EOF
+    ''; in
+      [
+        "L+ /root/.schleuder-cli/schleuder-cli.yml - - - - ${cliconfig}"
+      ];
+  };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_until_succeeds("nc -z localhost 4443")
+    machine.succeed("do-test")
+  '';
+}
diff --git a/nixos/tests/systemd-networkd-vrf.nix b/nixos/tests/systemd-networkd-vrf.nix
index 3839a49375db2..3c18f788e927d 100644
--- a/nixos/tests/systemd-networkd-vrf.nix
+++ b/nixos/tests/systemd-networkd-vrf.nix
@@ -138,18 +138,18 @@ in {
   };
 
   testScript = ''
-    def compare_tables(expected, actual):
-        assert (
-            expected == actual
-        ), """
-        Routing tables don't match!
-        Expected:
-          {}
-        Actual:
-          {}
-        """.format(
-            expected, actual
-        )
+    import json
+
+    def compare(raw_json, to_compare):
+        data = json.loads(raw_json)
+        assert len(raw_json) >= len(to_compare)
+        for i, row in enumerate(to_compare):
+            actual = data[i]
+            assert len(row.keys()) > 0
+            for key, value in row.items():
+                assert value == actual[key], f"""
+                  In entry {i}, value {key}: got: {actual[key]}, expected {value}
+                """
 
 
     start_all()
@@ -178,14 +178,28 @@ in {
     # Check that networkd properly configures the main routing table
     # and the routing tables for the VRF.
     with subtest("check vrf routing tables"):
-        compare_tables(
-            client_ipv4_table, client.succeed("ip -4 route list | head -n2").strip()
+        compare(
+            client.succeed("ip --json -4 route list"),
+            [
+                {"dst": "192.168.1.2", "dev": "vrf1", "metric": 100},
+                {"dst": "192.168.2.3", "dev": "vrf2", "metric": 100}
+            ]
         )
-        compare_tables(
-            vrf1_table, client.succeed("ip -4 route list table 23 | head -n4").strip()
+        compare(
+            client.succeed("ip --json -4 route list table 23"),
+            [
+                {"dst": "192.168.1.0/24", "dev": "eth1", "prefsrc": "192.168.1.1"},
+                {"type": "local", "dst": "192.168.1.1", "dev": "eth1", "prefsrc": "192.168.1.1"},
+                {"type": "broadcast", "dev": "eth1", "prefsrc": "192.168.1.1", "dst": "192.168.1.255"}
+            ]
         )
-        compare_tables(
-            vrf2_table, client.succeed("ip -4 route list table 42 | head -n4").strip()
+        compare(
+            client.succeed("ip --json -4 route list table 42"),
+            [
+                {"dst": "192.168.2.0/24", "dev": "eth2", "prefsrc": "192.168.2.1"},
+                {"type": "local", "dst": "192.168.2.1", "dev": "eth2", "prefsrc": "192.168.2.1"},
+                {"type": "broadcast", "dev": "eth2", "prefsrc": "192.168.2.1", "dst": "192.168.2.255"}
+            ]
         )
 
     # Ensure that other nodes are reachable via ICMP through the VRF.
diff --git a/nixos/tests/traefik.nix b/nixos/tests/traefik.nix
index 1d6c0a479ef62..989ec390c0603 100644
--- a/nixos/tests/traefik.nix
+++ b/nixos/tests/traefik.nix
@@ -11,14 +11,20 @@ import ./make-test-python.nix ({ pkgs, ... }: {
       environment.systemPackages = [ pkgs.curl ];
     };
     traefik = { config, pkgs, ... }: {
-      virtualisation.oci-containers.containers.nginx = {
-        extraOptions = [
-          "-l" "traefik.enable=true"
-          "-l" "traefik.http.routers.nginx.entrypoints=web"
-          "-l" "traefik.http.routers.nginx.rule=Host(`nginx.traefik.test`)"
-        ];
-        image = "nginx-container";
-        imageFile = pkgs.dockerTools.examples.nginx;
+      virtualisation.oci-containers = {
+        backend = "docker";
+        containers.nginx = {
+          extraOptions = [
+            "-l"
+            "traefik.enable=true"
+            "-l"
+            "traefik.http.routers.nginx.entrypoints=web"
+            "-l"
+            "traefik.http.routers.nginx.rule=Host(`nginx.traefik.test`)"
+          ];
+          image = "nginx-container";
+          imageFile = pkgs.dockerTools.examples.nginx;
+        };
       };
 
       networking.firewall.allowedTCPPorts = [ 80 ];
diff --git a/nixos/tests/vengi-tools.nix b/nixos/tests/vengi-tools.nix
index 8b80a13384e5a..5bc8d72c77237 100644
--- a/nixos/tests/vengi-tools.nix
+++ b/nixos/tests/vengi-tools.nix
@@ -23,7 +23,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
       # OCR on voxedit's window is very expensive, so we avoid wasting a try
       # by letting the window load fully first
       machine.sleep(15)
-      machine.wait_for_text("Palette")
+      machine.wait_for_text("Solid")
       machine.screenshot("screen")
     '';
 })