summary refs log tree commit diff
path: root/nixos/modules/services
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services')
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/slave.nix16
-rw-r--r--nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json17
-rw-r--r--nixos/modules/services/desktops/pipewire/wireplumber.nix2
-rw-r--r--nixos/modules/services/logging/logrotate.nix278
-rw-r--r--nixos/modules/services/matrix/matrix-synapse.nix2
-rw-r--r--nixos/modules/services/misc/gitlab.nix16
-rw-r--r--nixos/modules/services/misc/nix-gc.nix2
-rw-r--r--nixos/modules/services/misc/paperless-ng.nix4
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/bird.nix2
-rw-r--r--nixos/modules/services/networking/lxd-image-server.nix18
-rw-r--r--nixos/modules/services/networking/syncplay.nix18
-rw-r--r--nixos/modules/services/security/oauth2_proxy.nix3
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix21
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix17
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.nix1
15 files changed, 331 insertions, 86 deletions
diff --git a/nixos/modules/services/continuous-integration/jenkins/slave.nix b/nixos/modules/services/continuous-integration/jenkins/slave.nix
index 3c0e6f78e74ca..871b9914fb27a 100644
--- a/nixos/modules/services/continuous-integration/jenkins/slave.nix
+++ b/nixos/modules/services/continuous-integration/jenkins/slave.nix
@@ -1,4 +1,4 @@
-{ config, lib, ... }:
+{ config, lib, pkgs, ... }:
 with lib;
 let
   cfg = config.services.jenkinsSlave;
@@ -46,6 +46,15 @@ in {
           this is the home of the "jenkins" user.
         '';
       };
+
+      javaPackage = mkOption {
+        default = pkgs.jdk;
+        defaultText = literalExpression "pkgs.jdk";
+        description = ''
+          Java package to install.
+        '';
+        type = types.package;
+      };
     };
   };
 
@@ -64,5 +73,10 @@ in {
         uid = config.ids.uids.jenkins;
       };
     };
+
+    programs.java = {
+      enable = true;
+      package = cfg.javaPackage;
+    };
   };
 }
diff --git a/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json b/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json
index df0f62556dff6..b19fb33ec1788 100644
--- a/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json
+++ b/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json
@@ -29,14 +29,7 @@
     },
     {
       "name": "libpipewire-module-protocol-pulse",
-      "args": {
-        "server.address": [
-          "unix:native"
-        ],
-        "vm.overrides": {
-          "pulse.min.quantum": "1024/48000"
-        }
-      }
+      "args": {}
     }
   ],
   "context.exec": [
@@ -46,6 +39,14 @@
     }
   ],
   "stream.properties": {},
+  "pulse.properties": {
+    "server.address": [
+      "unix:native"
+    ],
+    "vm.overrides": {
+      "pulse.min.quantum": "1024/48000"
+    }
+  },
   "pulse.rules": [
     {
       "matches": [
diff --git a/nixos/modules/services/desktops/pipewire/wireplumber.nix b/nixos/modules/services/desktops/pipewire/wireplumber.nix
index 32206ccb4e600..1dbdd842c4a1e 100644
--- a/nixos/modules/services/desktops/pipewire/wireplumber.nix
+++ b/nixos/modules/services/desktops/pipewire/wireplumber.nix
@@ -38,7 +38,7 @@ in
 
     environment.etc."wireplumber/main.lua.d/80-nixos.lua" = lib.mkIf (!pwUsedForAudio) {
      text = ''
-        # Pipewire is not used for audio, so prevent it from grabbing audio devices
+        -- Pipewire is not used for audio, so prevent it from grabbing audio devices
         alsa_monitor.enable = function() end
       '';
     };
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
index 082cf92ff4efe..332a2a597edc1 100644
--- a/nixos/modules/services/logging/logrotate.nix
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -5,7 +5,10 @@ with lib;
 let
   cfg = config.services.logrotate;
 
-  pathOpts = { name, ... }:  {
+  # deprecated legacy compat settings
+  # these options will be removed before 22.11 in the following PR:
+  # https://github.com/NixOS/nixpkgs/pull/164169
+  pathOpts = { name, ... }: {
     options = {
       enable = mkOption {
         type = types.bool;
@@ -86,23 +89,113 @@ let
     config.name = name;
   };
 
-  mkConf = pathOpts: ''
-    # generated by NixOS using the `services.logrotate.paths.${pathOpts.name}` attribute set
-    ${concatMapStringsSep " " (path: ''"${path}"'') (toList pathOpts.path)} {
-      ${optionalString (pathOpts.user != null || pathOpts.group != null) "su ${pathOpts.user} ${pathOpts.group}"}
-      ${pathOpts.frequency}
-      rotate ${toString pathOpts.keep}
-      ${pathOpts.extraConfig}
-    }
-  '';
-
-  paths = sortProperties (attrValues (filterAttrs (_: pathOpts: pathOpts.enable) cfg.paths));
-  configFile = pkgs.writeText "logrotate.conf" (
-    concatStringsSep "\n" (
-      [ "missingok" "notifempty" cfg.extraConfig ] ++ (map mkConf paths)
-    )
+  generateLine = n: v:
+    if builtins.elem n [ "files" "priority" "enable" "global" ] || v == null then null
+    else if builtins.elem n [ "extraConfig" "frequency" ] then "${v}\n"
+    else if builtins.elem n [ "firstaction" "lastaction" "prerotate" "postrotate" "preremove" ]
+         then "${n}\n    ${v}\n  endscript\n"
+    else if isInt v then "${n} ${toString v}\n"
+    else if v == true then "${n}\n"
+    else if v == false then "no${n}\n"
+    else "${n} ${v}\n";
+  generateSection = indent: settings: concatStringsSep (fixedWidthString indent " " "") (
+    filter (x: x != null) (mapAttrsToList generateLine settings)
   );
 
+  # generateSection includes a final newline hence weird closing brace
+  mkConf = settings:
+    if settings.global or false then generateSection 0 settings
+    else ''
+      ${concatMapStringsSep "\n" (files: ''"${files}"'') (toList settings.files)} {
+        ${generateSection 2 settings}}
+    '';
+
+  # below two mapPaths are compat functions
+  mapPathOptToSetting = n: v:
+    if n == "keep" then nameValuePair "rotate" v
+    else if n == "path" then nameValuePair "files" v
+    else nameValuePair n v;
+
+  mapPathsToSettings = path: pathOpts:
+    nameValuePair path (
+      filterAttrs (n: v: ! builtins.elem n [ "user" "group" "name" ] && v != "") (
+        (mapAttrs' mapPathOptToSetting pathOpts) //
+        {
+          su =
+            if pathOpts.user != null
+            then "${pathOpts.user} ${pathOpts.group}"
+            else null;
+        }
+      )
+    );
+
+  settings = sortProperties (attrValues (filterAttrs (_: settings: settings.enable) (
+    foldAttrs recursiveUpdate { } [
+      {
+        header = {
+          enable = true;
+          missingok = true;
+          notifempty = true;
+          frequency = "weekly";
+          rotate = 4;
+        };
+        # compat section
+        extraConfig = {
+          enable = (cfg.extraConfig != "");
+          global = true;
+          extraConfig = cfg.extraConfig;
+          priority = 101;
+        };
+      }
+      (mapAttrs' mapPathsToSettings cfg.paths)
+      cfg.settings
+      { header = { global = true; priority = 100; }; }
+    ]
+  )));
+  configFile = pkgs.writeTextFile {
+    name = "logrotate.conf";
+    text = concatStringsSep "\n" (
+      map mkConf settings
+    );
+    checkPhase = optionalString cfg.checkConfig ''
+      # logrotate --debug also checks that users specified in config
+      # file exist, but we only have sandboxed users here so brown these
+      # out. according to man page that means su, create and createolddir.
+      # files required to exist also won't be present, so missingok is forced.
+      user=$(${pkgs.coreutils}/bin/id -un)
+      group=$(${pkgs.coreutils}/bin/id -gn)
+      sed -e "s/\bsu\s.*/su $user $group/" \
+          -e "s/\b\(create\s\+[0-9]*\s*\|createolddir\s\+[0-9]*\s\+\).*/\1$user $group/" \
+          -e "1imissingok" -e "s/\bnomissingok\b//" \
+          $out > /tmp/logrotate.conf
+      # Since this makes for very verbose builds only show real error.
+      # There is no way to control log level, but logrotate hardcodes
+      # 'error:' at common log level, so we can use grep, taking care
+      # to keep error codes
+      set -o pipefail
+      if ! ${pkgs.logrotate}/sbin/logrotate --debug /tmp/logrotate.conf 2>&1 \
+          | ( ! grep "error:" ) > /tmp/logrotate-error; then
+              echo "Logrotate configuration check failed."
+              echo "The failing configuration (after adjustments to pass tests in sandbox) was:"
+              printf "%s\n" "-------"
+              cat /tmp/logrotate.conf
+              printf "%s\n" "-------"
+              echo "The error reported by logrotate was as follow:"
+              printf "%s\n" "-------"
+              cat /tmp/logrotate-error
+              printf "%s\n" "-------"
+              echo "You can disable this check with services.logrotate.checkConfig = false,"
+              echo "but if you think it should work please report this failure along with"
+              echo "the config file being tested!"
+              false
+      fi
+    '';
+  };
+
+  mailOption =
+    if foldr (n: a: a || n ? mail) false (attrValues cfg.settings)
+    then "--mail=${pkgs.mailutils}/bin/mail"
+    else "";
 in
 {
   imports = [
@@ -112,17 +205,121 @@ in
   options = {
     services.logrotate = {
       enable = mkEnableOption "the logrotate systemd service" // {
-        default = foldr (n: a: a || n.enable) false (attrValues cfg.paths);
-        defaultText = literalExpression "cfg.paths != {}";
+        default = foldr (n: a: a || n.enable) false (attrValues cfg.settings);
+        defaultText = literalExpression "cfg.settings != {}";
+      };
+
+      settings = mkOption {
+        default = { };
+        description = ''
+          logrotate freeform settings: each attribute here will define its own section,
+          ordered by priority, which can either define files to rotate with their settings
+          or settings common to all further files settings.
+          Refer to <link xlink:href="https://linux.die.net/man/8/logrotate"/> for details.
+        '';
+        type = types.attrsOf (types.submodule ({ name, ... }: {
+          freeformType = with types; attrsOf (nullOr (oneOf [ int bool str ]));
+
+          options = {
+            enable = mkEnableOption "setting individual kill switch" // {
+              default = true;
+            };
+
+            global = mkOption {
+              type = types.bool;
+              default = false;
+              description = ''
+                Whether this setting is a global option or not: set to have these
+                settings apply to all files settings with a higher priority.
+              '';
+            };
+            files = mkOption {
+              type = with types; either str (listOf str);
+              default = name;
+              defaultText = ''
+                The attrset name if not specified
+              '';
+              description = ''
+                Single or list of files for which rules are defined.
+                The files are quoted with double-quotes in logrotate configuration,
+                so globs and spaces are supported.
+                Note this setting is ignored if globals is true.
+              '';
+            };
+
+            frequency = mkOption {
+              type = types.nullOr types.str;
+              default = null;
+              description = ''
+                How often to rotate the logs. Defaults to previously set global setting,
+                which itself defauts to weekly.
+              '';
+            };
+
+            priority = mkOption {
+              type = types.int;
+              default = 1000;
+              description = ''
+                Order of this logrotate block in relation to the others. The semantics are
+                the same as with `lib.mkOrder`. Smaller values are inserted first.
+              '';
+            };
+          };
+
+        }));
+      };
+
+      configFile = mkOption {
+        type = types.path;
+        default = configFile;
+        defaultText = ''
+          A configuration file automatically generated by NixOS.
+        '';
+        description = ''
+          Override the configuration file used by MySQL. By default,
+          NixOS generates one automatically from <xref linkend="opt-services.logrotate.settings"/>.
+        '';
+        example = literalExpression ''
+          pkgs.writeText "logrotate.conf" '''
+            missingok
+            "/var/log/*.log" {
+              rotate 4
+              weekly
+            }
+          ''';
+        '';
       };
 
+      checkConfig = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether the config should be checked at build time.
+
+          Some options are not checkable at build time because of the build sandbox:
+          for example, the test does not know about existing files and system users are
+          not known.
+          These limitations mean we must adjust the file for tests (missingok is forced
+          and users are replaced by dummy users), so tests are complemented by a
+          logrotate-checkconf service that is enabled by default.
+          This extra check can be disabled by disabling it at the systemd level with the
+          <option>services.systemd.services.logrotate-checkconf.enable</option> option.
+
+          Conversely there are still things that might make this check fail incorrectly
+          (e.g. a file path where we don't have access to intermediate directories):
+          in this case you can disable the failing check with this option.
+        '';
+      };
+
+      # deprecated legacy compat settings
       paths = mkOption {
         type = with types; attrsOf (submodule pathOpts);
-        default = {};
+        default = { };
         description = ''
           Attribute set of paths to rotate. The order each block appears in the generated configuration file
           can be controlled by the <link linkend="opt-services.logrotate.paths._name_.priority">priority</link> option
           using the same semantics as `lib.mkOrder`. Smaller values have a greater priority.
+          This setting has been deprecated in favor of <link linkend="opt-services.logrotate.settings">logrotate settings</link>.
         '';
         example = literalExpression ''
           {
@@ -151,19 +348,37 @@ in
         description = ''
           Extra contents to append to the logrotate configuration file. Refer to
           <link xlink:href="https://linux.die.net/man/8/logrotate"/> for details.
+          This setting has been deprecated in favor of
+          <link linkend="opt-services.logrotate.settings">logrotate settings</link>.
         '';
       };
     };
   };
 
   config = mkIf cfg.enable {
-    assertions = mapAttrsToList (name: pathOpts:
-      { assertion = (pathOpts.user != null) == (pathOpts.group != null);
-        message = ''
-          If either of `services.logrotate.paths.${name}.user` or `services.logrotate.paths.${name}.group` are specified then *both* must be specified.
-        '';
-      }
-    ) cfg.paths;
+    assertions =
+      mapAttrsToList
+        (name: pathOpts:
+          {
+            assertion = (pathOpts.user != null) == (pathOpts.group != null);
+            message = ''
+              If either of `services.logrotate.paths.${name}.user` or `services.logrotate.paths.${name}.group` are specified then *both* must be specified.
+            '';
+          })
+        cfg.paths;
+
+    warnings =
+      (mapAttrsToList
+        (name: pathOpts: ''
+          Using config.services.logrotate.paths.${name} is deprecated and will become unsupported in a future release.
+          Please use services.logrotate.settings instead.
+        '')
+        cfg.paths
+      ) ++
+      (optional (cfg.extraConfig != "") ''
+        Using config.services.logrotate.extraConfig is deprecated and will become unsupported in a future release.
+        Please use services.logrotate.settings with globals=true instead.
+      '');
 
     systemd.services.logrotate = {
       description = "Logrotate Service";
@@ -172,7 +387,16 @@ in
       serviceConfig = {
         Restart = "no";
         User = "root";
-        ExecStart = "${pkgs.logrotate}/sbin/logrotate ${configFile}";
+        ExecStart = "${pkgs.logrotate}/sbin/logrotate ${mailOption} ${cfg.configFile}";
+      };
+    };
+    systemd.services.logrotate-checkconf = {
+      description = "Logrotate configuration check";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+        ExecStart = "${pkgs.logrotate}/sbin/logrotate --debug ${cfg.configFile}";
       };
     };
   };
diff --git a/nixos/modules/services/matrix/matrix-synapse.nix b/nixos/modules/services/matrix/matrix-synapse.nix
index c4d14dbd547ef..4abcc8b69bc53 100644
--- a/nixos/modules/services/matrix/matrix-synapse.nix
+++ b/nixos/modules/services/matrix/matrix-synapse.nix
@@ -141,7 +141,7 @@ in {
       enable = mkEnableOption "matrix.org synapse";
 
       configFile = mkOption {
-        type = types.str;
+        type = types.path;
         readOnly = true;
         description = ''
           Path to the configuration file on the target system. Useful to configure e.g. workers
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index c3b23f4d34825..0811b34156e49 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -848,10 +848,7 @@ in {
 
         extraConfig = mkOption {
           type = types.lines;
-          default = ''
-            copytruncate
-            compress
-          '';
+          default = "";
           description = ''
             Extra logrotate config options for this path. Refer to
             <link xlink:href="https://linux.die.net/man/8/logrotate"/> for details.
@@ -977,13 +974,14 @@ in {
     # Enable rotation of log files
     services.logrotate = {
       enable = cfg.logrotate.enable;
-      paths = {
+      settings = {
         gitlab = {
-          path = "${cfg.statePath}/log/*.log";
-          user = cfg.user;
-          group = cfg.group;
+          files = "${cfg.statePath}/log/*.log";
+          su = "${cfg.user} ${cfg.group}";
           frequency = cfg.logrotate.frequency;
-          keep = cfg.logrotate.keep;
+          rotate = cfg.logrotate.keep;
+          copytruncate = true;
+          compress = true;
           extraConfig = cfg.logrotate.extraConfig;
         };
       };
diff --git a/nixos/modules/services/misc/nix-gc.nix b/nixos/modules/services/misc/nix-gc.nix
index b4b4b55a6c823..0fcb016010175 100644
--- a/nixos/modules/services/misc/nix-gc.nix
+++ b/nixos/modules/services/misc/nix-gc.nix
@@ -39,7 +39,7 @@ in
         type = types.str;
         example = "45min";
         description = ''
-          Add a randomized delay before each automatic upgrade.
+          Add a randomized delay before each garbage collection.
           The delay will be chosen between zero and this value.
           This value must be a time span in the format specified by
           <citerefentry><refentrytitle>systemd.time</refentrytitle>
diff --git a/nixos/modules/services/misc/paperless-ng.nix b/nixos/modules/services/misc/paperless-ng.nix
index 11e44f5ece575..881fa93c04eed 100644
--- a/nixos/modules/services/misc/paperless-ng.nix
+++ b/nixos/modules/services/misc/paperless-ng.nix
@@ -216,6 +216,8 @@ in
         Restart = "on-failure";
         # The `mbind` syscall is needed for running the classifier.
         SystemCallFilter = defaultServiceConfig.SystemCallFilter ++ [ "mbind" ];
+        # Needs to talk to mail server for automated import rules
+        PrivateNetwork = false;
       };
       environment = env;
       wantedBy = [ "multi-user.target" ];
@@ -258,8 +260,6 @@ in
             '${cfg.passwordFile}' '${cfg.dataDir}/superuser-password'
         '';
         Type = "oneshot";
-        # Needs to talk to mail server for automated import rules
-        PrivateNetwork = false;
       };
     };
 
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/bird.nix b/nixos/modules/services/monitoring/prometheus/exporters/bird.nix
index 1ef264fc86e5a..5fda4c980ebb8 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/bird.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/bird.nix
@@ -17,7 +17,7 @@ in
     };
     birdSocket = mkOption {
       type = types.path;
-      default = "/var/run/bird.ctl";
+      default = "/run/bird/bird.ctl";
       description = ''
         Path to BIRD2 (or BIRD1 v4) socket.
       '';
diff --git a/nixos/modules/services/networking/lxd-image-server.nix b/nixos/modules/services/networking/lxd-image-server.nix
index b119ba8acf634..d326626eed442 100644
--- a/nixos/modules/services/networking/lxd-image-server.nix
+++ b/nixos/modules/services/networking/lxd-image-server.nix
@@ -51,18 +51,14 @@ in
 
       environment.etc."lxd-image-server/config.toml".source = format.generate "config.toml" cfg.settings;
 
-      services.logrotate.paths.lxd-image-server = {
-        path = "/var/log/lxd-image-server/lxd-image-server.log";
+      services.logrotate.settings.lxd-image-server = {
+        files = "/var/log/lxd-image-server/lxd-image-server.log";
         frequency = "daily";
-        keep = 21;
-        extraConfig = ''
-          create 755 lxd-image-server ${cfg.group}
-          missingok
-          compress
-          delaycompress
-          copytruncate
-          notifempty
-        '';
+        rotate = 21;
+        create = "755 lxd-image-server ${cfg.group}";
+        compress = true;
+        delaycompress = true;
+        copytruncate = true;
       };
 
       systemd.tmpfiles.rules = [
diff --git a/nixos/modules/services/networking/syncplay.nix b/nixos/modules/services/networking/syncplay.nix
index b6faf2d3f7727..c17426ecced72 100644
--- a/nixos/modules/services/networking/syncplay.nix
+++ b/nixos/modules/services/networking/syncplay.nix
@@ -61,6 +61,15 @@ in
           Group to use when running Syncplay.
         '';
       };
+
+      passwordFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = ''
+          Path to the file that contains the server password. If
+          <literal>null</literal>, the server doesn't require a password.
+        '';
+      };
     };
   };
 
@@ -71,10 +80,17 @@ in
       after       = [ "network-online.target" ];
 
       serviceConfig = {
-        ExecStart = "${pkgs.syncplay}/bin/syncplay-server ${escapeShellArgs cmdArgs}";
         User = cfg.user;
         Group = cfg.group;
+        LoadCredential = lib.mkIf (cfg.passwordFile != null) "password:${cfg.passwordFile}";
       };
+
+      script = ''
+        ${lib.optionalString (cfg.passwordFile != null) ''
+          export SYNCPLAY_PASSWORD=$(cat "''${CREDENTIALS_DIRECTORY}/password")
+        ''}
+        exec ${pkgs.syncplay}/bin/syncplay-server ${escapeShellArgs cmdArgs}
+      '';
     };
   };
 }
diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix
index ce295bd4ba3bb..5c89d58723760 100644
--- a/nixos/modules/services/security/oauth2_proxy.nix
+++ b/nixos/modules/services/security/oauth2_proxy.nix
@@ -571,8 +571,11 @@ in
     users.users.oauth2_proxy = {
       description = "OAuth2 Proxy";
       isSystemUser = true;
+      group = "oauth2_proxy";
     };
 
+    users.groups.oauth2_proxy = {};
+
     systemd.services.oauth2_proxy = {
       description = "OAuth2 Proxy";
       path = [ cfg.package ];
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index d817ff6019a3b..3099705acbe2e 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -710,20 +710,15 @@ in
 
     services.logrotate = optionalAttrs (cfg.logFormat != "none") {
       enable = mkDefault true;
-      paths.httpd = {
-        path = "${cfg.logDir}/*.log";
-        user = cfg.user;
-        group = cfg.group;
+      settings.httpd = {
+        files = "${cfg.logDir}/*.log";
+        su = "${cfg.user} ${cfg.group}";
         frequency = "daily";
-        keep = 28;
-        extraConfig = ''
-          sharedscripts
-          compress
-          delaycompress
-          postrotate
-            systemctl reload httpd.service > /dev/null 2>/dev/null || true
-          endscript
-        '';
+        rotate = 28;
+        sharedscripts = true;
+        compress = true;
+        delaycompress = true;
+        postrotate = "systemctl reload httpd.service > /dev/null 2>/dev/null || true";
       };
     };
 
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index e046c28dd6bbe..7caaf5611cc0e 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -989,17 +989,14 @@ in
       nginx.gid = config.ids.gids.nginx;
     };
 
-    services.logrotate.paths.nginx = mapAttrs (_: mkDefault) {
-      path = "/var/log/nginx/*.log";
+    services.logrotate.settings.nginx = mapAttrs (_: mkDefault) {
+      files = "/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
-      '';
+      su = "${cfg.user} ${cfg.group}";
+      rotate = 26;
+      compress = true;
+      delaycompress = true;
+      postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
     };
   };
 }
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index 48e119a861875..3528b0f40e7b7 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -302,6 +302,7 @@ in
       environment.systemPackages = with pkgs.pantheon; [
         contractor
         file-roller-contract
+        gnome-bluetooth-contract
       ];
 
       environment.pathsToLink = [