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/development/option-types.section.md11
-rw-r--r--nixos/doc/manual/from_md/development/option-types.section.xml19
-rw-r--r--nixos/doc/manual/from_md/release-notes/rl-2111.section.xml11
-rw-r--r--nixos/doc/manual/from_md/release-notes/rl-2205.section.xml37
-rw-r--r--nixos/doc/manual/release-notes/rl-2111.section.md3
-rw-r--r--nixos/doc/manual/release-notes/rl-2205.section.md11
-rw-r--r--nixos/modules/misc/ids.nix2
-rw-r--r--nixos/modules/misc/wordlist.nix59
-rw-r--r--nixos/modules/module-list.nix3
-rw-r--r--nixos/modules/programs/k40-whisperer.nix40
-rw-r--r--nixos/modules/rename.nix3
-rw-r--r--nixos/modules/services/databases/virtuoso.nix99
-rw-r--r--nixos/modules/services/desktops/pipewire/pipewire-media-session.nix5
-rw-r--r--nixos/modules/services/desktops/pipewire/wireplumber.nix11
-rw-r--r--nixos/modules/services/logging/logrotate.nix35
-rw-r--r--nixos/modules/services/misc/plex.nix13
-rw-r--r--nixos/modules/services/security/vaultwarden/default.nix4
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix12
-rw-r--r--nixos/modules/system/boot/systemd.nix17
-rw-r--r--nixos/modules/virtualisation/openstack-metadata-fetcher.nix3
-rw-r--r--nixos/tests/all-tests.nix2
-rw-r--r--nixos/tests/logrotate.nix35
-rw-r--r--nixos/tests/nginx-modsecurity.nix39
23 files changed, 335 insertions, 139 deletions
diff --git a/nixos/doc/manual/development/option-types.section.md b/nixos/doc/manual/development/option-types.section.md
index 56ffa8e9d79c4..78ace62e8f173 100644
--- a/nixos/doc/manual/development/option-types.section.md
+++ b/nixos/doc/manual/development/option-types.section.md
@@ -63,6 +63,17 @@ merging is handled.
     ```
     :::
 
+`types.raw`
+
+:   A type which doesn't do any checking, merging or nested evaluation. It
+    accepts a single arbitrary value that is not recursed into, making it
+    useful for values coming from outside the module system, such as package
+    sets or arbitrary data. Options of this type are still evaluated according
+    to priorities and conditionals, so `mkForce`, `mkIf` and co. still work on
+    the option value itself, but not for any value nested within it. This type
+    should only be used when checking, merging and nested evaluation are not
+    desirable.
+
 `types.attrs`
 
 :   A free-form attribute set.
diff --git a/nixos/doc/manual/from_md/development/option-types.section.xml b/nixos/doc/manual/from_md/development/option-types.section.xml
index 76ffb6f837c35..90ef05a24e777 100644
--- a/nixos/doc/manual/from_md/development/option-types.section.xml
+++ b/nixos/doc/manual/from_md/development/option-types.section.xml
@@ -94,6 +94,25 @@
       </varlistentry>
       <varlistentry>
         <term>
+          <literal>types.raw</literal>
+        </term>
+        <listitem>
+          <para>
+            A type which doesn’t do any checking, merging or nested
+            evaluation. It accepts a single arbitrary value that is not
+            recursed into, making it useful for values coming from
+            outside the module system, such as package sets or arbitrary
+            data. Options of this type are still evaluated according to
+            priorities and conditionals, so <literal>mkForce</literal>,
+            <literal>mkIf</literal> and co. still work on the option
+            value itself, but not for any value nested within it. This
+            type should only be used when checking, merging and nested
+            evaluation are not desirable.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>
           <literal>types.attrs</literal>
         </term>
         <listitem>
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
index fc253a7a8b029..a11baa91dea6d 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
@@ -1447,6 +1447,17 @@ Superuser created successfully.
           knob.
         </para>
       </listitem>
+      <listitem>
+        <para>
+          <literal>/usr</literal> will always be included in the initial
+          ramdisk. See the
+          <literal>fileSystems.&lt;name&gt;.neededForBoot</literal>
+          option. If any files exist under <literal>/usr</literal>
+          (which is not typical for NixOS), they will be included in the
+          initial ramdisk, increasing its size to a possibly problematic
+          extent.
+        </para>
+      </listitem>
     </itemizedlist>
   </section>
   <section xml:id="sec-release-21.11-notable-changes">
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 4acdcd7d60f9b..645b4ac55741b 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
@@ -147,6 +147,15 @@
       </listitem>
       <listitem>
         <para>
+          <link xlink:href="https://www.scorchworks.com/K40whisperer/k40whisperer.html">K40-Whisperer</link>,
+          a program to control cheap Chinese laser cutters. Available as
+          <link xlink:href="options.html#opt-programs.k4-whisperer.enable">programs.k40-whisperer.enable</link>.
+          Users must add themselves to the <literal>k40</literal> group
+          to be able to access the device.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           <link xlink:href="https://github.com/mgumz/mtr-exporter">mtr-exporter</link>,
           a Prometheus exporter for mtr metrics. Available as
           <link xlink:href="options.html#opt-services.mtr-exporter.enable">services.mtr-exporter</link>.
@@ -716,6 +725,19 @@
           <link xlink:href="https://github.com/olimorris/onedarkpro.nvim">olimorris/onedarkpro.nvim</link>).
         </para>
       </listitem>
+      <listitem>
+        <para>
+          <literal>services.pipewire.enable</literal> will default to
+          enabling the WirePlumber session manager instead of
+          pipewire-media-session. pipewire-media-session is deprecated
+          by upstream and not recommended, but can still be manually
+          enabled by setting
+          <literal>services.pipewire.media-session.enable</literal> to
+          <literal>true</literal> and
+          <literal>services.pipewire.wireplumber.enable</literal> to
+          <literal>false</literal>.
+        </para>
+      </listitem>
     </itemizedlist>
   </section>
   <section xml:id="sec-release-22.05-notable-changes">
@@ -934,6 +956,14 @@
       </listitem>
       <listitem>
         <para>
+          It is now possible to specify wordlists to include as handy to
+          access environment variables using the
+          <literal>config.environment.wordlist</literal> configuration
+          options.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           The <literal>services.mbpfan</literal> module was converted to
           a
           <link xlink:href="https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md">RFC
@@ -972,6 +1002,13 @@
       </listitem>
       <listitem>
         <para>
+          <literal>services.logrotate.enable</literal> now defaults to
+          true if any rotate path has been defined, and some paths have
+          been added by default.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           The <literal>zrepl</literal> package has been updated from
           0.4.0 to 0.5:
         </para>
diff --git a/nixos/doc/manual/release-notes/rl-2111.section.md b/nixos/doc/manual/release-notes/rl-2111.section.md
index 2f667a7eb5651..f3644c32832b6 100644
--- a/nixos/doc/manual/release-notes/rl-2111.section.md
+++ b/nixos/doc/manual/release-notes/rl-2111.section.md
@@ -427,6 +427,9 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - The Linux kernel for security reasons now restricts access to BPF syscalls via `BPF_UNPRIV_DEFAULT_OFF=y`. Unprivileged access can be reenabled via the `kernel.unprivileged_bpf_disabled` sysctl knob.
 
+- `/usr` will always be included in the initial ramdisk. See the `fileSystems.<name>.neededForBoot` option.
+  If any files exist under `/usr` (which is not typical for NixOS), they will be included in the initial ramdisk, increasing its size to a possibly problematic extent.
+
 ## Other Notable Changes {#sec-release-21.11-notable-changes}
 
 
diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md
index e81bdd884d068..542fb24abbdc7 100644
--- a/nixos/doc/manual/release-notes/rl-2205.section.md
+++ b/nixos/doc/manual/release-notes/rl-2205.section.md
@@ -45,6 +45,8 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - [maddy](https://maddy.email), a composable all-in-one mail server. Available as [services.maddy](options.html#opt-services.maddy.enable).
 
+- [K40-Whisperer](https://www.scorchworks.com/K40whisperer/k40whisperer.html), a program to control cheap Chinese laser cutters. Available as [programs.k40-whisperer.enable](options.html#opt-programs.k4-whisperer.enable). Users must add themselves to the `k40` group to be able to access the device.
+
 - [mtr-exporter](https://github.com/mgumz/mtr-exporter), a Prometheus exporter for mtr metrics. Available as [services.mtr-exporter](options.html#opt-services.mtr-exporter.enable).
 
 - [tetrd](https://tetrd.app), share your internet connection from your device to your PC and vice versa through a USB cable. Available at [services.tetrd](#opt-services.tetrd.enable).
@@ -223,6 +225,10 @@ In addition to numerous new and upgraded packages, this release has the followin
 - `pkgs.vimPlugins.onedark-nvim` now refers to [navarasu/onedark.nvim](https://github.com/navarasu/onedark.nvim)
   (formerly refers to [olimorris/onedarkpro.nvim](https://github.com/olimorris/onedarkpro.nvim)).
 
+- `services.pipewire.enable` will default to enabling the WirePlumber session manager instead of pipewire-media-session.
+  pipewire-media-session is deprecated by upstream and not recommended, but can still be manually enabled by setting
+  `services.pipewire.media-session.enable` to `true` and `services.pipewire.wireplumber.enable` to `false`.
+
 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
 
 ## Other Notable Changes {#sec-release-22.05-notable-changes}
@@ -311,6 +317,8 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - The `firmwareLinuxNonfree` package has been renamed to `linux-firmware`.
 
+- It is now possible to specify wordlists to include as handy to access environment variables using the `config.environment.wordlist` configuration options.
+
 - The `services.mbpfan` module was converted to a [RFC 0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md) configuration.
 
 - The default value for `programs.spacefm.settings.graphical_su` got unset. It previously pointed to `gksu` which has been removed.
@@ -323,6 +331,9 @@ In addition to numerous new and upgraded packages, this release has the followin
 - `services.mattermost.plugins` has been added to allow the declarative installation of Mattermost plugins.
   Plugins are automatically repackaged using autoPatchelf.
 
+- `services.logrotate.enable` now defaults to true if any rotate path has
+  been defined, and some paths have been added by default.
+
 - The `zrepl` package has been updated from 0.4.0 to 0.5:
 
   - The RPC protocol version was bumped; all zrepl daemons in a setup must be updated and restarted before replication can resume.
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 9d620084308b2..1b4105c676d95 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -82,7 +82,7 @@ in
       git = 41;
       #fourstore = 42; # dropped in 20.03
       #fourstorehttp = 43; # dropped in 20.03
-      virtuoso = 44;
+      #virtuoso = 44;  dropped module
       #rtkit = 45; # dynamically allocated 2021-09-03
       dovecot2 = 46;
       dovenull2 = 47;
diff --git a/nixos/modules/misc/wordlist.nix b/nixos/modules/misc/wordlist.nix
new file mode 100644
index 0000000000000..988b522d74314
--- /dev/null
+++ b/nixos/modules/misc/wordlist.nix
@@ -0,0 +1,59 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  concatAndSort = name: files: pkgs.runCommand name {} ''
+    awk 1 ${lib.escapeShellArgs files} | sed '{ /^\s*$/d; s/^\s\+//; s/\s\+$// }' | sort | uniq > $out
+  '';
+in
+{
+  options = {
+    environment.wordlist = {
+      enable = mkEnableOption "environment variables for lists of words";
+
+      lists = mkOption {
+        type = types.attrsOf (types.nonEmptyListOf types.path);
+
+        default = {
+          WORDLIST = [ "${pkgs.scowl}/share/dict/words.txt" ];
+        };
+
+        defaultText = literalExpression ''
+          {
+            WORDLIST = [ "''${pkgs.scowl}/share/dict/words.txt" ];
+          }
+        '';
+
+        description = ''
+          A set with the key names being the environment variable you'd like to
+          set and the values being a list of paths to text documents containing
+          lists of words. The various files will be merged, sorted, duplicates
+          removed, and extraneous spacing removed.
+
+          If you have a handful of words that you want to add to an already
+          existing wordlist, you may find `builtins.toFile` useful for this
+          task.
+        '';
+
+        example = literalExpression ''
+          {
+            WORDLIST = [ "''${pkgs.scowl}/share/dict/words.txt" ];
+            AUGMENTED_WORDLIST = [
+              "''${pkgs.scowl}/share/dict/words.txt"
+              "''${pkgs.scowl}/share/dict/words.variants.txt"
+              (builtins.toFile "extra-words" '''
+                desynchonization
+                oobleck''')
+            ];
+          }
+        '';
+      };
+    };
+  };
+
+  config = mkIf config.environment.wordlist.enable {
+    environment.variables =
+      lib.mapAttrs
+        (name: value: "${concatAndSort "wordlist-${name}" value}")
+        config.environment.wordlist.lists;
+  };
+}
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index ca82ddfb58638..28974c17ec712 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -115,6 +115,7 @@
   ./misc/nixpkgs.nix
   ./misc/passthru.nix
   ./misc/version.nix
+  ./misc/wordlist.nix
   ./misc/nixops-autoluks.nix
   ./programs/adb.nix
   ./programs/appgate-sdp.nix
@@ -166,6 +167,7 @@
   ./programs/iftop.nix
   ./programs/iotop.nix
   ./programs/java.nix
+  ./programs/k40-whisperer.nix
   ./programs/kdeconnect.nix
   ./programs/kbdlight.nix
   ./programs/less.nix
@@ -349,7 +351,6 @@
   ./services/databases/redis.nix
   ./services/databases/riak.nix
   ./services/databases/victoriametrics.nix
-  ./services/databases/virtuoso.nix
   ./services/desktops/accountsservice.nix
   ./services/desktops/bamf.nix
   ./services/desktops/blueman.nix
diff --git a/nixos/modules/programs/k40-whisperer.nix b/nixos/modules/programs/k40-whisperer.nix
new file mode 100644
index 0000000000000..3163e45f57e45
--- /dev/null
+++ b/nixos/modules/programs/k40-whisperer.nix
@@ -0,0 +1,40 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.k40-whisperer;
+  pkg = cfg.package.override {
+    udevGroup = cfg.group;
+  };
+in
+{
+  options.programs.k40-whisperer = {
+    enable = mkEnableOption "K40-Whisperer";
+
+    group = mkOption {
+      type = types.str;
+      description = ''
+        Group assigned to the device when connected.
+      '';
+      default = "k40";
+    };
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.k40-whisperer;
+      defaultText = literalExpression "pkgs.k40-whisperer";
+      example = literalExpression "pkgs.k40-whisperer";
+      description = ''
+        K40 Whisperer package to use.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.groups.${cfg.group} = {};
+
+    environment.systemPackages = [ pkg ];
+    services.udev.packages = [ pkg ];
+  };
+}
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index c271d504b7716..d72ff1c6f170c 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -87,10 +87,9 @@ with lib;
     (mkRemovedOptionModule [ "services" "racoon" ] ''
       The racoon module has been removed, because the software project was abandoned upstream.
     '')
-
     (mkRemovedOptionModule [ "services" "shellinabox" ] "The corresponding package was removed from nixpkgs.")
-
     (mkRemovedOptionModule [ "services" "gogoclient" ] "The corresponding package was removed from nixpkgs.")
+    (mkRemovedOptionModule [ "services" "virtuoso" ] "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/databases/virtuoso.nix b/nixos/modules/services/databases/virtuoso.nix
deleted file mode 100644
index 8b01622ecb039..0000000000000
--- a/nixos/modules/services/databases/virtuoso.nix
+++ /dev/null
@@ -1,99 +0,0 @@
-{ config, lib, pkgs, ... }:
-let
-  cfg = config.services.virtuoso;
-  virtuosoUser = "virtuoso";
-  stateDir = "/var/lib/virtuoso";
-in
-with lib;
-{
-
-  ###### interface
-
-  options = {
-
-    services.virtuoso = {
-
-      enable = mkEnableOption "Virtuoso Opensource database server";
-
-      config = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Extra options to put into Virtuoso configuration file.";
-      };
-
-      parameters = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Extra options to put into [Parameters] section of Virtuoso configuration file.";
-      };
-
-      listenAddress = mkOption {
-        type = types.str;
-        default = "1111";
-        example = "myserver:1323";
-        description = "ip:port or port to listen on.";
-      };
-
-      httpListenAddress = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        example = "myserver:8080";
-        description = "ip:port or port for Virtuoso HTTP server to listen on.";
-      };
-
-      dirsAllowed = mkOption {
-        type = types.nullOr types.str; # XXX Maybe use a list in the future?
-        default = null;
-        example = "/www, /home/";
-        description = "A list of directories Virtuoso is allowed to access";
-      };
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-
-    users.users.${virtuosoUser} =
-      { uid = config.ids.uids.virtuoso;
-        description = "virtuoso user";
-        home = stateDir;
-      };
-
-    systemd.services.virtuoso = {
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
-
-      preStart = ''
-        mkdir -p ${stateDir}
-        chown ${virtuosoUser} ${stateDir}
-      '';
-
-      script = ''
-        cd ${stateDir}
-        ${pkgs.virtuoso}/bin/virtuoso-t +foreground +configfile ${pkgs.writeText "virtuoso.ini" cfg.config}
-      '';
-    };
-
-    services.virtuoso.config = ''
-      [Database]
-      DatabaseFile=${stateDir}/x-virtuoso.db
-      TransactionFile=${stateDir}/x-virtuoso.trx
-      ErrorLogFile=${stateDir}/x-virtuoso.log
-      xa_persistent_file=${stateDir}/x-virtuoso.pxa
-
-      [Parameters]
-      ServerPort=${cfg.listenAddress}
-      RunAs=${virtuosoUser}
-      ${optionalString (cfg.dirsAllowed != null) "DirsAllowed=${cfg.dirsAllowed}"}
-      ${cfg.parameters}
-
-      [HTTPServer]
-      ${optionalString (cfg.httpListenAddress != null) "ServerPort=${cfg.httpListenAddress}"}
-    '';
-
-  };
-
-}
diff --git a/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix b/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix
index f7a03a4a3eaf1..109c91134b994 100644
--- a/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix
+++ b/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix
@@ -38,9 +38,8 @@ in {
     services.pipewire.media-session = {
       enable = mkOption {
         type = types.bool;
-        default = config.services.pipewire.enable;
-        defaultText = literalExpression "config.services.pipewire.enable";
-        description = "Example pipewire session manager";
+        default = false;
+        description = "Whether to enable the deprecated example Pipewire session manager";
       };
 
       package = mkOption {
diff --git a/nixos/modules/services/desktops/pipewire/wireplumber.nix b/nixos/modules/services/desktops/pipewire/wireplumber.nix
index ad96dc1f9745e..52ec17b95db4d 100644
--- a/nixos/modules/services/desktops/pipewire/wireplumber.nix
+++ b/nixos/modules/services/desktops/pipewire/wireplumber.nix
@@ -8,15 +8,18 @@ in
 
   options = {
     services.pipewire.wireplumber = {
-      enable = lib.mkEnableOption "A modular session / policy manager for PipeWire";
+      enable = lib.mkOption {
+        type = lib.types.bool;
+        default = config.services.pipewire.enable;
+        defaultText = lib.literalExpression "config.services.pipewire.enable";
+        description = "Whether to enable Wireplumber, a modular session / policy manager for PipeWire";
+      };
 
       package = lib.mkOption {
         type = lib.types.package;
         default = pkgs.wireplumber;
         defaultText = lib.literalExpression "pkgs.wireplumber";
-        description = ''
-          The wireplumber derivation to use.
-        '';
+        description = "The wireplumber derivation to use.";
       };
     };
   };
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
index 8cef4e8c083a9..77e4fc3959817 100644
--- a/nixos/modules/services/logging/logrotate.nix
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -4,7 +4,6 @@ with lib;
 
 let
   cfg = config.services.logrotate;
-  inherit (config.users) groups;
 
   pathOpts = { name, ... }:  {
     options = {
@@ -85,10 +84,6 @@ let
     };
 
     config.name = name;
-    config.extraConfig = ''
-      missingok
-      notifempty
-    '';
   };
 
   mkConf = pathOpts: ''
@@ -102,7 +97,11 @@ let
   '';
 
   paths = sortProperties (attrValues (filterAttrs (_: pathOpts: pathOpts.enable) cfg.paths));
-  configFile = pkgs.writeText "logrotate.conf" (concatStringsSep "\n" ((map mkConf paths) ++ [ cfg.extraConfig ]));
+  configFile = pkgs.writeText "logrotate.conf" (
+    concatStringsSep "\n" (
+      [ "missingok" "notifempty" cfg.extraConfig ] ++ (map mkConf paths)
+    )
+  );
 
 in
 {
@@ -112,7 +111,10 @@ in
 
   options = {
     services.logrotate = {
-      enable = mkEnableOption "the logrotate systemd service";
+      enable = mkEnableOption "the logrotate systemd service" // {
+        default = foldr (n: a: a || n.enable) false (attrValues cfg.paths);
+        defaultText = literalExpression "cfg.paths != {}";
+      };
 
       paths = mkOption {
         type = with types; attrsOf (submodule pathOpts);
@@ -163,25 +165,6 @@ in
       }
     ) cfg.paths;
 
-    services.logrotate = {
-      paths = {
-        "/var/log/btmp" = {
-          frequency = mkDefault "monthly";
-          keep = mkDefault 1;
-          extraConfig = ''
-            create 0660 root ${groups.utmp.name}
-          '';
-        };
-        "/var/log/wtmp" = {
-          frequency = mkDefault "monthly";
-          keep = mkDefault 1;
-          extraConfig = ''
-            create 0664 root ${groups.utmp.name}
-          '';
-        };
-      };
-    };
-
     systemd.services.logrotate = {
       description = "Logrotate Service";
       wantedBy = [ "multi-user.target" ];
diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix
index 7000d45975fc6..1cd8da768f48d 100644
--- a/nixos/modules/services/misc/plex.nix
+++ b/nixos/modules/services/misc/plex.nix
@@ -55,6 +55,19 @@ in
           symlinks in Plex's plugin directory will be cleared and this module
           will symlink all of the paths specified here to that directory.
         '';
+        example = literalExpression ''
+          [
+            (builtins.path {
+              name = "Audnexus.bundle";
+              path = pkgs.fetchFromGitHub {
+                owner = "djdembeck";
+                repo = "Audnexus.bundle";
+                rev = "v0.2.8";
+                sha256 = "sha256-IWOSz3vYL7zhdHan468xNc6C/eQ2C2BukQlaJNLXh7E=";
+              };
+            })
+          ]
+        '';
       };
 
       extraScanners = mkOption {
diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix
index fd459f70ccde0..8277f493639c2 100644
--- a/nixos/modules/services/security/vaultwarden/default.nix
+++ b/nixos/modules/services/security/vaultwarden/default.nix
@@ -151,7 +151,7 @@ in {
     };
 
     systemd.services.backup-vaultwarden = mkIf (cfg.backupDir != null) {
-      aliases = [ "backup-bitwarden_rs" ];
+      aliases = [ "backup-bitwarden_rs.service" ];
       description = "Backup vaultwarden";
       environment = {
         DATA_FOLDER = "/var/lib/bitwarden_rs";
@@ -169,7 +169,7 @@ in {
     };
 
     systemd.timers.backup-vaultwarden = mkIf (cfg.backupDir != null) {
-      aliases = [ "backup-bitwarden_rs" ];
+      aliases = [ "backup-bitwarden_rs.service" ];
       description = "Backup vaultwarden on time";
       timerConfig = {
         OnCalendar = mkDefault "23:00";
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 6876dbf39d84b..7daf0f158b35d 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -988,5 +988,17 @@ in
       nginx.gid = config.ids.gids.nginx;
     };
 
+    services.logrotate.paths.nginx = mapAttrs (_: mkDefault) {
+      path = "/var/log/nginx/*.log";
+      frequency = "weekly";
+      keep = 26;
+      extraConfig = ''
+        compress
+        delaycompress
+        postrotate
+          [ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`
+        endscript
+      '';
+    };
   };
 }
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 1f2dd618698c6..441faa03af00b 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -1217,6 +1217,23 @@ in
     boot.kernel.sysctl."kernel.pid_max" = mkIf pkgs.stdenv.is64bit (lib.mkDefault 4194304);
 
     boot.kernelParams = optional (!cfg.enableUnifiedCgroupHierarchy) "systemd.unified_cgroup_hierarchy=0";
+
+    services.logrotate.paths = {
+      "/var/log/btmp" = mapAttrs (_: mkDefault) {
+        frequency = "monthly";
+        keep = 1;
+        extraConfig = ''
+          create 0660 root ${config.users.groups.utmp.name}
+        '';
+      };
+      "/var/log/wtmp" = mapAttrs (_: mkDefault) {
+        frequency = "monthly";
+        keep = 1;
+        extraConfig = ''
+          create 0664 root ${config.users.groups.utmp.name}
+        '';
+      };
+    };
   };
 
   # FIXME: Remove these eventually.
diff --git a/nixos/modules/virtualisation/openstack-metadata-fetcher.nix b/nixos/modules/virtualisation/openstack-metadata-fetcher.nix
index 133cd4c0e9f91..25104bb476674 100644
--- a/nixos/modules/virtualisation/openstack-metadata-fetcher.nix
+++ b/nixos/modules/virtualisation/openstack-metadata-fetcher.nix
@@ -15,7 +15,8 @@
   }
 
   wget_imds -O "$metaDir/ami-manifest-path" http://169.254.169.254/1.0/meta-data/ami-manifest-path
-  (umask 077 && wget_imds -O "$metaDir/user-data" http://169.254.169.254/1.0/user-data)
+  # When no user-data is provided, the OpenStack metadata server doesn't expose the user-data route.
+  (umask 077 && wget_imds -O "$metaDir/user-data" http://169.254.169.254/1.0/user-data || rm -f "$metaDir/user-data")
   wget_imds -O "$metaDir/hostname" http://169.254.169.254/1.0/meta-data/hostname
   wget_imds -O "$metaDir/public-keys-0-openssh-key" http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key
 ''
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 515a3c7208ce4..c9c39e7925143 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -270,6 +270,7 @@ in
   litestream = handleTest ./litestream.nix {};
   locate = handleTest ./locate.nix {};
   login = handleTest ./login.nix {};
+  logrotate = handleTest ./logrotate.nix {};
   loki = handleTest ./loki.nix {};
   lxd = handleTest ./lxd.nix {};
   lxd-image = handleTest ./lxd-image.nix {};
@@ -347,6 +348,7 @@ in
   nginx = handleTest ./nginx.nix {};
   nginx-auth = handleTest ./nginx-auth.nix {};
   nginx-etag = handleTest ./nginx-etag.nix {};
+  nginx-modsecurity = handleTest ./nginx-modsecurity.nix {};
   nginx-pubhtml = handleTest ./nginx-pubhtml.nix {};
   nginx-sandbox = handleTestOn ["x86_64-linux"] ./nginx-sandbox.nix {};
   nginx-sso = handleTest ./nginx-sso.nix {};
diff --git a/nixos/tests/logrotate.nix b/nixos/tests/logrotate.nix
new file mode 100644
index 0000000000000..0f6b59f071d45
--- /dev/null
+++ b/nixos/tests/logrotate.nix
@@ -0,0 +1,35 @@
+# Test logrotate service works and is enabled by default
+
+import ./make-test-python.nix ({ pkgs, ...} : rec {
+  name = "logrotate";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ martinetd ];
+  };
+
+  # default machine
+  machine = { ... }: {
+  };
+
+  testScript =
+    ''
+      with subtest("whether logrotate works"):
+          machine.succeed(
+              # we must rotate once first to create logrotate stamp
+              "systemctl start --wait logrotate.service",
+
+              # wtmp is present in default config.
+              "rm -f /var/log/wtmp*",
+              "echo test > /var/log/wtmp",
+
+              # move into the future and rotate
+              "date -s 'now + 1 month + 1 day'",
+              # systemd will run logrotate from logrotate.timer automatically
+              # on date change, but if we want to wait for it to terminate
+              # it's easier to run again...
+              "systemctl start --wait logrotate.service",
+
+              # check rotate worked
+              "[ -e /var/log/wtmp.1 ]",
+          )
+    '';
+})
diff --git a/nixos/tests/nginx-modsecurity.nix b/nixos/tests/nginx-modsecurity.nix
new file mode 100644
index 0000000000000..8c53c0196d4cc
--- /dev/null
+++ b/nixos/tests/nginx-modsecurity.nix
@@ -0,0 +1,39 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "nginx-modsecurity";
+
+  machine = { config, lib, pkgs, ... }: {
+    services.nginx = {
+      enable = true;
+      additionalModules = [ pkgs.nginxModules.modsecurity-nginx ];
+      virtualHosts.localhost =
+        let modsecurity_conf = pkgs.writeText "modsecurity.conf" ''
+          SecRuleEngine On
+          SecDefaultAction "phase:1,log,auditlog,deny,status:403"
+          SecDefaultAction "phase:2,log,auditlog,deny,status:403"
+          SecRule REQUEST_METHOD   "HEAD"        "id:100, phase:1, block"
+          SecRule REQUEST_FILENAME "secret.html" "id:101, phase:2, block"
+        '';
+        testroot = pkgs.runCommand "testroot" {} ''
+          mkdir -p $out
+          echo "<html><body>Hello World!</body></html>" > $out/index.html
+          echo "s3cret" > $out/secret.html
+        '';
+      in {
+        root = testroot;
+        extraConfig = ''
+          modsecurity on;
+          modsecurity_rules_file ${modsecurity_conf};
+        '';
+      };
+    };
+  };
+  testScript = ''
+    machine.wait_for_unit("nginx")
+
+    response = machine.wait_until_succeeds("curl -fvvv -s http://127.0.0.1/")
+    assert "Hello World!" in response
+
+    machine.fail("curl -fvvv -X HEAD -s http://127.0.0.1/")
+    machine.fail("curl -fvvv -s http://127.0.0.1/secret.html")
+  '';
+})