about summary refs log tree commit diff
path: root/nixpkgs/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos')
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/system-tarball.nix2
-rw-r--r--nixpkgs/nixos/modules/module-list.nix4
-rw-r--r--nixpkgs/nixos/modules/security/misc.nix24
-rw-r--r--nixpkgs/nixos/modules/services/admin/oxidized.nix2
-rw-r--r--nixpkgs/nixos/modules/services/amqp/rabbitmq.nix5
-rw-r--r--nixpkgs/nixos/modules/services/audio/liquidsoap.nix7
-rw-r--r--nixpkgs/nixos/modules/services/audio/mpd.nix10
-rw-r--r--nixpkgs/nixos/modules/services/backup/automysqlbackup.nix115
-rw-r--r--nixpkgs/nixos/modules/services/backup/mysql-backup.nix8
-rw-r--r--nixpkgs/nixos/modules/services/backup/postgresql-backup.nix11
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/addon-manager.nix85
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/addons/dashboard.nix36
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/apiserver.nix69
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/controller-manager.nix41
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix26
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/flannel.nix70
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix86
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix167
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix39
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/scheduler.nix36
-rw-r--r--nixpkgs/nixos/modules/services/databases/clickhouse.nix17
-rw-r--r--nixpkgs/nixos/modules/services/databases/couchdb.nix21
-rw-r--r--nixpkgs/nixos/modules/services/databases/influxdb.nix13
-rw-r--r--nixpkgs/nixos/modules/services/databases/memcached.nix8
-rw-r--r--nixpkgs/nixos/modules/services/databases/stanchion.nix20
-rw-r--r--nixpkgs/nixos/modules/services/desktops/gnome3/gnome-settings-daemon.nix2
-rw-r--r--nixpkgs/nixos/modules/services/hardware/bluetooth.nix2
-rw-r--r--nixpkgs/nixos/modules/services/hardware/vdr.nix4
-rw-r--r--nixpkgs/nixos/modules/services/mail/mailcatcher.nix2
-rw-r--r--nixpkgs/nixos/modules/services/mail/nullmailer.nix6
-rw-r--r--nixpkgs/nixos/modules/services/mail/offlineimap.nix2
-rw-r--r--nixpkgs/nixos/modules/services/mail/rss2email.nix10
-rw-r--r--nixpkgs/nixos/modules/services/misc/beanstalkd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/etcd.nix10
-rw-r--r--nixpkgs/nixos/modules/services/misc/jackett.nix13
-rw-r--r--nixpkgs/nixos/modules/services/misc/lidarr.nix7
-rw-r--r--nixpkgs/nixos/modules/services/misc/matrix-synapse.nix5
-rw-r--r--nixpkgs/nixos/modules/services/misc/mesos-master.nix7
-rw-r--r--nixpkgs/nixos/modules/services/misc/mesos-slave.nix7
-rw-r--r--nixpkgs/nixos/modules/services/misc/plex.nix104
-rw-r--r--nixpkgs/nixos/modules/services/misc/radarr.nix13
-rw-r--r--nixpkgs/nixos/modules/services/misc/sonarr.nix13
-rw-r--r--nixpkgs/nixos/modules/services/misc/sssd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/zookeeper.nix7
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/collectd.nix11
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/graphite.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/munin.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix672
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix14
-rw-r--r--nixpkgs/nixos/modules/services/networking/i2pd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/miredo.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/monero.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/mosquitto.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/mxisd.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/namecoind.nix3
-rw-r--r--nixpkgs/nixos/modules/services/networking/nullidentdmod.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/smokeping.nix3
-rw-r--r--nixpkgs/nixos/modules/services/networking/syncthing.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/tedicross.nix100
-rw-r--r--nixpkgs/nixos/modules/services/networking/toxvpn.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/wg-quick.nix312
-rw-r--r--nixpkgs/nixos/modules/services/networking/wireguard.nix83
-rw-r--r--nixpkgs/nixos/modules/services/search/kibana.nix2
-rw-r--r--nixpkgs/nixos/modules/services/search/solr.nix2
-rw-r--r--nixpkgs/nixos/modules/services/security/bitwarden_rs/backup.sh17
-rw-r--r--nixpkgs/nixos/modules/services/security/bitwarden_rs/default.nix126
-rw-r--r--nixpkgs/nixos/modules/services/security/munge.nix13
-rw-r--r--nixpkgs/nixos/modules/services/security/vault.nix9
-rw-r--r--nixpkgs/nixos/modules/services/torrent/peerflix.nix6
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/codimd.nix5
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/nexus.nix5
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/minio.nix13
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/traefik.nix10
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix2
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/maxx.nix6
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/startx.nix4
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/xpra.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/stage-1-init.sh2
-rw-r--r--nixpkgs/nixos/modules/system/boot/stage-1.nix2
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix2
-rw-r--r--nixpkgs/nixos/modules/virtualisation/ec2-amis.nix19
-rw-r--r--nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix5
-rw-r--r--nixpkgs/nixos/tests/all-tests.nix3
-rw-r--r--nixpkgs/nixos/tests/automysqlbackup.nix34
-rw-r--r--nixpkgs/nixos/tests/kubernetes/base.nix5
-rw-r--r--nixpkgs/nixos/tests/kubernetes/dns.nix3
-rw-r--r--nixpkgs/nixos/tests/kubernetes/rbac.nix4
-rw-r--r--nixpkgs/nixos/tests/mosquitto.nix69
-rw-r--r--nixpkgs/nixos/tests/nginx.nix70
-rw-r--r--nixpkgs/nixos/tests/wireguard/generated.nix57
90 files changed, 2027 insertions, 830 deletions
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball.nix b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball.nix
index e72d4a5b4910..b84096861f56 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball.nix
@@ -68,7 +68,7 @@ in
 
     # Create the tarball
     system.build.tarball = import ../../../lib/make-system-tarball.nix {
-      inherit (pkgs) stdenv perl xz pathsFromGraph;
+      inherit (pkgs) stdenv closureInfo pixz;
 
       inherit (config.tarball) contents storeContents;
     };
diff --git a/nixpkgs/nixos/modules/module-list.nix b/nixpkgs/nixos/modules/module-list.nix
index 5012a3a303c9..5fb559d2e6ef 100644
--- a/nixpkgs/nixos/modules/module-list.nix
+++ b/nixpkgs/nixos/modules/module-list.nix
@@ -188,6 +188,7 @@
   ./services/audio/snapserver.nix
   ./services/audio/squeezelite.nix
   ./services/audio/ympd.nix
+  ./services/backup/automysqlbackup.nix
   ./services/backup/bacula.nix
   ./services/backup/borgbackup.nix
   ./services/backup/duplicati.nix
@@ -673,6 +674,7 @@
   ./services/networking/syncthing-relay.nix
   ./services/networking/tcpcrypt.nix
   ./services/networking/teamspeak3.nix
+  ./services/networking/tedicross.nix
   ./services/networking/tinc.nix
   ./services/networking/tinydns.nix
   ./services/networking/tftpd.nix
@@ -685,6 +687,7 @@
   ./services/networking/vsftpd.nix
   ./services/networking/wakeonlan.nix
   ./services/networking/websockify.nix
+  ./services/networking/wg-quick.nix
   ./services/networking/wicd.nix
   ./services/networking/wireguard.nix
   ./services/networking/wpa_supplicant.nix
@@ -706,6 +709,7 @@
   ./services/search/hound.nix
   ./services/search/kibana.nix
   ./services/search/solr.nix
+  ./services/security/bitwarden_rs/default.nix
   ./services/security/certmgr.nix
   ./services/security/cfssl.nix
   ./services/security/clamav.nix
diff --git a/nixpkgs/nixos/modules/security/misc.nix b/nixpkgs/nixos/modules/security/misc.nix
index 4506a67487d4..ecf22bf81c59 100644
--- a/nixpkgs/nixos/modules/security/misc.nix
+++ b/nixpkgs/nixos/modules/security/misc.nix
@@ -12,14 +12,24 @@ with lib;
       type = types.bool;
       default = true;
       description = ''
-        Whether to allow creation of user namespaces.  A recurring problem
-        with user namespaces is the presence of code paths where the kernel's
-        permission checking logic fails to account for namespacing, instead
-        permitting a namespaced process to act outside the namespace with the
-        same privileges as it would have inside it.  This is particularly
+        Whether to allow creation of user namespaces.
+        </para>
+
+        <para>
+        The motivation for disabling user namespaces is the potential
+        presence of code paths where the kernel's permission checking
+        logic fails to account for namespacing, instead permitting a
+        namespaced process to act outside the namespace with the same
+        privileges as it would have inside it.  This is particularly
         damaging in the common case of running as root within the namespace.
-        When user namespace creation is disallowed, attempting to create
-        a user namespace fails with "no space left on device" (ENOSPC).
+        </para>
+
+        <para>
+        When user namespace creation is disallowed, attempting to create a
+        user namespace fails with "no space left on device" (ENOSPC).
+        root may re-enable user namespace creation at runtime.
+        </para>
+        <para>
       '';
     };
 
diff --git a/nixpkgs/nixos/modules/services/admin/oxidized.nix b/nixpkgs/nixos/modules/services/admin/oxidized.nix
index 70f7dd9e3647..687cdfb5ba57 100644
--- a/nixpkgs/nixos/modules/services/admin/oxidized.nix
+++ b/nixpkgs/nixos/modules/services/admin/oxidized.nix
@@ -7,7 +7,7 @@ let
 in
 {
   options.services.oxidized = {
-    enable = mkEnableOption "the oxidized configuation backup service.";
+    enable = mkEnableOption "the oxidized configuration backup service";
 
     user = mkOption {
       type = types.str;
diff --git a/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix b/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix
index 7373be2a9b0b..302b94de1965 100644
--- a/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix
+++ b/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix
@@ -179,11 +179,11 @@ in {
       } //  optionalAttrs (cfg.config != "") { RABBITMQ_ADVANCED_CONFIG_FILE = advanced_config_file; };
 
       serviceConfig = {
-        PermissionsStartOnly = true; # preStart must be run as root
         ExecStart = "${cfg.package}/sbin/rabbitmq-server";
         ExecStop = "${cfg.package}/sbin/rabbitmqctl shutdown";
         User = "rabbitmq";
         Group = "rabbitmq";
+        LogsDirectory = "rabbitmq";
         WorkingDirectory = cfg.dataDir;
         Type = "notify";
         NotifyAccess = "all";
@@ -197,11 +197,8 @@ in {
       preStart = ''
         ${optionalString (cfg.cookie != "") ''
             echo -n ${cfg.cookie} > ${cfg.dataDir}/.erlang.cookie
-            chown rabbitmq:rabbitmq ${cfg.dataDir}/.erlang.cookie
             chmod 600 ${cfg.dataDir}/.erlang.cookie
         ''}
-        mkdir -p /var/log/rabbitmq
-        chown rabbitmq:rabbitmq /var/log/rabbitmq
       '';
     };
 
diff --git a/nixpkgs/nixos/modules/services/audio/liquidsoap.nix b/nixpkgs/nixos/modules/services/audio/liquidsoap.nix
index 66f84ef20762..3a047d10a631 100644
--- a/nixpkgs/nixos/modules/services/audio/liquidsoap.nix
+++ b/nixpkgs/nixos/modules/services/audio/liquidsoap.nix
@@ -14,15 +14,10 @@ let
         description = "${name} liquidsoap stream";
         wantedBy = [ "multi-user.target" ];
         path = [ pkgs.wget ];
-        preStart =
-          ''
-            mkdir -p /var/log/liquidsoap
-            chown liquidsoap -R /var/log/liquidsoap
-          '';
         serviceConfig = {
-          PermissionsStartOnly="true";
           ExecStart = "${pkgs.liquidsoap}/bin/liquidsoap ${stream}";
           User = "liquidsoap";
+          LogsDirectory = "liquidsoap";
         };
       };
     };
diff --git a/nixpkgs/nixos/modules/services/audio/mpd.nix b/nixpkgs/nixos/modules/services/audio/mpd.nix
index 5bfe2b6a22ad..0df8f9688d25 100644
--- a/nixpkgs/nixos/modules/services/audio/mpd.nix
+++ b/nixpkgs/nixos/modules/services/audio/mpd.nix
@@ -158,18 +158,18 @@ in {
       };
     };
 
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' - ${cfg.user} ${cfg.group} - -"
+      "d '${cfg.playlistDirectory}' - ${cfg.user} ${cfg.group} - -"
+    ];
+
     systemd.services.mpd = {
       after = [ "network.target" "sound.target" ];
       description = "Music Player Daemon";
       wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target";
 
-      preStart = ''
-        mkdir -p "${cfg.dataDir}" && chown -R ${cfg.user}:${cfg.group} "${cfg.dataDir}"
-        mkdir -p "${cfg.playlistDirectory}" && chown -R ${cfg.user}:${cfg.group} "${cfg.playlistDirectory}"
-      '';
       serviceConfig = {
         User = "${cfg.user}";
-        PermissionsStartOnly = true;
         ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon ${mpdConf}";
         Type = "notify";
         LimitRTPRIO = 50;
diff --git a/nixpkgs/nixos/modules/services/backup/automysqlbackup.nix b/nixpkgs/nixos/modules/services/backup/automysqlbackup.nix
new file mode 100644
index 000000000000..b845f370fb70
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/backup/automysqlbackup.nix
@@ -0,0 +1,115 @@
+{ config, lib, pkgs, ... }:
+
+let
+
+  inherit (lib) concatMapStringsSep concatStringsSep isInt isList literalExample;
+  inherit (lib) mapAttrs mapAttrsToList mkDefault mkEnableOption mkIf mkOption optional types;
+
+  cfg = config.services.automysqlbackup;
+  pkg = pkgs.automysqlbackup;
+  user = "automysqlbackup";
+  group = "automysqlbackup";
+
+  toStr = val:
+    if isList val then "( ${concatMapStringsSep " " (val: "'${val}'") val} )"
+    else if isInt val then toString val
+    else if true == val then "'yes'"
+    else if false == val then "'no'"
+    else "'${toString val}'";
+
+  configFile = pkgs.writeText "automysqlbackup.conf" ''
+    #version=${pkg.version}
+    # DONT'T REMOVE THE PREVIOUS VERSION LINE!
+    #
+    ${concatStringsSep "\n" (mapAttrsToList (name: value: "CONFIG_${name}=${toStr value}") cfg.config)}
+  '';
+
+in
+{
+  # interface
+  options = {
+    services.automysqlbackup = {
+
+      enable = mkEnableOption "AutoMySQLBackup";
+
+      calendar = mkOption {
+        type = types.str;
+        default = "01:15:00";
+        description = ''
+          Configured when to run the backup service systemd unit (DayOfWeek Year-Month-Day Hour:Minute:Second).
+        '';
+      };
+
+      config = mkOption {
+        type = with types; attrsOf (either (either str (either int bool)) (listOf str));
+        default = {};
+        description = ''
+          automysqlbackup configuration. Refer to
+          <filename>''${pkgs.automysqlbackup}/etc/automysqlbackup.conf</filename>
+          for details on supported values.
+        '';
+        example = literalExample ''
+          {
+            db_names = [ "nextcloud" "matomo" ];
+            table_exclude = [ "nextcloud.oc_users" "nextcloud.oc_whats_new" ];
+            mailcontent = "log";
+            mail_address = "admin@example.org";
+          }
+        '';
+      };
+
+    };
+  };
+
+  # implementation
+  config = mkIf cfg.enable {
+
+    assertions = [
+      { assertion = !config.services.mysqlBackup.enable;
+        message = "Please choose one of services.mysqlBackup or services.automysqlbackup.";
+      }
+    ];
+
+    services.automysqlbackup.config = mapAttrs (name: mkDefault) {
+      mysql_dump_username = user;
+      mysql_dump_host = "localhost";
+      backup_dir = "/var/backup/mysql";
+      db_exclude = [ "information_schema" "performance_schema" ];
+      mailcontent = "stdout";
+      mysql_dump_single_transaction = true;
+    };
+
+    systemd.timers.automysqlbackup = {
+      description = "automysqlbackup timer";
+      wantedBy = [ "timers.target" ];
+      timerConfig = {
+        OnCalendar = cfg.calendar;
+        AccuracySec = "5m";
+      };
+    };
+
+    systemd.services.automysqlbackup = {
+      description = "automysqlbackup service";
+      serviceConfig = {
+        User = user;
+        Group = group;
+        ExecStart = "${pkg}/bin/automysqlbackup ${configFile}";
+      };
+    };
+
+    environment.systemPackages = [ pkg ];
+
+    users.users.${user}.group = group;
+    users.groups.${group} = { };
+
+    systemd.tmpfiles.rules = [
+      "d '${cfg.config.backup_dir}' 0750 ${user} ${group} - -"
+    ];
+
+    services.mysql.ensureUsers = optional (config.services.mysql.enable && cfg.config.mysql_dump_host == "localhost") {
+      name = user;
+      ensurePermissions = { "*.*" = "SELECT, SHOW VIEW, TRIGGER, LOCK TABLES"; };
+    };
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/backup/mysql-backup.nix b/nixpkgs/nixos/modules/services/backup/mysql-backup.nix
index f0c273ffebf1..ba6e154f6b3d 100644
--- a/nixpkgs/nixos/modules/services/backup/mysql-backup.nix
+++ b/nixpkgs/nixos/modules/services/backup/mysql-backup.nix
@@ -117,14 +117,12 @@ in
         enable = true;
         serviceConfig = {
           User = cfg.user;
-          PermissionsStartOnly = true;
         };
-        preStart = ''
-          mkdir -m 0700 -p ${cfg.location}
-          chown -R ${cfg.user} ${cfg.location}
-        '';
         script = backupScript;
       };
+      tmpfiles.rules = [
+        "d ${cfg.location} 0700 ${cfg.user} - - -"
+      ];
     };
   };
 
diff --git a/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix b/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix
index 11efa47ec5b2..17b410a97f3e 100644
--- a/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix
+++ b/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix
@@ -14,11 +14,6 @@ let
 
       requires = [ "postgresql.service" ];
 
-      preStart = ''
-        mkdir -m 0700 -p ${cfg.location}
-        chown postgres ${cfg.location}
-      '';
-
       script = ''
         umask 0077 # ensure backup is only readable by postgres user
 
@@ -32,7 +27,6 @@ let
 
       serviceConfig = {
         Type = "oneshot";
-        PermissionsStartOnly = "true";
         User = "postgres";
       };
 
@@ -107,6 +101,11 @@ in {
         message = "config.services.postgresqlBackup.backupAll cannot be used together with config.services.postgresqlBackup.databases";
       }];
     }
+    (mkIf cfg.enable {
+      systemd.tmpfiles.rules = [
+        "d '${cfg.location}' 0700 postgres - - -"
+      ];
+    })
     (mkIf (cfg.enable && cfg.backupAll) {
       systemd.services.postgresqlBackup =
         postgresqlBackupService "all" "${config.services.postgresql.package}/bin/pg_dumpall";
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/addon-manager.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/addon-manager.nix
index 17f2dde31a71..ad7d17c9c283 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/addon-manager.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/addon-manager.nix
@@ -62,19 +62,50 @@ in
       '';
     };
 
-    enable = mkEnableOption "Whether to enable Kubernetes addon manager.";
+    enable = mkEnableOption "Kubernetes addon manager";
+
+    kubeconfig = top.lib.mkKubeConfigOptions "Kubernetes addon manager";
+    bootstrapAddonsKubeconfig = top.lib.mkKubeConfigOptions "Kubernetes addon manager bootstrap";
   };
 
   ###### implementation
-  config = mkIf cfg.enable {
+  config = let
+
+    addonManagerPaths = filter (a: a != null) [
+      cfg.kubeconfig.caFile
+      cfg.kubeconfig.certFile
+      cfg.kubeconfig.keyFile
+    ];
+    bootstrapAddonsPaths = filter (a: a != null) [
+      cfg.bootstrapAddonsKubeconfig.caFile
+      cfg.bootstrapAddonsKubeconfig.certFile
+      cfg.bootstrapAddonsKubeconfig.keyFile
+    ];
+
+  in mkIf cfg.enable {
     environment.etc."kubernetes/addons".source = "${addons}/";
 
+    #TODO: Get rid of kube-addon-manager in the future for the following reasons
+    # - it is basically just a shell script wrapped around kubectl
+    # - it assumes that it is clusterAdmin or can gain clusterAdmin rights through serviceAccount
+    # - it is designed to be used with k8s system components only
+    # - it would be better with a more Nix-oriented way of managing addons
     systemd.services.kube-addon-manager = {
       description = "Kubernetes addon manager";
       wantedBy = [ "kubernetes.target" ];
-      after = [ "kube-apiserver.service" ];
-      environment.ADDON_PATH = "/etc/kubernetes/addons/";
-      path = [ pkgs.gawk ];
+      after = [ "kube-node-online.target" ];
+      before = [ "kubernetes.target" ];
+      environment = {
+        ADDON_PATH = "/etc/kubernetes/addons/";
+        KUBECONFIG = top.lib.mkKubeConfig "kube-addon-manager" cfg.kubeconfig;
+      };
+      path = with pkgs; [ gawk kubectl ];
+      preStart = ''
+        until kubectl -n kube-system get serviceaccounts/default 2>/dev/null; do
+          echo kubectl -n kube-system get serviceaccounts/default: exit status $?
+          sleep 2
+        done
+      '';
       serviceConfig = {
         Slice = "kubernetes.slice";
         ExecStart = "${top.package}/bin/kube-addons";
@@ -84,8 +115,52 @@ in
         Restart = "on-failure";
         RestartSec = 10;
       };
+      unitConfig.ConditionPathExists = addonManagerPaths;
     };
 
+    systemd.paths.kube-addon-manager = {
+      wantedBy = [ "kube-addon-manager.service" ];
+      pathConfig = {
+        PathExists = addonManagerPaths;
+        PathChanged = addonManagerPaths;
+      };
+    };
+
+    services.kubernetes.addonManager.kubeconfig.server = mkDefault top.apiserverAddress;
+
+    systemd.services.kube-addon-manager-bootstrap = mkIf (top.apiserver.enable && top.addonManager.bootstrapAddons != {}) {
+      wantedBy = [ "kube-control-plane-online.target" ];
+      after = [ "kube-apiserver.service" ];
+      before = [ "kube-control-plane-online.target" ];
+      path = [ pkgs.kubectl ];
+      environment = {
+        KUBECONFIG = top.lib.mkKubeConfig "kube-addon-manager-bootstrap" cfg.bootstrapAddonsKubeconfig;
+      };
+      preStart = with pkgs; let
+        files = mapAttrsToList (n: v: writeText "${n}.json" (builtins.toJSON v))
+          cfg.bootstrapAddons;
+      in ''
+        until kubectl auth can-i '*' '*' -q 2>/dev/null; do
+          echo kubectl auth can-i '*' '*': exit status $?
+          sleep 2
+        done
+
+        kubectl apply -f ${concatStringsSep " \\\n -f " files}
+      '';
+      script = "echo Ok";
+      unitConfig.ConditionPathExists = bootstrapAddonsPaths;
+    };
+
+    systemd.paths.kube-addon-manager-bootstrap = {
+      wantedBy = [ "kube-addon-manager-bootstrap.service" ];
+      pathConfig = {
+        PathExists = bootstrapAddonsPaths;
+        PathChanged = bootstrapAddonsPaths;
+      };
+    };
+
+    services.kubernetes.addonManager.bootstrapAddonsKubeconfig.server = mkDefault top.apiserverAddress;
+
     services.kubernetes.addonManager.bootstrapAddons = mkIf isRBACEnabled
     (let
       name = system:kube-addon-manager;
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/addons/dashboard.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/addons/dashboard.nix
index 454e7d35bc01..2295694ffc74 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/addons/dashboard.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/addons/dashboard.nix
@@ -169,6 +169,23 @@ in {
         };
       };
 
+      kubernetes-dashboard-cm = {
+        apiVersion = "v1";
+        kind = "ConfigMap";
+        metadata = {
+          labels = {
+            k8s-app = "kubernetes-dashboard";
+            # Allows editing resource and makes sure it is created first.
+            "addonmanager.kubernetes.io/mode" = "EnsureExists";
+          };
+          name = "kubernetes-dashboard-settings";
+          namespace = "kube-system";
+        };
+      };
+    };
+
+    services.kubernetes.addonManager.bootstrapAddons = mkMerge [{
+
       kubernetes-dashboard-sa = {
         apiVersion = "v1";
         kind = "ServiceAccount";
@@ -210,20 +227,9 @@ in {
         };
         type = "Opaque";
       };
-      kubernetes-dashboard-cm = {
-        apiVersion = "v1";
-        kind = "ConfigMap";
-        metadata = {
-          labels = {
-            k8s-app = "kubernetes-dashboard";
-            # Allows editing resource and makes sure it is created first.
-            "addonmanager.kubernetes.io/mode" = "EnsureExists";
-          };
-          name = "kubernetes-dashboard-settings";
-          namespace = "kube-system";
-        };
-      };
-    } // (optionalAttrs cfg.rbac.enable
+    }
+
+    (optionalAttrs cfg.rbac.enable
       (let
         subjects = [{
           kind = "ServiceAccount";
@@ -323,6 +329,6 @@ in {
             inherit subjects;
           };
         })
-    ));
+    ))];
   };
 }
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/apiserver.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/apiserver.nix
index 455d02396040..0c04648355b4 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/apiserver.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/apiserver.nix
@@ -184,6 +184,18 @@ in
       type = bool;
     };
 
+    proxyClientCertFile = mkOption {
+      description = "Client certificate to use for connections to proxy.";
+      default = null;
+      type = nullOr path;
+    };
+
+    proxyClientKeyFile = mkOption {
+      description = "Key to use for connections to proxy.";
+      default = null;
+      type = nullOr path;
+    };
+
     runtimeConfig = mkOption {
       description = ''
         Api runtime configuration. See
@@ -272,11 +284,32 @@ in
   ###### implementation
   config = mkMerge [
 
-    (mkIf cfg.enable {
+    (let
+
+      apiserverPaths = filter (a: a != null) [
+        cfg.clientCaFile
+        cfg.etcd.caFile
+        cfg.etcd.certFile
+        cfg.etcd.keyFile
+        cfg.kubeletClientCaFile
+        cfg.kubeletClientCertFile
+        cfg.kubeletClientKeyFile
+        cfg.serviceAccountKeyFile
+        cfg.tlsCertFile
+        cfg.tlsKeyFile
+      ];
+      etcdPaths = filter (a: a != null) [
+        config.services.etcd.trustedCaFile
+        config.services.etcd.certFile
+        config.services.etcd.keyFile
+      ];
+
+    in mkIf cfg.enable {
         systemd.services.kube-apiserver = {
           description = "Kubernetes APIServer Service";
-          wantedBy = [ "kubernetes.target" ];
-          after = [ "network.target" ];
+          wantedBy = [ "kube-control-plane-online.target" ];
+          after = [ "certmgr.service" ];
+          before = [ "kube-control-plane-online.target" ];
           serviceConfig = {
             Slice = "kubernetes.slice";
             ExecStart = ''${top.package}/bin/kube-apiserver \
@@ -316,6 +349,10 @@ in
                 "--kubelet-client-certificate=${cfg.kubeletClientCertFile}"} \
               ${optionalString (cfg.kubeletClientKeyFile != null)
                 "--kubelet-client-key=${cfg.kubeletClientKeyFile}"} \
+              ${optionalString (cfg.proxyClientCertFile != null)
+                "--proxy-client-cert-file=${cfg.proxyClientCertFile}"} \
+              ${optionalString (cfg.proxyClientKeyFile != null)
+                "--proxy-client-key-file=${cfg.proxyClientKeyFile}"} \
               --insecure-bind-address=${cfg.insecureBindAddress} \
               --insecure-port=${toString cfg.insecurePort} \
               ${optionalString (cfg.runtimeConfig != "")
@@ -341,6 +378,15 @@ in
             Restart = "on-failure";
             RestartSec = 5;
           };
+          unitConfig.ConditionPathExists = apiserverPaths;
+        };
+
+        systemd.paths.kube-apiserver = mkIf top.apiserver.enable {
+          wantedBy = [ "kube-apiserver.service" ];
+          pathConfig = {
+            PathExists = apiserverPaths;
+            PathChanged = apiserverPaths;
+          };
         };
 
         services.etcd = {
@@ -354,6 +400,18 @@ in
           initialAdvertisePeerUrls = mkDefault ["https://${top.masterAddress}:2380"];
         };
 
+        systemd.services.etcd = {
+          unitConfig.ConditionPathExists = etcdPaths;
+        };
+
+        systemd.paths.etcd = {
+          wantedBy = [ "etcd.service" ];
+          pathConfig = {
+            PathExists = etcdPaths;
+            PathChanged = etcdPaths;
+          };
+        };
+
         services.kubernetes.addonManager.bootstrapAddons = mkIf isRBACEnabled {
 
           apiserver-kubelet-api-admin-crb = {
@@ -389,6 +447,11 @@ in
                   ] ++ cfg.extraSANs;
           action = "systemctl restart kube-apiserver.service";
         };
+        apiserverProxyClient = mkCert {
+          name = "kube-apiserver-proxy-client";
+          CN = "front-proxy-client";
+          action = "systemctl restart kube-apiserver.service";
+        };
         apiserverKubeletClient = mkCert {
           name = "kube-apiserver-kubelet-client";
           CN = "system:kube-apiserver";
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/controller-manager.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/controller-manager.nix
index 060fd9b78db6..b94e8bd86d4c 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/controller-manager.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/controller-manager.nix
@@ -28,7 +28,7 @@ in
       type = str;
     };
 
-    enable = mkEnableOption "Kubernetes controller manager.";
+    enable = mkEnableOption "Kubernetes controller manager";
 
     extraOpts = mkOption {
       description = "Kubernetes controller manager extra command line options.";
@@ -104,11 +104,31 @@ in
   };
 
   ###### implementation
-  config = mkIf cfg.enable {
-    systemd.services.kube-controller-manager = {
+  config = let
+
+    controllerManagerPaths = filter (a: a != null) [
+      cfg.kubeconfig.caFile
+      cfg.kubeconfig.certFile
+      cfg.kubeconfig.keyFile
+      cfg.rootCaFile
+      cfg.serviceAccountKeyFile
+      cfg.tlsCertFile
+      cfg.tlsKeyFile
+    ];
+
+  in mkIf cfg.enable {
+    systemd.services.kube-controller-manager = rec {
       description = "Kubernetes Controller Manager Service";
-      wantedBy = [ "kubernetes.target" ];
+      wantedBy = [ "kube-control-plane-online.target" ];
       after = [ "kube-apiserver.service" ];
+      before = [ "kube-control-plane-online.target" ];
+      environment.KUBECONFIG = top.lib.mkKubeConfig "kube-controller-manager" cfg.kubeconfig;
+      preStart = ''
+        until kubectl auth can-i get /api -q 2>/dev/null; do
+          echo kubectl auth can-i get /api: exit status $?
+          sleep 2
+        done
+      '';
       serviceConfig = {
         RestartSec = "30s";
         Restart = "on-failure";
@@ -120,7 +140,7 @@ in
             "--cluster-cidr=${cfg.clusterCidr}"} \
           ${optionalString (cfg.featureGates != [])
             "--feature-gates=${concatMapStringsSep "," (feature: "${feature}=true") cfg.featureGates}"} \
-          --kubeconfig=${top.lib.mkKubeConfig "kube-controller-manager" cfg.kubeconfig} \
+          --kubeconfig=${environment.KUBECONFIG} \
           --leader-elect=${boolToString cfg.leaderElect} \
           ${optionalString (cfg.rootCaFile!=null)
             "--root-ca-file=${cfg.rootCaFile}"} \
@@ -141,7 +161,16 @@ in
         User = "kubernetes";
         Group = "kubernetes";
       };
-      path = top.path;
+      path = top.path ++ [ pkgs.kubectl ];
+      unitConfig.ConditionPathExists = controllerManagerPaths;
+    };
+
+    systemd.paths.kube-controller-manager = {
+      wantedBy = [ "kube-controller-manager.service" ];
+      pathConfig = {
+        PathExists = controllerManagerPaths;
+        PathChanged = controllerManagerPaths;
+      };
     };
 
     services.kubernetes.pki.certs = with top.lib; {
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix
index 3e53d18f8bbf..192c893f8a16 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix
@@ -263,6 +263,30 @@ in {
         wantedBy = [ "multi-user.target" ];
       };
 
+      systemd.targets.kube-control-plane-online = {
+        wantedBy = [ "kubernetes.target" ];
+        before = [ "kubernetes.target" ];
+      };
+
+      systemd.services.kube-control-plane-online = rec {
+        description = "Kubernetes control plane is online";
+        wantedBy = [ "kube-control-plane-online.target" ];
+        after = [ "kube-scheduler.service" "kube-controller-manager.service" ];
+        before = [ "kube-control-plane-online.target" ];
+        environment.KUBECONFIG = cfg.lib.mkKubeConfig "default" cfg.kubeconfig;
+        path = [ pkgs.kubectl ];
+        preStart = ''
+          until kubectl get --raw=/healthz 2>/dev/null; do
+            echo kubectl get --raw=/healthz: exit status $?
+            sleep 3
+          done
+        '';
+        script = "echo Ok";
+        serviceConfig = {
+          TimeoutSec = "500";
+        };
+      };
+
       systemd.tmpfiles.rules = [
         "d /opt/cni/bin 0755 root root -"
         "d /run/kubernetes 0755 kubernetes kubernetes -"
@@ -286,6 +310,8 @@ in {
       services.kubernetes.apiserverAddress = mkDefault ("https://${if cfg.apiserver.advertiseAddress != null
                           then cfg.apiserver.advertiseAddress
                           else "${cfg.masterAddress}:${toString cfg.apiserver.securePort}"}");
+
+      services.kubernetes.kubeconfig.server = mkDefault cfg.apiserverAddress;
     })
   ];
 }
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/flannel.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/flannel.nix
index 93ee2fd65eeb..d9437427d6d1 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/flannel.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/flannel.nix
@@ -23,17 +23,27 @@ in
 {
   ###### interface
   options.services.kubernetes.flannel = {
-    enable = mkEnableOption "enable flannel networking";
+    enable = mkEnableOption "flannel networking";
+    kubeconfig = top.lib.mkKubeConfigOptions "Kubernetes flannel";
   };
 
   ###### implementation
-  config = mkIf cfg.enable {
+  config = let
+
+    flannelPaths = filter (a: a != null) [
+      cfg.kubeconfig.caFile
+      cfg.kubeconfig.certFile
+      cfg.kubeconfig.keyFile
+    ];
+    kubeconfig = top.lib.mkKubeConfig "flannel" cfg.kubeconfig;
+
+  in mkIf cfg.enable {
     services.flannel = {
 
       enable = mkDefault true;
       network = mkDefault top.clusterCidr;
-      inherit storageBackend;
-      nodeName = config.services.kubernetes.kubelet.hostname;
+      inherit storageBackend kubeconfig;
+      nodeName = top.kubelet.hostname;
     };
 
     services.kubernetes.kubelet = {
@@ -48,24 +58,66 @@ in
       }];
     };
 
-    systemd.services."mk-docker-opts" = {
+    systemd.services.mk-docker-opts = {
       description = "Pre-Docker Actions";
+      wantedBy = [ "flannel.target" ];
+      before = [ "flannel.target" ];
       path = with pkgs; [ gawk gnugrep ];
       script = ''
         ${mkDockerOpts}/mk-docker-opts -d /run/flannel/docker
         systemctl restart docker
       '';
+      unitConfig.ConditionPathExists = [ "/run/flannel/subnet.env" ];
       serviceConfig.Type = "oneshot";
     };
 
-    systemd.paths."flannel-subnet-env" = {
-      wantedBy = [ "flannel.service" ];
+    systemd.paths.flannel-subnet-env = {
+      wantedBy = [ "mk-docker-opts.service" ];
       pathConfig = {
-        PathModified = "/run/flannel/subnet.env";
+        PathExists = [ "/run/flannel/subnet.env" ];
+        PathChanged = [ "/run/flannel/subnet.env" ];
         Unit = "mk-docker-opts.service";
       };
     };
 
+    systemd.targets.flannel = {
+      wantedBy = [ "kube-node-online.target" ];
+      before = [ "kube-node-online.target" ];
+    };
+
+    systemd.services.flannel = {
+      wantedBy = [ "flannel.target" ];
+      after = [ "kubelet.target" ];
+      before = [ "flannel.target" ];
+      path = with pkgs; [ iptables kubectl ];
+      environment.KUBECONFIG = kubeconfig;
+      preStart = let
+        args = [
+          "--selector=kubernetes.io/hostname=${top.kubelet.hostname}"
+          # flannel exits if node is not registered yet, before that there is no podCIDR
+          "--output=jsonpath={.items[0].spec.podCIDR}"
+          # if jsonpath cannot be resolved exit with status 1
+          "--allow-missing-template-keys=false"
+        ];
+      in ''
+        until kubectl get nodes ${concatStringsSep " " args} 2>/dev/null; do
+          echo Waiting for ${top.kubelet.hostname} to be RegisteredNode
+          sleep 1
+        done
+      '';
+      unitConfig.ConditionPathExists = flannelPaths;
+    };
+
+    systemd.paths.flannel = {
+      wantedBy = [ "flannel.service" ];
+      pathConfig = {
+        PathExists = flannelPaths;
+        PathChanged = flannelPaths;
+      };
+    };
+
+    services.kubernetes.flannel.kubeconfig.server = mkDefault top.apiserverAddress;
+
     systemd.services.docker = {
       environment.DOCKER_OPTS = "-b none";
       serviceConfig.EnvironmentFile = "-/run/flannel/docker";
@@ -92,7 +144,6 @@ in
 
     # give flannel som kubernetes rbac permissions if applicable
     services.kubernetes.addonManager.bootstrapAddons = mkIf ((storageBackend == "kubernetes") && (elem "RBAC" top.apiserver.authorizationMode)) {
-
       flannel-cr = {
         apiVersion = "rbac.authorization.k8s.io/v1beta1";
         kind = "ClusterRole";
@@ -128,7 +179,6 @@ in
           name = "flannel-client";
         }];
       };
-
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix
index c94bb28bf7fb..2a4a0624555d 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix
@@ -241,21 +241,28 @@ in
 
   ###### implementation
   config = mkMerge [
-    (mkIf cfg.enable {
+    (let
+
+      kubeletPaths = filter (a: a != null) [
+        cfg.kubeconfig.caFile
+        cfg.kubeconfig.certFile
+        cfg.kubeconfig.keyFile
+        cfg.clientCaFile
+        cfg.tlsCertFile
+        cfg.tlsKeyFile
+      ];
+
+    in mkIf cfg.enable {
       services.kubernetes.kubelet.seedDockerImages = [infraContainer];
 
       systemd.services.kubelet = {
         description = "Kubernetes Kubelet Service";
-        wantedBy = [ "kubernetes.target" ];
-        after = [ "network.target" "docker.service" "kube-apiserver.service" ];
+        wantedBy = [ "kubelet.target" ];
+        after = [ "kube-control-plane-online.target" ];
+        before = [ "kubelet.target" ];
         path = with pkgs; [ gitMinimal openssh docker utillinux iproute ethtool thin-provisioning-tools iptables socat ] ++ top.path;
         preStart = ''
-          ${concatMapStrings (img: ''
-            echo "Seeding docker image: ${img}"
-            docker load <${img}
-          '') cfg.seedDockerImages}
-
-          rm /opt/cni/bin/* || true
+          rm -f /opt/cni/bin/* || true
           ${concatMapStrings (package: ''
             echo "Linking cni package: ${package}"
             ln -fs ${package}/bin/* /opt/cni/bin
@@ -308,6 +315,56 @@ in
           '';
           WorkingDirectory = top.dataDir;
         };
+        unitConfig.ConditionPathExists = kubeletPaths;
+      };
+
+      systemd.paths.kubelet = {
+        wantedBy =  [ "kubelet.service" ];
+        pathConfig = {
+          PathExists = kubeletPaths;
+          PathChanged = kubeletPaths;
+        };
+      };
+
+      systemd.services.docker.before = [ "kubelet.service" ];
+
+      systemd.services.docker-seed-images = {
+        wantedBy = [ "docker.service" ];
+        after = [ "docker.service" ];
+        before = [ "kubelet.service" ];
+        path = with pkgs; [ docker ];
+        preStart = ''
+          ${concatMapStrings (img: ''
+            echo "Seeding docker image: ${img}"
+            docker load <${img}
+          '') cfg.seedDockerImages}
+        '';
+        script = "echo Ok";
+        serviceConfig.Type = "oneshot";
+        serviceConfig.RemainAfterExit = true;
+        serviceConfig.Slice = "kubernetes.slice";
+      };
+
+      systemd.services.kubelet-online = {
+        wantedBy = [ "kube-node-online.target" ];
+        after = [ "flannel.target" "kubelet.target" ];
+        before = [ "kube-node-online.target" ];
+        # it is complicated. flannel needs kubelet to run the pause container before
+        # it discusses the node CIDR with apiserver and afterwards configures and restarts
+        # dockerd. Until then prevent creating any pods because they have to be recreated anyway
+        # because the network of docker0 has been changed by flannel.
+        script = let
+          docker-env = "/run/flannel/docker";
+          flannel-date = "stat --print=%Y ${docker-env}";
+          docker-date = "systemctl show --property=ActiveEnterTimestamp --value docker";
+        in ''
+          until test -f ${docker-env} ; do sleep 1 ; done
+          while test `${flannel-date}` -gt `date +%s --date="$(${docker-date})"` ; do
+            sleep 1
+          done
+        '';
+        serviceConfig.Type = "oneshot";
+        serviceConfig.Slice = "kubernetes.slice";
       };
 
       # Allways include cni plugins
@@ -354,5 +411,16 @@ in
       };
     })
 
+    {
+      systemd.targets.kubelet = {
+        wantedBy = [ "kube-node-online.target" ];
+        before = [ "kube-node-online.target" ];
+      };
+
+      systemd.targets.kube-node-online = {
+        wantedBy = [ "kubernetes.target" ];
+        before = [ "kubernetes.target" ];
+      };
+    }
   ];
 }
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix
index 38deca23a990..32eacad9025f 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix
@@ -27,12 +27,11 @@ let
   certmgrAPITokenPath = "${top.secretsPath}/${cfsslAPITokenBaseName}";
   cfsslAPITokenLength = 32;
 
-  clusterAdminKubeconfig = with cfg.certs.clusterAdmin;
-    top.lib.mkKubeConfig "cluster-admin" {
-        server = top.apiserverAddress;
-        certFile = cert;
-        keyFile = key;
-    };
+  clusterAdminKubeconfig = with cfg.certs.clusterAdmin; {
+    server = top.apiserverAddress;
+    certFile = cert;
+    keyFile = key;
+  };
 
   remote = with config.services; "https://${kubernetes.masterAddress}:${toString cfssl.port}";
 in
@@ -40,7 +39,7 @@ in
   ###### interface
   options.services.kubernetes.pki = with lib.types; {
 
-    enable = mkEnableOption "Whether to enable easyCert issuer service.";
+    enable = mkEnableOption "easyCert issuer service";
 
     certs = mkOption {
       description = "List of certificate specs to feed to cert generator.";
@@ -119,6 +118,12 @@ in
     cfsslCertPathPrefix = "${config.services.cfssl.dataDir}/cfssl";
     cfsslCert = "${cfsslCertPathPrefix}.pem";
     cfsslKey = "${cfsslCertPathPrefix}-key.pem";
+    cfsslPort = toString config.services.cfssl.port;
+
+    certmgrPaths = [
+      top.caFile
+      certmgrAPITokenPath
+    ];
   in
   {
 
@@ -168,13 +173,40 @@ in
         chown cfssl "${cfsslAPITokenPath}" && chmod 400 "${cfsslAPITokenPath}"
       '')]);
 
+    systemd.targets.cfssl-online = {
+      wantedBy = [ "network-online.target" ];
+      after = [ "cfssl.service" "network-online.target" "cfssl-online.service" ];
+    };
+
+    systemd.services.cfssl-online = {
+      description = "Wait for ${remote} to be reachable.";
+      wantedBy = [ "cfssl-online.target" ];
+      before = [ "cfssl-online.target" ];
+      path = [ pkgs.curl ];
+      preStart = ''
+        until curl --fail-early -fskd '{}' ${remote}/api/v1/cfssl/info -o /dev/null; do
+          echo curl ${remote}/api/v1/cfssl/info: exit status $?
+          sleep 2
+        done
+      '';
+      script = "echo Ok";
+      serviceConfig = {
+        TimeoutSec = "300";
+      };
+    };
+
     systemd.services.kube-certmgr-bootstrap = {
       description = "Kubernetes certmgr bootstrapper";
-      wantedBy = [ "certmgr.service" ];
-      after = [ "cfssl.target" ];
+      wantedBy = [ "cfssl-online.target" ];
+      after = [ "cfssl-online.target" ];
+      before = [ "certmgr.service" ];
+      path = with pkgs; [ curl cfssl ];
       script = concatStringsSep "\n" [''
         set -e
 
+        mkdir -p $(dirname ${certmgrAPITokenPath})
+        mkdir -p $(dirname ${top.caFile})
+
         # If there's a cfssl (cert issuer) running locally, then don't rely on user to
         # manually paste it in place. Just symlink.
         # otherwise, create the target file, ready for users to insert the token
@@ -186,15 +218,18 @@ in
         fi
       ''
       (optionalString (cfg.pkiTrustOnBootstrap) ''
-        if [ ! -f "${top.caFile}" ] || [ $(cat "${top.caFile}" | wc -c) -lt 1 ]; then
-          ${pkgs.curl}/bin/curl --fail-early -f -kd '{}' ${remote}/api/v1/cfssl/info | \
-            ${pkgs.cfssl}/bin/cfssljson -stdout >${top.caFile}
+        if [ ! -s "${top.caFile}" ]; then
+          until test -s ${top.caFile}.json; do
+            sleep 2
+            curl --fail-early -fskd '{}' ${remote}/api/v1/cfssl/info -o ${top.caFile}.json
+          done
+          cfssljson -f ${top.caFile}.json -stdout >${top.caFile}
+          rm ${top.caFile}.json
         fi
       '')
       ];
       serviceConfig = {
-        RestartSec = "10s";
-        Restart = "on-failure";
+        TimeoutSec = "500";
       };
     };
 
@@ -230,35 +265,28 @@ in
           mapAttrs mkSpec cfg.certs;
       };
 
-      #TODO: Get rid of kube-addon-manager in the future for the following reasons
-      # - it is basically just a shell script wrapped around kubectl
-      # - it assumes that it is clusterAdmin or can gain clusterAdmin rights through serviceAccount
-      # - it is designed to be used with k8s system components only
-      # - it would be better with a more Nix-oriented way of managing addons
-      systemd.services.kube-addon-manager = mkIf top.addonManager.enable (mkMerge [{
-        environment.KUBECONFIG = with cfg.certs.addonManager;
-          top.lib.mkKubeConfig "addon-manager" {
-            server = top.apiserverAddress;
-            certFile = cert;
-            keyFile = key;
-          };
-        }
-
-        (optionalAttrs (top.addonManager.bootstrapAddons != {}) {
-          serviceConfig.PermissionsStartOnly = true;
-          preStart = with pkgs;
-          let
-            files = mapAttrsToList (n: v: writeText "${n}.json" (builtins.toJSON v))
-              top.addonManager.bootstrapAddons;
-          in
-          ''
-            export KUBECONFIG=${clusterAdminKubeconfig}
-            ${kubectl}/bin/kubectl apply -f ${concatStringsSep " \\\n -f " files}
-          '';
-        })]);
+      systemd.services.certmgr = {
+        wantedBy = [ "cfssl-online.target" ];
+        after = [ "cfssl-online.target" "kube-certmgr-bootstrap.service" ];
+        preStart = ''
+          while ! test -s ${certmgrAPITokenPath} ; do
+            sleep 1
+            echo Waiting for ${certmgrAPITokenPath}
+          done
+        '';
+        unitConfig.ConditionPathExists = certmgrPaths;
+      };
+
+      systemd.paths.certmgr = {
+        wantedBy = [ "certmgr.service" ];
+        pathConfig = {
+          PathExists = certmgrPaths;
+          PathChanged = certmgrPaths;
+        };
+      };
 
       environment.etc.${cfg.etcClusterAdminKubeconfig}.source = mkIf (!isNull cfg.etcClusterAdminKubeconfig)
-        clusterAdminKubeconfig;
+        (top.lib.mkKubeConfig "cluster-admin" clusterAdminKubeconfig);
 
       environment.systemPackages = mkIf (top.kubelet.enable || top.proxy.enable) [
       (pkgs.writeScriptBin "nixos-kubernetes-node-join" ''
@@ -284,38 +312,22 @@ in
           exit 1
         fi
 
+        do_restart=$(test -s ${certmgrAPITokenPath} && echo -n y || echo -n n)
+
         echo $token > ${certmgrAPITokenPath}
         chmod 600 ${certmgrAPITokenPath}
 
-        echo "Restarting certmgr..." >&1
-        systemctl restart certmgr
-
-        echo "Waiting for certs to appear..." >&1
-
-        ${optionalString top.kubelet.enable ''
-          while [ ! -f ${cfg.certs.kubelet.cert} ]; do sleep 1; done
-          echo "Restarting kubelet..." >&1
-          systemctl restart kubelet
-        ''}
-
-        ${optionalString top.proxy.enable ''
-          while [ ! -f ${cfg.certs.kubeProxyClient.cert} ]; do sleep 1; done
-          echo "Restarting kube-proxy..." >&1
-          systemctl restart kube-proxy
-        ''}
-
-        ${optionalString top.flannel.enable ''
-          while [ ! -f ${cfg.certs.flannelClient.cert} ]; do sleep 1; done
-          echo "Restarting flannel..." >&1
-          systemctl restart flannel
-        ''}
+        if [ y = $do_restart ]; then
+          echo "Restarting certmgr..." >&1
+          systemctl restart certmgr
+        fi
 
-        echo "Node joined succesfully"
+        echo "Node joined succesfully" >&1
       '')];
 
       # isolate etcd on loopback at the master node
       # easyCerts doesn't support multimaster clusters anyway atm.
-      services.etcd = with cfg.certs.etcd; {
+      services.etcd = mkIf top.apiserver.enable (with cfg.certs.etcd; {
         listenClientUrls = ["https://127.0.0.1:2379"];
         listenPeerUrls = ["https://127.0.0.1:2380"];
         advertiseClientUrls = ["https://etcd.local:2379"];
@@ -324,19 +336,11 @@ in
         certFile = mkDefault cert;
         keyFile = mkDefault key;
         trustedCaFile = mkDefault caCert;
-      };
+      });
       networking.extraHosts = mkIf (config.services.etcd.enable) ''
         127.0.0.1 etcd.${top.addons.dns.clusterDomain} etcd.local
       '';
 
-      services.flannel = with cfg.certs.flannelClient; {
-        kubeconfig = top.lib.mkKubeConfig "flannel" {
-          server = top.apiserverAddress;
-          certFile = cert;
-          keyFile = key;
-        };
-      };
-
       services.kubernetes = {
 
         apiserver = mkIf top.apiserver.enable (with cfg.certs.apiServer; {
@@ -353,7 +357,16 @@ in
           kubeletClientCaFile = mkDefault caCert;
           kubeletClientCertFile = mkDefault cfg.certs.apiserverKubeletClient.cert;
           kubeletClientKeyFile = mkDefault cfg.certs.apiserverKubeletClient.key;
+          proxyClientCertFile = mkDefault cfg.certs.apiserverProxyClient.cert;
+          proxyClientKeyFile = mkDefault cfg.certs.apiserverProxyClient.key;
         });
+        addonManager = mkIf top.addonManager.enable {
+          kubeconfig = with cfg.certs.addonManager; {
+            certFile = mkDefault cert;
+            keyFile = mkDefault key;
+          };
+          bootstrapAddonsKubeconfig = clusterAdminKubeconfig;
+        };
         controllerManager = mkIf top.controllerManager.enable {
           serviceAccountKeyFile = mkDefault cfg.certs.serviceAccount.key;
           rootCaFile = cfg.certs.controllerManagerClient.caCert;
@@ -362,6 +375,12 @@ in
             keyFile = mkDefault key;
           };
         };
+        flannel = mkIf top.flannel.enable {
+          kubeconfig = with cfg.certs.flannelClient; {
+            certFile = cert;
+            keyFile = key;
+          };
+        };
         scheduler = mkIf top.scheduler.enable {
           kubeconfig = with cfg.certs.schedulerClient; {
             certFile = mkDefault cert;
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix
index 83cd3e231000..23f4d97b7030 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix
@@ -17,7 +17,7 @@ in
       type = str;
     };
 
-    enable = mkEnableOption "Whether to enable Kubernetes proxy.";
+    enable = mkEnableOption "Kubernetes proxy";
 
     extraOpts = mkOption {
       description = "Kubernetes proxy extra command line options.";
@@ -45,12 +45,28 @@ in
   };
 
   ###### implementation
-  config = mkIf cfg.enable {
-    systemd.services.kube-proxy = {
+  config = let
+
+    proxyPaths = filter (a: a != null) [
+      cfg.kubeconfig.caFile
+      cfg.kubeconfig.certFile
+      cfg.kubeconfig.keyFile
+    ];
+
+  in mkIf cfg.enable {
+    systemd.services.kube-proxy = rec {
       description = "Kubernetes Proxy Service";
-      wantedBy = [ "kubernetes.target" ];
-      after = [ "kube-apiserver.service" ];
-      path = with pkgs; [ iptables conntrack_tools ];
+      wantedBy = [ "kube-node-online.target" ];
+      after = [ "kubelet-online.service" ];
+      before = [ "kube-node-online.target" ];
+      environment.KUBECONFIG = top.lib.mkKubeConfig "kube-proxy" cfg.kubeconfig;
+      path = with pkgs; [ iptables conntrack_tools kubectl ];
+      preStart = ''
+        until kubectl auth can-i get nodes/${top.kubelet.hostname} -q 2>/dev/null; do
+          echo kubectl auth can-i get nodes/${top.kubelet.hostname}: exit status $?
+          sleep 2
+        done
+      '';
       serviceConfig = {
         Slice = "kubernetes.slice";
         ExecStart = ''${top.package}/bin/kube-proxy \
@@ -59,7 +75,7 @@ in
             "--cluster-cidr=${top.clusterCidr}"} \
           ${optionalString (cfg.featureGates != [])
             "--feature-gates=${concatMapStringsSep "," (feature: "${feature}=true") cfg.featureGates}"} \
-          --kubeconfig=${top.lib.mkKubeConfig "kube-proxy" cfg.kubeconfig} \
+          --kubeconfig=${environment.KUBECONFIG} \
           ${optionalString (cfg.verbosity != null) "--v=${toString cfg.verbosity}"} \
           ${cfg.extraOpts}
         '';
@@ -67,6 +83,15 @@ in
         Restart = "on-failure";
         RestartSec = 5;
       };
+      unitConfig.ConditionPathExists = proxyPaths;
+    };
+
+    systemd.paths.kube-proxy = {
+      wantedBy = [ "kube-proxy.service" ];
+      pathConfig = {
+        PathExists = proxyPaths;
+        PathChanged = proxyPaths;
+      };
     };
 
     services.kubernetes.pki.certs = {
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/scheduler.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/scheduler.nix
index 0305b9aefe59..a0e484542951 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/scheduler.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/scheduler.nix
@@ -16,7 +16,7 @@ in
       type = str;
     };
 
-    enable = mkEnableOption "Whether to enable Kubernetes scheduler.";
+    enable = mkEnableOption "Kubernetes scheduler";
 
     extraOpts = mkOption {
       description = "Kubernetes scheduler extra command line options.";
@@ -56,18 +56,35 @@ in
   };
 
   ###### implementation
-  config = mkIf cfg.enable {
-    systemd.services.kube-scheduler = {
+  config =  let
+
+    schedulerPaths = filter (a: a != null) [
+      cfg.kubeconfig.caFile
+      cfg.kubeconfig.certFile
+      cfg.kubeconfig.keyFile
+    ];
+
+  in mkIf cfg.enable {
+    systemd.services.kube-scheduler = rec {
       description = "Kubernetes Scheduler Service";
-      wantedBy = [ "kubernetes.target" ];
+      wantedBy = [ "kube-control-plane-online.target" ];
       after = [ "kube-apiserver.service" ];
+      before = [ "kube-control-plane-online.target" ];
+      environment.KUBECONFIG = top.lib.mkKubeConfig "kube-scheduler" cfg.kubeconfig;
+      path = [ pkgs.kubectl ];
+      preStart = ''
+        until kubectl auth can-i get /api -q 2>/dev/null; do
+          echo kubectl auth can-i get /api: exit status $?
+          sleep 2
+        done
+      '';
       serviceConfig = {
         Slice = "kubernetes.slice";
         ExecStart = ''${top.package}/bin/kube-scheduler \
           --address=${cfg.address} \
           ${optionalString (cfg.featureGates != [])
             "--feature-gates=${concatMapStringsSep "," (feature: "${feature}=true") cfg.featureGates}"} \
-          --kubeconfig=${top.lib.mkKubeConfig "kube-scheduler" cfg.kubeconfig} \
+          --kubeconfig=${environment.KUBECONFIG} \
           --leader-elect=${boolToString cfg.leaderElect} \
           --port=${toString cfg.port} \
           ${optionalString (cfg.verbosity != null) "--v=${toString cfg.verbosity}"} \
@@ -79,6 +96,15 @@ in
         Restart = "on-failure";
         RestartSec = 5;
       };
+      unitConfig.ConditionPathExists = schedulerPaths;
+    };
+
+    systemd.paths.kube-scheduler = {
+      wantedBy = [ "kube-scheduler.service" ];
+      pathConfig = {
+        PathExists = schedulerPaths;
+        PathChanged = schedulerPaths;
+      };
     };
 
     services.kubernetes.pki.certs = {
diff --git a/nixpkgs/nixos/modules/services/databases/clickhouse.nix b/nixpkgs/nixos/modules/services/databases/clickhouse.nix
index 21e0cee34151..dbabcae43ee5 100644
--- a/nixpkgs/nixos/modules/services/databases/clickhouse.nix
+++ b/nixpkgs/nixos/modules/services/databases/clickhouse.nix
@@ -1,8 +1,6 @@
 { config, lib, pkgs, ... }:
 let
   cfg = config.services.clickhouse;
-  confDir = "/etc/clickhouse-server";
-  stateDir = "/var/lib/clickhouse";
 in
 with lib;
 {
@@ -43,20 +41,13 @@ with lib;
 
       after = [ "network.target" ];
 
-      preStart = ''
-        mkdir -p ${stateDir}
-        chown clickhouse:clickhouse ${confDir} ${stateDir}
-      '';
-
-      script = ''
-        cd "${confDir}"
-        exec ${pkgs.clickhouse}/bin/clickhouse-server
-      '';
-
       serviceConfig = {
         User = "clickhouse";
         Group = "clickhouse";
-        PermissionsStartOnly = true;
+        ConfigurationDirectory = "clickhouse-server";
+        StateDirectory = "clickhouse";
+        LogsDirectory = "clickhouse";
+        ExecStart = "${pkgs.clickhouse}/bin/clickhouse-server --config-file=${pkgs.clickhouse}/etc/clickhouse-server/config.xml";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/databases/couchdb.nix b/nixpkgs/nixos/modules/services/databases/couchdb.nix
index 84d108d9c747..5ddf8ba4bfbd 100644
--- a/nixpkgs/nixos/modules/services/databases/couchdb.nix
+++ b/nixpkgs/nixos/modules/services/databases/couchdb.nix
@@ -158,27 +158,21 @@ in {
     services.couchdb.configFile = mkDefault
       (if useVersion2 then "/var/lib/couchdb/local.ini" else "/var/lib/couchdb/couchdb.ini");
 
+    systemd.tmpfiles.rules = [
+      "d '${dirOf cfg.uriFile}' - ${cfg.user} ${cfg.group} - -"
+      "d '${dirOf cfg.logFile}' - ${cfg.user} ${cfg.group} - -"
+      "d '${cfg.databaseDir}' -  ${cfg.user} ${cfg.group} - -"
+      "d '${cfg.viewIndexDir}' -  ${cfg.user} ${cfg.group} - -"
+    ];
+
     systemd.services.couchdb = {
       description = "CouchDB Server";
       wantedBy = [ "multi-user.target" ];
 
       preStart =
         ''
-        mkdir -p `dirname ${cfg.uriFile}`;
-        mkdir -p `dirname ${cfg.logFile}`;
-        mkdir -p ${cfg.databaseDir};
-        mkdir -p ${cfg.viewIndexDir};
         touch ${cfg.configFile}
         touch -a ${cfg.logFile}
-
-        if [ "$(id -u)" = 0 ]; then
-          chown ${cfg.user}:${cfg.group} `dirname ${cfg.uriFile}`;
-          (test -f ${cfg.uriFile} && chown ${cfg.user}:${cfg.group} ${cfg.uriFile}) || true
-          chown ${cfg.user}:${cfg.group} ${cfg.databaseDir}
-          chown ${cfg.user}:${cfg.group} ${cfg.viewIndexDir}
-          chown ${cfg.user}:${cfg.group} ${cfg.configFile}
-          chown ${cfg.user}:${cfg.group} ${cfg.logFile}
-        fi
         '';
 
       environment = mkIf useVersion2 {
@@ -191,7 +185,6 @@ in {
       };
 
       serviceConfig = {
-        PermissionsStartOnly = true;
         User = cfg.user;
         Group = cfg.group;
         ExecStart = executable;
diff --git a/nixpkgs/nixos/modules/services/databases/influxdb.nix b/nixpkgs/nixos/modules/services/databases/influxdb.nix
index 888bf13c3df8..6868050c8446 100644
--- a/nixpkgs/nixos/modules/services/databases/influxdb.nix
+++ b/nixpkgs/nixos/modules/services/databases/influxdb.nix
@@ -157,20 +157,19 @@ in
 
   config = mkIf config.services.influxdb.enable {
 
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
+    ];
+
     systemd.services.influxdb = {
       description = "InfluxDB Server";
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
       serviceConfig = {
         ExecStart = ''${cfg.package}/bin/influxd -config "${configFile}"'';
-        User = "${cfg.user}";
-        Group = "${cfg.group}";
-        PermissionsStartOnly = true;
+        User = cfg.user;
+        Group = cfg.group;
       };
-      preStart = ''
-        mkdir -m 0770 -p ${cfg.dataDir}
-        if [ "$(id -u)" = 0 ]; then chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}; fi
-      '';
       postStart =
         let
           scheme = if configOptions.http.https-enabled then "-k https" else "http";
diff --git a/nixpkgs/nixos/modules/services/databases/memcached.nix b/nixpkgs/nixos/modules/services/databases/memcached.nix
index 7af452e4dced..052ff1f308eb 100644
--- a/nixpkgs/nixos/modules/services/databases/memcached.nix
+++ b/nixpkgs/nixos/modules/services/databases/memcached.nix
@@ -78,11 +78,6 @@ in
       after = [ "network.target" ];
 
       serviceConfig = {
-        PermissionsStartOnly = true;
-        ExecStartPre = optionals cfg.enableUnixSocket [
-          "${pkgs.coreutils}/bin/install -d -o ${cfg.user} /run/memcached/"
-          "${pkgs.coreutils}/bin/chown -R ${cfg.user} /run/memcached/"
-        ];
         ExecStart =
         let
           networking = if cfg.enableUnixSocket
@@ -91,12 +86,13 @@ in
         in "${memcached}/bin/memcached ${networking} -m ${toString cfg.maxMemory} -c ${toString cfg.maxConnections} ${concatStringsSep " " cfg.extraOptions}";
 
         User = cfg.user;
+        RuntimeDirectory = "memcached";
       };
     };
   };
   imports = [
     (mkRemovedOptionModule ["services" "memcached" "socket"] ''
-      This option was replaced by a fixed unix socket path at /run/memcached/memcached.sock enabled using services.memached.enableUnixSocket.
+      This option was replaced by a fixed unix socket path at /run/memcached/memcached.sock enabled using services.memcached.enableUnixSocket.
     '')
   ];
 
diff --git a/nixpkgs/nixos/modules/services/databases/stanchion.nix b/nixpkgs/nixos/modules/services/databases/stanchion.nix
index 9fe49f51edd2..97e55bc70c47 100644
--- a/nixpkgs/nixos/modules/services/databases/stanchion.nix
+++ b/nixpkgs/nixos/modules/services/databases/stanchion.nix
@@ -98,7 +98,7 @@ in
         type = types.path;
         default = "/var/log/stanchion";
         description = ''
-          Log directory for Stanchino.
+          Log directory for Stanchion.
         '';
       };
 
@@ -152,6 +152,11 @@ in
 
     users.groups.stanchion.gid = config.ids.gids.stanchion;
 
+    systemd.tmpfiles.rules = [
+      "d '${cfg.logDir}' - stanchion stanchion --"
+      "d '${cfg.dataDir}' 0700 stanchion stanchion --"
+    ];
+
     systemd.services.stanchion = {
       description = "Stanchion Server";
 
@@ -168,25 +173,12 @@ in
       environment.STANCHION_LOG_DIR = "${cfg.logDir}";
       environment.STANCHION_ETC_DIR = "/etc/stanchion";
 
-      preStart = ''
-        if ! test -e ${cfg.logDir}; then
-          mkdir -m 0755 -p ${cfg.logDir}
-          chown -R stanchion:stanchion ${cfg.logDir}
-        fi
-
-        if ! test -e ${cfg.dataDir}; then
-          mkdir -m 0700 -p ${cfg.dataDir}
-          chown -R stanchion:stanchion ${cfg.dataDir}
-        fi
-      '';
-
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/stanchion console";
         ExecStop = "${cfg.package}/bin/stanchion stop";
         StandardInput = "tty";
         User = "stanchion";
         Group = "stanchion";
-        PermissionsStartOnly = true;
         # Give Stanchion a decent amount of time to clean up.
         TimeoutStopSec = 120;
         LimitNOFILE = 65536;
diff --git a/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-settings-daemon.nix b/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-settings-daemon.nix
index dbf0f4e9b118..7f7adcf26acf 100644
--- a/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-settings-daemon.nix
+++ b/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-settings-daemon.nix
@@ -18,7 +18,7 @@ in
 
     services.gnome3.gnome-settings-daemon = {
 
-      enable = mkEnableOption "GNOME Settings Daemon.";
+      enable = mkEnableOption "GNOME Settings Daemon";
 
       # There are many forks of gnome-settings-daemon
       package = mkOption {
diff --git a/nixpkgs/nixos/modules/services/hardware/bluetooth.nix b/nixpkgs/nixos/modules/services/hardware/bluetooth.nix
index 2a8dfe4a66c9..c5f9d1f9b725 100644
--- a/nixpkgs/nixos/modules/services/hardware/bluetooth.nix
+++ b/nixpkgs/nixos/modules/services/hardware/bluetooth.nix
@@ -13,7 +13,7 @@ in {
   options = {
 
     hardware.bluetooth = {
-      enable = mkEnableOption "support for Bluetooth.";
+      enable = mkEnableOption "support for Bluetooth";
 
       powerOnBoot = mkOption {
         type    = types.bool;
diff --git a/nixpkgs/nixos/modules/services/hardware/vdr.nix b/nixpkgs/nixos/modules/services/hardware/vdr.nix
index 4822506a899b..6e246f70f515 100644
--- a/nixpkgs/nixos/modules/services/hardware/vdr.nix
+++ b/nixpkgs/nixos/modules/services/hardware/vdr.nix
@@ -12,7 +12,7 @@ in {
   options = {
 
     services.vdr = {
-      enable = mkEnableOption "enable VDR. Please put config into ${libDir}.";
+      enable = mkEnableOption "VDR. Please put config into ${libDir}";
 
       package = mkOption {
         type = types.package;
@@ -34,7 +34,7 @@ in {
         description = "Additional command line arguments to pass to VDR.";
       };
 
-      enableLirc = mkEnableOption "enable LIRC";
+      enableLirc = mkEnableOption "LIRC";
     };
   };
 
diff --git a/nixpkgs/nixos/modules/services/mail/mailcatcher.nix b/nixpkgs/nixos/modules/services/mail/mailcatcher.nix
index 2c6aadadce9d..fa8d41e918d3 100644
--- a/nixpkgs/nixos/modules/services/mail/mailcatcher.nix
+++ b/nixpkgs/nixos/modules/services/mail/mailcatcher.nix
@@ -11,7 +11,7 @@ in
   options = {
 
     services.mailcatcher = {
-      enable = mkEnableOption "Enable MailCatcher.";
+      enable = mkEnableOption "MailCatcher";
 
       http.ip = mkOption {
         type = types.str;
diff --git a/nixpkgs/nixos/modules/services/mail/nullmailer.nix b/nixpkgs/nixos/modules/services/mail/nullmailer.nix
index 418c02af4b7f..9997d287013e 100644
--- a/nixpkgs/nixos/modules/services/mail/nullmailer.nix
+++ b/nixpkgs/nixos/modules/services/mail/nullmailer.nix
@@ -212,6 +212,10 @@ with lib;
       };
     };
 
+    systemd.tmpfiles.rules = [
+      "d /var/spool/nullmailer - ${cfg.user} - - -"
+    ];
+
     systemd.services.nullmailer = {
       description = "nullmailer";
       wantedBy = [ "multi-user.target" ];
@@ -220,13 +224,11 @@ with lib;
       preStart = ''
         mkdir -p /var/spool/nullmailer/{queue,tmp}
         rm -f /var/spool/nullmailer/trigger && mkfifo -m 660 /var/spool/nullmailer/trigger
-        chown ${cfg.user} /var/spool/nullmailer/*
       '';
 
       serviceConfig = {
         User = cfg.user;
         Group = cfg.group;
-        PermissionsStartOnly=true;
         ExecStart = "${pkgs.nullmailer}/bin/nullmailer-send";
         Restart = "always";
       };
diff --git a/nixpkgs/nixos/modules/services/mail/offlineimap.nix b/nixpkgs/nixos/modules/services/mail/offlineimap.nix
index 4b24bd8d0813..294e3806f94a 100644
--- a/nixpkgs/nixos/modules/services/mail/offlineimap.nix
+++ b/nixpkgs/nixos/modules/services/mail/offlineimap.nix
@@ -7,7 +7,7 @@ let
 in {
 
   options.services.offlineimap = {
-    enable = mkEnableOption "Offlineimap, a software to dispose your mailbox(es) as a local Maildir(s).";
+    enable = mkEnableOption "OfflineIMAP, a software to dispose your mailbox(es) as a local Maildir(s)";
 
     install = mkOption {
       type = types.bool;
diff --git a/nixpkgs/nixos/modules/services/mail/rss2email.nix b/nixpkgs/nixos/modules/services/mail/rss2email.nix
index 5f3b2877008f..a123736005ab 100644
--- a/nixpkgs/nixos/modules/services/mail/rss2email.nix
+++ b/nixpkgs/nixos/modules/services/mail/rss2email.nix
@@ -94,6 +94,10 @@ in {
 
     services.rss2email.config.to = cfg.to;
 
+    systemd.tmpfiles.rules = [
+      "d /var/rss2email 0700 rss2email rss2email - -"
+    ];
+
     systemd.services.rss2email = let
       conf = pkgs.writeText "rss2email.cfg" (lib.generators.toINI {} ({
           DEFAULT = cfg.config;
@@ -105,22 +109,16 @@ in {
     in
     {
       preStart = ''
-        mkdir -p /var/rss2email
-        chmod 700 /var/rss2email
-
         cp ${conf} /var/rss2email/conf.cfg
         if [ ! -f /var/rss2email/db.json ]; then
           echo '{"version":2,"feeds":[]}' > /var/rss2email/db.json
         fi
-
-        chown -R rss2email:rss2email /var/rss2email
       '';
       path = [ pkgs.system-sendmail ];
       serviceConfig = {
         ExecStart =
           "${pkgs.rss2email}/bin/r2e -c /var/rss2email/conf.cfg -d /var/rss2email/db.json run";
         User = "rss2email";
-        PermissionsStartOnly = "true";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/misc/beanstalkd.nix b/nixpkgs/nixos/modules/services/misc/beanstalkd.nix
index 8a3e0ab1949a..06e881406b52 100644
--- a/nixpkgs/nixos/modules/services/misc/beanstalkd.nix
+++ b/nixpkgs/nixos/modules/services/misc/beanstalkd.nix
@@ -12,7 +12,7 @@ in
 
   options = {
     services.beanstalkd = {
-      enable = mkEnableOption "Enable the Beanstalk work queue.";
+      enable = mkEnableOption "the Beanstalk work queue";
 
       listen = {
         port = mkOption {
diff --git a/nixpkgs/nixos/modules/services/misc/etcd.nix b/nixpkgs/nixos/modules/services/misc/etcd.nix
index 2d1893dae64b..e4d5322f9b5f 100644
--- a/nixpkgs/nixos/modules/services/misc/etcd.nix
+++ b/nixpkgs/nixos/modules/services/misc/etcd.nix
@@ -142,6 +142,10 @@ in {
   };
 
   config = mkIf cfg.enable {
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' 0700 etcd - - -"
+    ];
+
     systemd.services.etcd = {
       description = "etcd key-value store";
       wantedBy = [ "multi-user.target" ];
@@ -176,14 +180,8 @@ in {
         Type = "notify";
         ExecStart = "${pkgs.etcd.bin}/bin/etcd";
         User = "etcd";
-        PermissionsStartOnly = true;
         LimitNOFILE = 40000;
       };
-
-      preStart = ''
-        mkdir -m 0700 -p ${cfg.dataDir}
-        if [ "$(id -u)" = 0 ]; then chown etcd ${cfg.dataDir}; fi
-      '';
     };
 
     environment.systemPackages = [ pkgs.etcdctl ];
diff --git a/nixpkgs/nixos/modules/services/misc/jackett.nix b/nixpkgs/nixos/modules/services/misc/jackett.nix
index b18ce2b1f81a..a07f20e5c24b 100644
--- a/nixpkgs/nixos/modules/services/misc/jackett.nix
+++ b/nixpkgs/nixos/modules/services/misc/jackett.nix
@@ -38,24 +38,19 @@ in
   };
 
   config = mkIf cfg.enable {
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -"
+    ];
+
     systemd.services.jackett = {
       description = "Jackett";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        test -d ${cfg.dataDir} || {
-          echo "Creating jackett data directory in ${cfg.dataDir}"
-          mkdir -p ${cfg.dataDir}
-        }
-        chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}
-        chmod 0700 ${cfg.dataDir}
-      '';
 
       serviceConfig = {
         Type = "simple";
         User = cfg.user;
         Group = cfg.group;
-        PermissionsStartOnly = "true";
         ExecStart = "${pkgs.jackett}/bin/Jackett --NoUpdates --DataFolder '${cfg.dataDir}'";
         Restart = "on-failure";
       };
diff --git a/nixpkgs/nixos/modules/services/misc/lidarr.nix b/nixpkgs/nixos/modules/services/misc/lidarr.nix
index 627f22334fe8..f466402abfc7 100644
--- a/nixpkgs/nixos/modules/services/misc/lidarr.nix
+++ b/nixpkgs/nixos/modules/services/misc/lidarr.nix
@@ -17,20 +17,15 @@ in
       description = "Lidarr";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        [ ! -d /var/lib/lidarr ] && mkdir -p /var/lib/lidarr
-        chown -R lidarr:lidarr /var/lib/lidarr
-      '';
 
       serviceConfig = {
         Type = "simple";
         User = "lidarr";
         Group = "lidarr";
-        PermissionsStartOnly = "true";
         ExecStart = "${pkgs.lidarr}/bin/Lidarr";
         Restart = "on-failure";
 
-        StateDirectory = "/var/lib/lidarr/";
+        StateDirectory = "lidarr";
         StateDirectoryMode = "0770";
       };
     };
diff --git a/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix b/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix
index 5e465926b832..00c8e7408030 100644
--- a/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix
+++ b/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix
@@ -554,7 +554,10 @@ in {
       };
       trusted_third_party_id_servers = mkOption {
         type = types.listOf types.str;
-        default = ["matrix.org"];
+        default = [
+          "matrix.org"
+          "vector.im"
+        ];
         description = ''
           The list of identity servers trusted to verify third party identifiers by this server.
         '';
diff --git a/nixpkgs/nixos/modules/services/misc/mesos-master.nix b/nixpkgs/nixos/modules/services/misc/mesos-master.nix
index 0523c6549ed6..572a9847e46c 100644
--- a/nixpkgs/nixos/modules/services/misc/mesos-master.nix
+++ b/nixpkgs/nixos/modules/services/misc/mesos-master.nix
@@ -95,6 +95,9 @@ in {
 
 
   config = mkIf cfg.enable {
+    systemd.tmpfiles.rules = [
+      "d '${cfg.workDir}' 0700 - - - -"
+    ];
     systemd.services.mesos-master = {
       description = "Mesos Master";
       wantedBy = [ "multi-user.target" ];
@@ -114,11 +117,7 @@ in {
             ${toString cfg.extraCmdLineOptions}
         '';
         Restart = "on-failure";
-        PermissionsStartOnly = true;
       };
-      preStart = ''
-        mkdir -m 0700 -p ${cfg.workDir}
-      '';
     };
   };
 
diff --git a/nixpkgs/nixos/modules/services/misc/mesos-slave.nix b/nixpkgs/nixos/modules/services/misc/mesos-slave.nix
index 468c7f36ecc5..170065d0065e 100644
--- a/nixpkgs/nixos/modules/services/misc/mesos-slave.nix
+++ b/nixpkgs/nixos/modules/services/misc/mesos-slave.nix
@@ -184,6 +184,9 @@ in {
   };
 
   config = mkIf cfg.enable {
+    systemd.tmpfiles.rules = [
+      "d '${cfg.workDir}' 0701 - - - -"
+    ];
     systemd.services.mesos-slave = {
       description = "Mesos Slave";
       wantedBy = [ "multi-user.target" ];
@@ -210,11 +213,7 @@ in {
             --executor_environment_variables=${lib.escapeShellArg (builtins.toJSON cfg.executorEnvironmentVariables)} \
             ${toString cfg.extraCmdLineOptions}
         '';
-        PermissionsStartOnly = true;
       };
-      preStart = ''
-        mkdir -m 0701 -p ${cfg.workDir}
-      '';
     };
   };
 
diff --git a/nixpkgs/nixos/modules/services/misc/plex.nix b/nixpkgs/nixos/modules/services/misc/plex.nix
index fce9b29011f1..7efadf1b9bb1 100644
--- a/nixpkgs/nixos/modules/services/misc/plex.nix
+++ b/nixpkgs/nixos/modules/services/misc/plex.nix
@@ -10,35 +10,38 @@ in
     services.plex = {
       enable = mkEnableOption "Plex Media Server";
 
-      # FIXME: In order for this config option to work, symlinks in the Plex
-      # package in the Nix store have to be changed to point to this directory.
       dataDir = mkOption {
         type = types.str;
         default = "/var/lib/plex";
-        description = "The directory where Plex stores its data files.";
+        description = ''
+          The directory where Plex stores its data files.
+        '';
       };
 
       openFirewall = mkOption {
         type = types.bool;
         default = false;
         description = ''
-          Open ports in the firewall for the media server
+          Open ports in the firewall for the media server.
         '';
       };
 
       user = mkOption {
         type = types.str;
         default = "plex";
-        description = "User account under which Plex runs.";
+        description = ''
+          User account under which Plex runs.
+        '';
       };
 
       group = mkOption {
         type = types.str;
         default = "plex";
-        description = "Group under which Plex runs.";
+        description = ''
+          Group under which Plex runs.
+        '';
       };
 
-
       managePlugins = mkOption {
         type = types.bool;
         default = true;
@@ -80,73 +83,48 @@ in
       description = "Plex Media Server";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        test -d "${cfg.dataDir}/Plex Media Server" || {
-          echo "Creating initial Plex data directory in \"${cfg.dataDir}\"."
-          mkdir -p "${cfg.dataDir}/Plex Media Server"
-          chown -R ${cfg.user}:${cfg.group} "${cfg.dataDir}"
-        }
-
-        # Copy the database skeleton files to /var/lib/plex/.skeleton
-        # See the the Nix expression for Plex's package for more information on
-        # why this is done.
-        install --owner ${cfg.user} --group ${cfg.group} -d "${cfg.dataDir}/.skeleton"
-        for db in "com.plexapp.plugins.library.db"; do
-            if [ ! -e  "${cfg.dataDir}/.skeleton/$db" ]; then
-              cp "${cfg.package}/usr/lib/plexmediaserver/Resources/base_$db" "${cfg.dataDir}/.skeleton/$db"
-            fi
-            chmod u+w "${cfg.dataDir}/.skeleton/$db"
-            chown ${cfg.user}:${cfg.group} "${cfg.dataDir}/.skeleton/$db"
-        done
-
-        # If managePlugins is enabled, setup symlinks for plugins.
-        ${optionalString cfg.managePlugins ''
-          echo "Preparing plugin directory."
-          PLUGINDIR="${cfg.dataDir}/Plex Media Server/Plug-ins"
-          test -d "$PLUGINDIR" || {
-            mkdir -p "$PLUGINDIR";
-            chown ${cfg.user}:${cfg.group} "$PLUGINDIR";
-          }
-
-          echo "Removing old symlinks."
-          # First, remove all of the symlinks in the directory.
-          for f in `ls "$PLUGINDIR/"`; do
-            if [[ -L "$PLUGINDIR/$f" ]]; then
-              echo "Removing plugin symlink $PLUGINDIR/$f."
-              rm "$PLUGINDIR/$f"
-            fi
-          done
-
-          echo "Symlinking plugins."
-          for path in ${toString cfg.extraPlugins}; do
-            dest="$PLUGINDIR/$(basename $path)"
-            if [[ ! -d "$path" ]]; then
-              echo "Error symlinking plugin from $path: no such directory."
-            elif [[ -d "$dest" || -L "$dest" ]]; then
-              echo "Error symlinking plugin from $path to $dest: file or directory already exists."
-            else
-              echo "Symlinking plugin at $path..."
-              ln -s "$path" "$dest"
-            fi
-          done
-        ''}
-     '';
+
       serviceConfig = {
         Type = "simple";
         User = cfg.user;
         Group = cfg.group;
-        PermissionsStartOnly = "true";
-        ExecStart = "\"${cfg.package}/usr/lib/plexmediaserver/Plex Media Server\"";
+
+        # Run the pre-start script with full permissions (the "!" prefix) so it
+        # can create the data directory if necessary.
+        ExecStartPre = let
+          preStartScript = pkgs.writeScript "plex-run-prestart" ''
+            #!${pkgs.bash}/bin/bash
+
+            # Create data directory if it doesn't exist
+            if ! test -d "$PLEX_DATADIR"; then
+              echo "Creating initial Plex data directory in: $PLEX_DATADIR"
+              install -d -m 0755 -o "${cfg.user}" -g "${cfg.group}" "$PLEX_DATADIR"
+            fi
+         '';
+        in
+          "!${preStartScript}";
+
+        ExecStart = "${cfg.package}/bin/plexmediaserver";
         KillSignal = "SIGQUIT";
         Restart = "on-failure";
       };
+
       environment = {
-        PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR=cfg.dataDir;
-        PLEX_MEDIA_SERVER_HOME="${cfg.package}/usr/lib/plexmediaserver";
+        # Configuration for our FHS userenv script
+        PLEX_DATADIR=cfg.dataDir;
+        PLEX_PLUGINS=concatMapStringsSep ":" builtins.toString cfg.extraPlugins;
+
+        # The following variables should be set by the FHS userenv script:
+        #   PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR
+        #   PLEX_MEDIA_SERVER_HOME
+
+        # Allow access to GPU acceleration; the Plex LD_LIBRARY_PATH is added
+        # by the FHS userenv script.
+        LD_LIBRARY_PATH="/run/opengl-driver/lib";
+
         PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS="6";
         PLEX_MEDIA_SERVER_TMPDIR="/tmp";
         PLEX_MEDIA_SERVER_USE_SYSLOG="true";
-        LD_LIBRARY_PATH="/run/opengl-driver/lib:${cfg.package}/usr/lib/plexmediaserver/lib";
         LC_ALL="en_US.UTF-8";
         LANG="en_US.UTF-8";
       };
diff --git a/nixpkgs/nixos/modules/services/misc/radarr.nix b/nixpkgs/nixos/modules/services/misc/radarr.nix
index 9ab26d848325..74444e24043f 100644
--- a/nixpkgs/nixos/modules/services/misc/radarr.nix
+++ b/nixpkgs/nixos/modules/services/misc/radarr.nix
@@ -38,24 +38,19 @@ in
   };
 
   config = mkIf cfg.enable {
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -"
+    ];
+
     systemd.services.radarr = {
       description = "Radarr";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        test -d ${cfg.dataDir} || {
-          echo "Creating radarr data directory in ${cfg.dataDir}"
-          mkdir -p ${cfg.dataDir}
-        }
-        chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}
-        chmod 0700 ${cfg.dataDir}
-      '';
 
       serviceConfig = {
         Type = "simple";
         User = cfg.user;
         Group = cfg.group;
-        PermissionsStartOnly = "true";
         ExecStart = "${pkgs.radarr}/bin/Radarr -nobrowser -data='${cfg.dataDir}'";
         Restart = "on-failure";
       };
diff --git a/nixpkgs/nixos/modules/services/misc/sonarr.nix b/nixpkgs/nixos/modules/services/misc/sonarr.nix
index a99445a268d7..77c7f0582d0b 100644
--- a/nixpkgs/nixos/modules/services/misc/sonarr.nix
+++ b/nixpkgs/nixos/modules/services/misc/sonarr.nix
@@ -39,24 +39,19 @@ in
   };
 
   config = mkIf cfg.enable {
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -"
+    ];
+
     systemd.services.sonarr = {
       description = "Sonarr";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        test -d ${cfg.dataDir} || {
-          echo "Creating sonarr data directory in ${cfg.dataDir}"
-          mkdir -p ${cfg.dataDir}
-        }
-        chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}
-        chmod 0700 ${cfg.dataDir}
-      '';
 
       serviceConfig = {
         Type = "simple";
         User = cfg.user;
         Group = cfg.group;
-        PermissionsStartOnly = "true";
         ExecStart = "${pkgs.sonarr}/bin/NzbDrone -nobrowser -data='${cfg.dataDir}'";
         Restart = "on-failure";
       };
diff --git a/nixpkgs/nixos/modules/services/misc/sssd.nix b/nixpkgs/nixos/modules/services/misc/sssd.nix
index fe472a6c68e5..6b64045dde88 100644
--- a/nixpkgs/nixos/modules/services/misc/sssd.nix
+++ b/nixpkgs/nixos/modules/services/misc/sssd.nix
@@ -6,7 +6,7 @@ let
 in {
   options = {
     services.sssd = {
-      enable = mkEnableOption "the System Security Services Daemon.";
+      enable = mkEnableOption "the System Security Services Daemon";
 
       config = mkOption {
         type = types.lines;
diff --git a/nixpkgs/nixos/modules/services/misc/zookeeper.nix b/nixpkgs/nixos/modules/services/misc/zookeeper.nix
index cb7cc97d5a5c..50c84e3c6b80 100644
--- a/nixpkgs/nixos/modules/services/misc/zookeeper.nix
+++ b/nixpkgs/nixos/modules/services/misc/zookeeper.nix
@@ -119,6 +119,10 @@ in {
   config = mkIf cfg.enable {
     environment.systemPackages = [cfg.package];
 
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' 0700 zookeeper - - -"
+    ];
+
     systemd.services.zookeeper = {
       description = "Zookeeper Daemon";
       wantedBy = [ "multi-user.target" ];
@@ -135,11 +139,8 @@ in {
             ${configDir}/zoo.cfg
         '';
         User = "zookeeper";
-        PermissionsStartOnly = true;
       };
       preStart = ''
-        mkdir -m 0700 -p ${cfg.dataDir}
-        if [ "$(id -u)" = 0 ]; then chown zookeeper ${cfg.dataDir}; fi
         echo "${toString cfg.id}" > ${cfg.dataDir}/myid
       '';
     };
diff --git a/nixpkgs/nixos/modules/services/monitoring/collectd.nix b/nixpkgs/nixos/modules/services/monitoring/collectd.nix
index 45e3312c0f44..6a4c678eb21f 100644
--- a/nixpkgs/nixos/modules/services/monitoring/collectd.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/collectd.nix
@@ -79,6 +79,10 @@ in {
   };
 
   config = mkIf cfg.enable {
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' - ${cfg.user} - - -"
+    ];
+
     systemd.services.collectd = {
       description = "Collectd Monitoring Agent";
       after = [ "network.target" ];
@@ -87,16 +91,9 @@ in {
       serviceConfig = {
         ExecStart = "${cfg.package}/sbin/collectd -C ${conf} -f";
         User = cfg.user;
-        PermissionsStartOnly = true;
         Restart = "on-failure";
         RestartSec = 3;
       };
-
-      preStart = ''
-        mkdir -p "${cfg.dataDir}"
-        chmod 755 "${cfg.dataDir}"
-        chown -R ${cfg.user} "${cfg.dataDir}"
-      '';
     };
 
     users.users = optional (cfg.user == "collectd") {
diff --git a/nixpkgs/nixos/modules/services/monitoring/graphite.nix b/nixpkgs/nixos/modules/services/monitoring/graphite.nix
index f59bc56962b1..2365142af40e 100644
--- a/nixpkgs/nixos/modules/services/monitoring/graphite.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/graphite.nix
@@ -123,7 +123,7 @@ in {
           graphite carbon.
 
           For more information visit
-          <link xlink:href="http://graphite-api.readthedocs.org/en/latest/"/>
+          <link xlink:href="https://graphite-api.readthedocs.org/en/latest/"/>
         '';
         default = false;
         type = types.bool;
diff --git a/nixpkgs/nixos/modules/services/monitoring/munin.nix b/nixpkgs/nixos/modules/services/monitoring/munin.nix
index f67986327245..ffe223fedbe1 100644
--- a/nixpkgs/nixos/modules/services/monitoring/munin.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/munin.nix
@@ -8,7 +8,7 @@
 # spawn-fcgi -s /run/munin/fastcgi-graph.sock -U www-data   -u munin -g munin /usr/lib/munin/cgi/munin-cgi-graph
 # spawn-fcgi -s /run/munin/fastcgi-html.sock  -U www-data   -u munin -g munin /usr/lib/munin/cgi/munin-cgi-html
 # https://paste.sh/vofcctHP#-KbDSXVeWoifYncZmLfZzgum
-# nginx http://munin.readthedocs.org/en/latest/example/webserver/nginx.html
+# nginx https://munin.readthedocs.org/en/latest/example/webserver/nginx.html
 
 
 with lib;
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
index e7ac12c07d33..d8384e0d35b3 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
@@ -22,9 +22,6 @@ let
   workingDir  = stateDirBase + stateDir;
   workingDir2 = stateDirBase + cfg2.stateDir;
 
-  # Get a submodule without any embedded metadata:
-  _filter = x: filterAttrs (k: v: k != "_module") x;
-
   # a wrapper that verifies that the configuration is valid
   promtoolCheck = what: name: file: pkgs.runCommand "${name}-${what}-checked"
     { buildInputs = [ cfg.package ]; } ''
@@ -50,11 +47,11 @@ let
 
   # This becomes the main config file for Prometheus 1
   promConfig = {
-    global = cfg.globalConfig;
+    global = filterValidPrometheus cfg.globalConfig;
     rule_files = map (promtoolCheck "check-rules" "rules") (cfg.ruleFiles ++ [
       (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules))
     ]);
-    scrape_configs = filterEmpty cfg.scrapeConfigs;
+    scrape_configs = filterValidPrometheus cfg.scrapeConfigs;
   };
 
   generatedPrometheusYml = writePrettyJSON "prometheus.yml" promConfig;
@@ -77,11 +74,11 @@ let
 
   # This becomes the main config file for Prometheus 2
   promConfig2 = {
-    global = cfg2.globalConfig;
+    global = filterValidPrometheus cfg2.globalConfig;
     rule_files = map (prom2toolCheck "check rules" "rules") (cfg2.ruleFiles ++ [
       (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg2.rules))
     ]);
-    scrape_configs = filterEmpty cfg2.scrapeConfigs;
+    scrape_configs = filterValidPrometheus cfg2.scrapeConfigs;
     alerting = optionalAttrs (cfg2.alertmanagerURL != []) {
       alertmanagers = [{
         static_configs = [{
@@ -108,7 +105,7 @@ let
   ] ++
   optional (cfg2.webExternalUrl != null) "--web.external-url=${cfg2.webExternalUrl}";
 
-  filterEmpty = filterAttrsListRecursive (_n: v: !(v == null || v == [] || v == {}));
+  filterValidPrometheus = filterAttrsListRecursive (n: v: !(n == "_module" || v == null));
   filterAttrsListRecursive = pred: x:
     if isAttrs x then
       listToAttrs (
@@ -123,41 +120,37 @@ let
       map (filterAttrsListRecursive pred) x
     else x;
 
-  promTypes.globalConfig = types.submodule {
-    options = {
-      scrape_interval = mkOption {
-        type = types.str;
-        default = "1m";
-        description = ''
-          How frequently to scrape targets by default.
-        '';
-      };
+  mkDefOpt = type : defaultStr : description : mkOpt type (description + ''
 
-      scrape_timeout = mkOption {
-        type = types.str;
-        default = "10s";
-        description = ''
-          How long until a scrape request times out.
-        '';
-      };
+    Defaults to <literal>${defaultStr}</literal> in prometheus
+    when set to <literal>null</literal>.
+  '');
 
-      evaluation_interval = mkOption {
-        type = types.str;
-        default = "1m";
-        description = ''
-          How frequently to evaluate rules by default.
-        '';
-      };
+  mkOpt = type : description : mkOption {
+    type = types.nullOr type;
+    default = null;
+    inherit description;
+  };
 
-      external_labels = mkOption {
-        type = types.attrsOf types.str;
-        description = ''
-          The labels to add to any time series or alerts when
-          communicating with external systems (federation, remote
-          storage, Alertmanager).
-        '';
-        default = {};
-      };
+  promTypes.globalConfig = types.submodule {
+    options = {
+      scrape_interval = mkDefOpt types.str "1m" ''
+        How frequently to scrape targets by default.
+      '';
+
+      scrape_timeout = mkDefOpt types.str "10s" ''
+        How long until a scrape request times out.
+      '';
+
+      evaluation_interval = mkDefOpt types.str "1m" ''
+        How frequently to evaluate rules by default.
+      '';
+
+      external_labels = mkOpt (types.attrsOf types.str) ''
+        The labels to add to any time series or alerts when
+        communicating with external systems (federation, remote
+        storage, Alertmanager).
+      '';
     };
   };
 
@@ -169,145 +162,127 @@ let
           The job name assigned to scraped metrics by default.
         '';
       };
-      scrape_interval = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          How frequently to scrape targets from this job. Defaults to the
-          globally configured default.
-        '';
-      };
-      scrape_timeout = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          Per-target timeout when scraping this job. Defaults to the
-          globally configured default.
-        '';
-      };
-      metrics_path = mkOption {
-        type = types.str;
-        default = "/metrics";
-        description = ''
-          The HTTP resource path on which to fetch metrics from targets.
-        '';
-      };
-      honor_labels = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Controls how Prometheus handles conflicts between labels
-          that are already present in scraped data and labels that
-          Prometheus would attach server-side ("job" and "instance"
-          labels, manually configured target labels, and labels
-          generated by service discovery implementations).
-
-          If honor_labels is set to "true", label conflicts are
-          resolved by keeping label values from the scraped data and
-          ignoring the conflicting server-side labels.
-
-          If honor_labels is set to "false", label conflicts are
-          resolved by renaming conflicting labels in the scraped data
-          to "exported_&lt;original-label&gt;" (for example
-          "exported_instance", "exported_job") and then attaching
-          server-side labels. This is useful for use cases such as
-          federation, where all labels specified in the target should
-          be preserved.
-        '';
-      };
-      scheme = mkOption {
-        type = types.enum ["http" "https"];
-        default = "http";
-        description = ''
-          The URL scheme with which to fetch metrics from targets.
-        '';
-      };
-      params = mkOption {
-        type = types.attrsOf (types.listOf types.str);
-        default = {};
-        description = ''
-          Optional HTTP URL parameters.
-        '';
-      };
-      basic_auth = mkOption {
-        type = types.nullOr (types.submodule {
-          options = {
-            username = mkOption {
-              type = types.str;
-              description = ''
-                HTTP username
-              '';
-            };
-            password = mkOption {
-              type = types.str;
-              description = ''
-                HTTP password
-              '';
-            };
+      scrape_interval = mkOpt types.str ''
+        How frequently to scrape targets from this job. Defaults to the
+        globally configured default.
+      '';
+
+      scrape_timeout = mkOpt types.str ''
+        Per-target timeout when scraping this job. Defaults to the
+        globally configured default.
+      '';
+
+      metrics_path = mkDefOpt types.str "/metrics" ''
+        The HTTP resource path on which to fetch metrics from targets.
+      '';
+
+      honor_labels = mkDefOpt types.bool "false" ''
+        Controls how Prometheus handles conflicts between labels
+        that are already present in scraped data and labels that
+        Prometheus would attach server-side ("job" and "instance"
+        labels, manually configured target labels, and labels
+        generated by service discovery implementations).
+
+        If honor_labels is set to "true", label conflicts are
+        resolved by keeping label values from the scraped data and
+        ignoring the conflicting server-side labels.
+
+        If honor_labels is set to "false", label conflicts are
+        resolved by renaming conflicting labels in the scraped data
+        to "exported_&lt;original-label&gt;" (for example
+        "exported_instance", "exported_job") and then attaching
+        server-side labels. This is useful for use cases such as
+        federation, where all labels specified in the target should
+        be preserved.
+      '';
+
+      honor_timestamps = mkDefOpt types.bool "true" ''
+        honor_timestamps controls whether Prometheus respects the timestamps present
+        in scraped data.
+
+        If honor_timestamps is set to <literal>true</literal>, the timestamps of the metrics exposed
+        by the target will be used.
+
+        If honor_timestamps is set to <literal>false</literal>, the timestamps of the metrics exposed
+        by the target will be ignored.
+      '';
+
+      scheme = mkDefOpt (types.enum ["http" "https"]) "http" ''
+        The URL scheme with which to fetch metrics from targets.
+      '';
+
+      params = mkOpt (types.attrsOf (types.listOf types.str)) ''
+        Optional HTTP URL parameters.
+      '';
+
+      basic_auth = mkOpt (types.submodule {
+        options = {
+          username = mkOption {
+            type = types.str;
+            description = ''
+              HTTP username
+            '';
           };
-        });
-        default = null;
-        apply = x: mapNullable _filter x;
-        description = ''
-          Optional http login credentials for metrics scraping.
-        '';
-      };
-      tls_config = mkOption {
-        type = types.nullOr promTypes.tls_config;
-        default = null;
-        apply = x: mapNullable _filter x;
-        description = ''
-          Configures the scrape request's TLS settings.
-        '';
-      };
-      dns_sd_configs = mkOption {
-        type = types.listOf promTypes.dns_sd_config;
-        default = [];
-        apply = x: map _filter x;
-        description = ''
-          List of DNS service discovery configurations.
-        '';
-      };
-      consul_sd_configs = mkOption {
-        type = types.listOf promTypes.consul_sd_config;
-        default = [];
-        apply = x: map _filter x;
-        description = ''
-          List of Consul service discovery configurations.
-        '';
-      };
-      file_sd_configs = mkOption {
-        type = types.listOf promTypes.file_sd_config;
-        default = [];
-        apply = x: map _filter x;
-        description = ''
-          List of file service discovery configurations.
-        '';
-      };
-      static_configs = mkOption {
-        type = types.listOf promTypes.static_config;
-        default = [];
-        apply = x: map _filter x;
-        description = ''
-          List of labeled target groups for this job.
-        '';
-      };
-      ec2_sd_configs = mkOption {
-        type = types.listOf promTypes.ec2_sd_config;
-        default = [];
-        apply = x: map _filter x;
-        description = ''
-          List of EC2 service discovery configurations.
-        '';
-      };
-      relabel_configs = mkOption {
-        type = types.listOf promTypes.relabel_config;
-        default = [];
-        apply = x: map _filter x;
-        description = ''
-          List of relabel configurations.
-        '';
-      };
+          password = mkOption {
+            type = types.str;
+            description = ''
+              HTTP password
+            '';
+          };
+        };
+      }) ''
+        Optional http login credentials for metrics scraping.
+      '';
+
+      bearer_token = mkOpt types.str ''
+        Sets the `Authorization` header on every scrape request with
+        the configured bearer token. It is mutually exclusive with
+        <option>bearer_token_file</option>.
+      '';
+
+      bearer_token_file = mkOpt types.str ''
+        Sets the `Authorization` header on every scrape request with
+        the bearer token read from the configured file. It is mutually
+        exclusive with <option>bearer_token</option>.
+      '';
+
+      tls_config = mkOpt promTypes.tls_config ''
+        Configures the scrape request's TLS settings.
+      '';
+
+      proxy_url = mkOpt types.str ''
+        Optional proxy URL.
+      '';
+
+      ec2_sd_configs = mkOpt (types.listOf promTypes.ec2_sd_config) ''
+        List of EC2 service discovery configurations.
+      '';
+
+      dns_sd_configs = mkOpt (types.listOf promTypes.dns_sd_config) ''
+        List of DNS service discovery configurations.
+      '';
+
+      consul_sd_configs = mkOpt (types.listOf promTypes.consul_sd_config) ''
+        List of Consul service discovery configurations.
+      '';
+
+      file_sd_configs = mkOpt (types.listOf promTypes.file_sd_config) ''
+        List of file service discovery configurations.
+      '';
+
+      static_configs = mkOpt (types.listOf promTypes.static_config) ''
+        List of labeled target groups for this job.
+      '';
+
+      relabel_configs = mkOpt (types.listOf promTypes.relabel_config) ''
+        List of relabel configurations.
+      '';
+
+      sample_limit = mkDefOpt types.int "0" ''
+        Per-scrape limit on number of scraped samples that will be accepted.
+        If more than this number of samples are present after metric relabelling
+        the entire scrape will be treated as failed. 0 means no limit.
+      '';
     };
   };
 
@@ -337,66 +312,41 @@ let
           The AWS Region.
         '';
       };
-      endpoint = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          Custom endpoint to be used.
-        '';
-      };
-      access_key = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          The AWS API key id. If blank, the environment variable
-          <literal>AWS_ACCESS_KEY_ID</literal> is used.
-        '';
-      };
-      secret_key = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          The AWS API key secret. If blank, the environment variable
-           <literal>AWS_SECRET_ACCESS_KEY</literal> is used.
-        '';
-      };
-      profile = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          Named AWS profile used to connect to the API.
-        '';
-      };
-      role_arn = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          AWS Role ARN, an alternative to using AWS API keys.
-        '';
-      };
-      refresh_interval = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          Refresh interval to re-read the instance list.
-        '';
-      };
-      port = mkOption {
-        type = types.int;
-        default = 80;
-        description = ''
-          The port to scrape metrics from. If using the public IP
-          address, this must instead be specified in the relabeling
-          rule.
-        '';
-      };
-      filters = mkOption {
-        type = types.nullOr (types.listOf promTypes.filter);
-        default = null;
-        description = ''
-          Filters can be used optionally to filter the instance list by other criteria.
-        '';
-      };
+      endpoint = mkOpt types.str ''
+        Custom endpoint to be used.
+      '';
+
+      access_key = mkOpt types.str ''
+        The AWS API key id. If blank, the environment variable
+        <literal>AWS_ACCESS_KEY_ID</literal> is used.
+      '';
+
+      secret_key = mkOpt types.str ''
+        The AWS API key secret. If blank, the environment variable
+         <literal>AWS_SECRET_ACCESS_KEY</literal> is used.
+      '';
+
+      profile = mkOpt  types.str ''
+        Named AWS profile used to connect to the API.
+      '';
+
+      role_arn = mkOpt types.str ''
+        AWS Role ARN, an alternative to using AWS API keys.
+      '';
+
+      refresh_interval = mkDefOpt types.str "60s" ''
+        Refresh interval to re-read the instance list.
+      '';
+
+      port = mkDefOpt types.int "80" ''
+        The port to scrape metrics from. If using the public IP
+        address, this must instead be specified in the relabeling
+        rule.
+      '';
+
+      filters = mkOpt (types.listOf promTypes.filter) ''
+        Filters can be used optionally to filter the instance list by other criteria.
+      '';
     };
   };
 
@@ -409,6 +359,7 @@ let
           for the available filters.
         '';
       };
+
       value = mkOption {
         type = types.listOf types.str;
         default = [];
@@ -427,56 +378,63 @@ let
           A list of DNS SRV record names to be queried.
         '';
       };
-      refresh_interval = mkOption {
-        type = types.str;
-        default = "30s";
-        description = ''
-          The time after which the provided names are refreshed.
-        '';
-      };
+
+      refresh_interval = mkDefOpt types.str "30s" ''
+        The time after which the provided names are refreshed.
+      '';
     };
   };
 
   promTypes.consul_sd_config = types.submodule {
     options = {
-      server = mkOption {
-        type = types.str;
-        description = "Consul server to query.";
-      };
-      token = mkOption {
-        type = types.nullOr types.str;
-        description = "Consul token";
-      };
-      datacenter = mkOption {
-        type = types.nullOr types.str;
-        description = "Consul datacenter";
-      };
-      scheme = mkOption {
-        type = types.nullOr types.str;
-        description = "Consul scheme";
-      };
-      username = mkOption {
-        type = types.nullOr types.str;
-        description = "Consul username";
-      };
-      password = mkOption {
-        type = types.nullOr types.str;
-        description = "Consul password";
-      };
+      server = mkDefOpt types.str "localhost:8500" ''
+        Consul server to query.
+      '';
 
-      services = mkOption {
-        type = types.listOf types.str;
-        description = ''
-          A list of services for which targets are retrieved.
-        '';
-      };
-      tag_separator = mkOption {
-        type = types.str;
-        default = ",";
-        description = ''
-          The string by which Consul tags are joined into the tag label.
-        '';
-      };
+      token = mkOpt types.str "Consul token";
+
+      datacenter = mkOpt types.str "Consul datacenter";
+
+      scheme = mkDefOpt types.str "http" "Consul scheme";
+
+      username = mkOpt types.str "Consul username";
+
+      password = mkOpt types.str "Consul password";
+
+      tls_config = mkOpt promTypes.tls_config ''
+        Configures the Consul request's TLS settings.
+      '';
+
+      services = mkOpt (types.listOf types.str) ''
+        A list of services for which targets are retrieved.
+      '';
+
+      tags = mkOpt (types.listOf types.str) ''
+        An optional list of tags used to filter nodes for a given
+        service. Services must contain all tags in the list.
+      '';
+
+      node_meta = mkOpt (types.attrsOf types.str) ''
+        Node metadata used to filter nodes for a given service.
+      '';
+
+      tag_separator = mkDefOpt types.str "," ''
+        The string by which Consul tags are joined into the tag label.
+      '';
+
+      allow_stale = mkOpt types.bool ''
+        Allow stale Consul results
+        (see <link xlink:href="https://www.consul.io/api/index.html#consistency-modes"/>).
+
+        Will reduce load on Consul.
+      '';
+
+      refresh_interval = mkDefOpt types.str "30s" ''
+        The time after which the provided names are refreshed.
+
+        On large setup it might be a good idea to increase this value
+        because the catalog will change all the time.
+      '';
     };
   };
 
@@ -488,108 +446,74 @@ let
           Patterns for files from which target groups are extracted. Refer
           to the Prometheus documentation for permitted filename patterns
           and formats.
-
-        '';
-      };
-      refresh_interval = mkOption {
-        type = types.str;
-        default = "30s";
-        description = ''
-          Refresh interval to re-read the files.
         '';
       };
+
+      refresh_interval = mkDefOpt types.str "5m" ''
+        Refresh interval to re-read the files.
+      '';
     };
   };
 
   promTypes.relabel_config = types.submodule {
     options = {
-      source_labels = mkOption {
-        type = with types; nullOr (listOf str);
-        default = null;
-        description = ''
-          The source labels select values from existing labels. Their content
-          is concatenated using the configured separator and matched against
-          the configured regular expression.
-        '';
-      };
-      separator = mkOption {
-        type = types.str;
-        default = ";";
-        description = ''
-          Separator placed between concatenated source label values.
-        '';
-      };
-      target_label = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          Label to which the resulting value is written in a replace action.
-          It is mandatory for replace actions.
-        '';
-      };
-      regex = mkOption {
-        type = types.str;
-        default = "(.*)";
-        description = ''
-          Regular expression against which the extracted value is matched.
-        '';
-      };
-      replacement = mkOption {
-        type = types.str;
-        default = "$1";
-        description = ''
-          Replacement value against which a regex replace is performed if the
-          regular expression matches.
-        '';
-      };
-      action = mkOption {
-        type = types.enum ["replace" "keep" "drop"];
-        default = "replace";
-        description = ''
-          Action to perform based on regex matching.
-        '';
-      };
+      source_labels = mkOpt (types.listOf types.str) ''
+        The source labels select values from existing labels. Their content
+        is concatenated using the configured separator and matched against
+        the configured regular expression.
+      '';
+
+      separator = mkDefOpt types.str ";" ''
+        Separator placed between concatenated source label values.
+      '';
+
+      target_label = mkOpt types.str ''
+        Label to which the resulting value is written in a replace action.
+        It is mandatory for replace actions.
+      '';
+
+      regex = mkDefOpt types.str "(.*)" ''
+        Regular expression against which the extracted value is matched.
+      '';
+
+      modulus = mkOpt types.int ''
+        Modulus to take of the hash of the source label values.
+      '';
+
+      replacement = mkDefOpt types.str "$1" ''
+        Replacement value against which a regex replace is performed if the
+        regular expression matches.
+      '';
+
+      action = mkDefOpt (types.enum ["replace" "keep" "drop"]) "replace" ''
+        Action to perform based on regex matching.
+      '';
+
     };
   };
 
   promTypes.tls_config = types.submodule {
     options = {
-      ca_file = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          CA certificate to validate API server certificate with.
-        '';
-      };
-      cert_file = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          Certificate file for client cert authentication to the server.
-        '';
-      };
-      key_file = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          Key file for client cert authentication to the server.
-        '';
-      };
-      server_name = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          ServerName extension to indicate the name of the server.
-          http://tools.ietf.org/html/rfc4366#section-3.1
-        '';
-      };
-      insecure_skip_verify = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Disable validation of the server certificate.
-        '';
-      };
+      ca_file = mkOpt types.str ''
+        CA certificate to validate API server certificate with.
+      '';
+
+      cert_file = mkOpt types.str ''
+        Certificate file for client cert authentication to the server.
+      '';
+
+      key_file = mkOpt types.str ''
+        Key file for client cert authentication to the server.
+      '';
+
+      server_name = mkOpt types.str ''
+        ServerName extension to indicate the name of the server.
+        http://tools.ietf.org/html/rfc4366#section-3.1
+      '';
+
+      insecure_skip_verify = mkOpt types.bool ''
+        Disable validation of the server certificate.
+      '';
     };
   };
 
@@ -662,7 +586,6 @@ in {
       globalConfig = mkOption {
         type = promTypes.globalConfig;
         default = {};
-        apply = _filter;
         description = ''
           Parameters that are valid in all  configuration contexts. They
           also serve as defaults for other configuration sections
@@ -688,7 +611,6 @@ in {
       scrapeConfigs = mkOption {
         type = types.listOf promTypes.scrape_config;
         default = [];
-        apply = x: map _filter x;
         description = ''
           A list of scrape configurations.
         '';
@@ -786,7 +708,6 @@ in {
       globalConfig = mkOption {
         type = promTypes.globalConfig;
         default = {};
-        apply = _filter;
         description = ''
           Parameters that are valid in all  configuration contexts. They
           also serve as defaults for other configuration sections
@@ -812,7 +733,6 @@ in {
       scrapeConfigs = mkOption {
         type = types.listOf promTypes.scrape_config;
         default = [];
-        apply = x: map _filter x;
         description = ''
           A list of scrape configurations.
         '';
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix b/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix
index d4fa1eccdf3b..f19bf9d81396 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix
@@ -226,18 +226,19 @@ in {
       ipfs.gid = config.ids.gids.ipfs;
     };
 
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' - ${cfg.user} ${cfg.group} - -"
+    ] ++ optionals cfg.autoMount [
+      "d '${cfg.ipfsMountDir}' - ${cfg.user} ${cfg.group} - -"
+      "d '${cfg.ipnsMountDir}' - ${cfg.user} ${cfg.group} - -"
+    ];
+
     systemd.services.ipfs-init = recursiveUpdate commonEnv {
       description = "IPFS Initializer";
 
       after = [ "local-fs.target" ];
       before = [ "ipfs.service" "ipfs-offline.service" "ipfs-norouting.service" ];
 
-      preStart = ''
-        install -m 0755 -o ${cfg.user} -g ${cfg.group} -d ${cfg.dataDir}
-      '' + optionalString cfg.autoMount ''
-        install -m 0755 -o ${cfg.user} -g ${cfg.group} -d ${cfg.ipfsMountDir}
-        install -m 0755 -o ${cfg.user} -g ${cfg.group} -d ${cfg.ipnsMountDir}
-      '';
       script = ''
         if [[ ! -f ${cfg.dataDir}/config ]]; then
           ipfs init ${optionalString cfg.emptyRepo "-e"} \
@@ -253,7 +254,6 @@ in {
       serviceConfig = {
         Type = "oneshot";
         RemainAfterExit = true;
-        PermissionsStartOnly = true;
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/networking/i2pd.nix b/nixpkgs/nixos/modules/services/networking/i2pd.nix
index 0e9b354cfcaf..40478b85b75e 100644
--- a/nixpkgs/nixos/modules/services/networking/i2pd.nix
+++ b/nixpkgs/nixos/modules/services/networking/i2pd.nix
@@ -470,7 +470,7 @@ in
         '';
       };
 
-      trust.hidden = mkEnableOption "Router concealment.";
+      trust.hidden = mkEnableOption "Router concealment";
 
       websocket = mkEndpointOpt "websockets" "127.0.0.1" 7666;
 
@@ -478,7 +478,7 @@ in
       exploratory.outbound = i2cpOpts "exploratory";
 
       ntcp2.enable = mkEnableTrueOption "NTCP2.";
-      ntcp2.published = mkEnableOption "NTCP2 publication.";
+      ntcp2.published = mkEnableOption "NTCP2 publication";
       ntcp2.port = mkOption {
         type = types.int;
         default = 0;
diff --git a/nixpkgs/nixos/modules/services/networking/miredo.nix b/nixpkgs/nixos/modules/services/networking/miredo.nix
index 8694d08385ca..2c8393fb5b41 100644
--- a/nixpkgs/nixos/modules/services/networking/miredo.nix
+++ b/nixpkgs/nixos/modules/services/networking/miredo.nix
@@ -20,7 +20,7 @@ in
 
     services.miredo = {
 
-      enable = mkEnableOption "the Miredo IPv6 tunneling service.";
+      enable = mkEnableOption "the Miredo IPv6 tunneling service";
 
       package = mkOption {
         type = types.package;
diff --git a/nixpkgs/nixos/modules/services/networking/monero.nix b/nixpkgs/nixos/modules/services/networking/monero.nix
index 8241c32bad07..831e4d60d8da 100644
--- a/nixpkgs/nixos/modules/services/networking/monero.nix
+++ b/nixpkgs/nixos/modules/services/networking/monero.nix
@@ -51,7 +51,7 @@ in
 
     services.monero = {
 
-      enable = mkEnableOption "Monero node daemon.";
+      enable = mkEnableOption "Monero node daemon";
 
       mining.enable = mkOption {
         type = types.bool;
diff --git a/nixpkgs/nixos/modules/services/networking/mosquitto.nix b/nixpkgs/nixos/modules/services/networking/mosquitto.nix
index 9974cbd89d1e..1d49c137723c 100644
--- a/nixpkgs/nixos/modules/services/networking/mosquitto.nix
+++ b/nixpkgs/nixos/modules/services/networking/mosquitto.nix
@@ -44,7 +44,7 @@ in
 
   options = {
     services.mosquitto = {
-      enable = mkEnableOption "Enable the MQTT Mosquitto broker.";
+      enable = mkEnableOption "the MQTT Mosquitto broker";
 
       host = mkOption {
         default = "127.0.0.1";
@@ -65,7 +65,7 @@ in
       };
 
       ssl = {
-        enable = mkEnableOption "Enable SSL listener.";
+        enable = mkEnableOption "SSL listener";
 
         cafile = mkOption {
           type = types.nullOr types.path;
diff --git a/nixpkgs/nixos/modules/services/networking/mxisd.nix b/nixpkgs/nixos/modules/services/networking/mxisd.nix
index 0aa6d0d9ecd3..0b9824f29fd7 100644
--- a/nixpkgs/nixos/modules/services/networking/mxisd.nix
+++ b/nixpkgs/nixos/modules/services/networking/mxisd.nix
@@ -116,7 +116,6 @@ in {
         Group = "mxisd";
         ExecStart = "${cfg.package}/bin/mxisd --spring.config.location=${cfg.dataDir}/ --spring.profiles.active=systemd --java.security.egd=file:/dev/./urandom";
         WorkingDirectory = cfg.dataDir;
-        PermissionsStartOnly = true;
         SuccessExitStatus = 143;
         Restart = "on-failure";
       };
diff --git a/nixpkgs/nixos/modules/services/networking/namecoind.nix b/nixpkgs/nixos/modules/services/networking/namecoind.nix
index 8de23b442f93..a569ca87e262 100644
--- a/nixpkgs/nixos/modules/services/networking/namecoind.nix
+++ b/nixpkgs/nixos/modules/services/networking/namecoind.nix
@@ -1,3 +1,4 @@
+
 { config, lib, pkgs, ... }:
 
 with lib;
@@ -43,7 +44,7 @@ in
 
     services.namecoind = {
 
-      enable = mkEnableOption "namecoind, Namecoin client.";
+      enable = mkEnableOption "namecoind, Namecoin client";
 
       wallet = mkOption {
         type = types.path;
diff --git a/nixpkgs/nixos/modules/services/networking/nullidentdmod.nix b/nixpkgs/nixos/modules/services/networking/nullidentdmod.nix
index 786b5227dbad..b0d338a27941 100644
--- a/nixpkgs/nixos/modules/services/networking/nullidentdmod.nix
+++ b/nixpkgs/nixos/modules/services/networking/nullidentdmod.nix
@@ -3,7 +3,7 @@
 
 in {
   options.services.nullidentdmod = with types; {
-    enable = mkEnableOption "Enable the nullidentdmod identd daemon";
+    enable = mkEnableOption "the nullidentdmod identd daemon";
 
     userid = mkOption {
       type = nullOr str;
diff --git a/nixpkgs/nixos/modules/services/networking/smokeping.nix b/nixpkgs/nixos/modules/services/networking/smokeping.nix
index 9ba6e48f417c..fab3ed5bb39d 100644
--- a/nixpkgs/nixos/modules/services/networking/smokeping.nix
+++ b/nixpkgs/nixos/modules/services/networking/smokeping.nix
@@ -285,12 +285,12 @@ in
       uid = config.ids.uids.smokeping;
       description = "smokeping daemon user";
       home = smokepingHome;
+      createHome = true;
     };
     systemd.services.smokeping = {
       wantedBy = [ "multi-user.target"];
       serviceConfig = {
         User = cfg.user;
-        PermissionsStartOnly = true;
         Restart = "on-failure";
       };
       preStart = ''
@@ -300,7 +300,6 @@ in
         cp ${cgiHome} ${smokepingHome}/smokeping.fcgi
         ${cfg.package}/bin/smokeping --check --config=${configPath}
         ${cfg.package}/bin/smokeping --static --config=${configPath}
-        chown -R ${cfg.user} ${smokepingHome}
       '';
       script = ''${cfg.package}/bin/smokeping --config=${configPath} --nodaemon'';
     };
diff --git a/nixpkgs/nixos/modules/services/networking/syncthing.nix b/nixpkgs/nixos/modules/services/networking/syncthing.nix
index 702481ec5177..114a64dfb175 100644
--- a/nixpkgs/nixos/modules/services/networking/syncthing.nix
+++ b/nixpkgs/nixos/modules/services/networking/syncthing.nix
@@ -151,7 +151,6 @@ in {
           RestartForceExitStatus="3 4";
           User = cfg.user;
           Group = cfg.group;
-          PermissionsStartOnly = true;
           ExecStart = ''
             ${cfg.package}/bin/syncthing \
               -no-browser \
diff --git a/nixpkgs/nixos/modules/services/networking/tedicross.nix b/nixpkgs/nixos/modules/services/networking/tedicross.nix
new file mode 100644
index 000000000000..0716975f594a
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/tedicross.nix
@@ -0,0 +1,100 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  dataDir = "/var/lib/tedicross";
+  cfg = config.services.tedicross;
+  configJSON = pkgs.writeText "tedicross-settings.json" (builtins.toJSON cfg.config);
+  configYAML = pkgs.runCommand "tedicross-settings.yaml" { preferLocalBuild = true; } ''
+    ${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out
+  '';
+
+in {
+  options = {
+    services.tedicross = {
+      enable = mkEnableOption "the TediCross Telegram-Discord bridge service";
+
+      config = mkOption {
+        type = types.attrs;
+        # from https://github.com/TediCross/TediCross/blob/master/example.settings.yaml
+        example = literalExample ''
+          {
+            telegram = {
+              useFirstNameInsteadOfUsername = false;
+              colonAfterSenderName = false;
+              skipOldMessages = true;
+              sendEmojiWithStickers = true;
+            };
+            discord = {
+              useNickname = false;
+              skipOldMessages = true;
+              displayTelegramReplies = "embed";
+              replyLength = 100;
+            };
+            bridges = [
+              {
+                name = "Default bridge";
+                direction = "both";
+                telegram = {
+                  chatId = -123456789;
+                  relayJoinMessages = true;
+                  relayLeaveMessages = true;
+                  sendUsernames = true;
+                  ignoreCommands = true;
+                };
+                discord = {
+                  serverId = "DISCORD_SERVER_ID";
+                  channelId = "DISCORD_CHANNEL_ID";
+                  relayJoinMessages = true;
+                  relayLeaveMessages = true;
+                  sendUsernames = true;
+                  crossDeleteOnTelegram = true;
+                };
+              }
+            ];
+
+            debug = false;
+          }
+        '';
+        description = ''
+          <filename>settings.yaml</filename> configuration as a Nix attribute set.
+          Secret tokens should be specified using <option>environmentFile</option>
+          instead of this world-readable file.
+        '';
+      };
+
+      environmentFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = ''
+          File containing environment variables to be passed to the TediCross service,
+          in which secret tokens can be specified securely using the
+          <literal>TELEGRAM_BOT_TOKEN</literal> and <literal>DISCORD_BOT_TOKEN</literal>
+          keys.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    # from https://github.com/TediCross/TediCross/blob/master/guides/autostart/Linux.md
+    systemd.services.tedicross = {
+      description = "TediCross Telegram-Discord bridge service";
+      wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
+      after = [ "network-online.target" ];
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = "${pkgs.nodePackages.tedicross}/bin/tedicross --config='${configYAML}' --data-dir='${dataDir}'";
+        Restart = "always";
+        DynamicUser = true;
+        StateDirectory = baseNameOf dataDir;
+        EnvironmentFile = cfg.environmentFile;
+      };
+    };
+  };
+
+  meta.maintainers = with maintainers; [ pacien ];
+}
+
diff --git a/nixpkgs/nixos/modules/services/networking/toxvpn.nix b/nixpkgs/nixos/modules/services/networking/toxvpn.nix
index b7655f4bec62..7830dfb1834c 100644
--- a/nixpkgs/nixos/modules/services/networking/toxvpn.nix
+++ b/nixpkgs/nixos/modules/services/networking/toxvpn.nix
@@ -5,7 +5,7 @@ with lib;
 {
   options = {
     services.toxvpn = {
-      enable = mkEnableOption "enable toxvpn running on startup";
+      enable = mkEnableOption "toxvpn running on startup";
 
       localip = mkOption {
         type        = types.string;
diff --git a/nixpkgs/nixos/modules/services/networking/wg-quick.nix b/nixpkgs/nixos/modules/services/networking/wg-quick.nix
new file mode 100644
index 000000000000..b770d47d269e
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/wg-quick.nix
@@ -0,0 +1,312 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.networking.wg-quick;
+
+  kernel = config.boot.kernelPackages;
+
+  # interface options
+
+  interfaceOpts = { ... }: {
+    options = {
+      address = mkOption {
+        example = [ "192.168.2.1/24" ];
+        default = [];
+        type = with types; listOf str;
+        description = "The IP addresses of the interface.";
+      };
+
+      dns = mkOption {
+        example = [ "192.168.2.2" ];
+        default = [];
+        type = with types; listOf str;
+        description = "The IP addresses of DNS servers to configure.";
+      };
+
+      privateKey = mkOption {
+        example = "yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=";
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Base64 private key generated by wg genkey.
+
+          Warning: Consider using privateKeyFile instead if you do not
+          want to store the key in the world-readable Nix store.
+        '';
+      };
+
+      privateKeyFile = mkOption {
+        example = "/private/wireguard_key";
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Private key file as generated by wg genkey.
+        '';
+      };
+
+      listenPort = mkOption {
+        default = null;
+        type = with types; nullOr int;
+        example = 51820;
+        description = ''
+          16-bit port for listening. Optional; if not specified,
+          automatically generated based on interface name.
+        '';
+      };
+
+      preUp = mkOption {
+        example = literalExample ''
+          ${pkgs.iproute}/bin/ip netns add foo
+        '';
+        default = "";
+        type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
+        description = ''
+          Commands called at the start of the interface setup.
+        '';
+      };
+
+      preDown = mkOption {
+        example = literalExample ''
+          ${pkgs.iproute}/bin/ip netns del foo
+        '';
+        default = "";
+        type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
+        description = ''
+          Command called before the interface is taken down.
+        '';
+      };
+
+      postUp = mkOption {
+        example = literalExample ''
+          ${pkgs.iproute}/bin/ip netns add foo
+        '';
+        default = "";
+        type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
+        description = ''
+          Commands called after the interface setup.
+        '';
+      };
+
+      postDown = mkOption {
+        example = literalExample ''
+          ${pkgs.iproute}/bin/ip netns del foo
+        '';
+        default = "";
+        type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
+        description = ''
+          Command called after the interface is taken down.
+        '';
+      };
+
+      table = mkOption {
+        example = "main";
+        default = null;
+        type = with types; nullOr str;
+        description = ''
+          The kernel routing table to add this interface's
+          associated routes to. Setting this is useful for e.g. policy routing
+          ("ip rule") or virtual routing and forwarding ("ip vrf"). Both numeric
+          table IDs and table names (/etc/rt_tables) can be used. Defaults to
+          "main".
+        '';
+      };
+
+      mtu = mkOption {
+        example = 1248;
+        default = null;
+        type = with types; nullOr int;
+        description = ''
+          If not specified, the MTU is automatically determined
+          from the endpoint addresses or the system default route, which is usually
+          a sane choice. However, to manually specify an MTU to override this
+          automatic discovery, this value may be specified explicitly.
+        '';
+      };
+
+      peers = mkOption {
+        default = [];
+        description = "Peers linked to the interface.";
+        type = with types; listOf (submodule peerOpts);
+      };
+    };
+  };
+
+  # peer options
+
+  peerOpts = {
+    options = {
+      publicKey = mkOption {
+        example = "xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=";
+        type = types.str;
+        description = "The base64 public key the peer.";
+      };
+
+      presharedKey = mkOption {
+        default = null;
+        example = "rVXs/Ni9tu3oDBLS4hOyAUAa1qTWVA3loR8eL20os3I=";
+        type = with types; nullOr str;
+        description = ''
+          Base64 preshared key generated by wg genpsk. Optional,
+          and may be omitted. This option adds an additional layer of
+          symmetric-key cryptography to be mixed into the already existing
+          public-key cryptography, for post-quantum resistance.
+
+          Warning: Consider using presharedKeyFile instead if you do not
+          want to store the key in the world-readable Nix store.
+        '';
+      };
+
+      presharedKeyFile = mkOption {
+        default = null;
+        example = "/private/wireguard_psk";
+        type = with types; nullOr str;
+        description = ''
+          File pointing to preshared key as generated by wg pensk. Optional,
+          and may be omitted. This option adds an additional layer of
+          symmetric-key cryptography to be mixed into the already existing
+          public-key cryptography, for post-quantum resistance.
+        '';
+      };
+
+      allowedIPs = mkOption {
+        example = [ "10.192.122.3/32" "10.192.124.1/24" ];
+        type = with types; listOf str;
+        description = ''List of IP (v4 or v6) addresses with CIDR masks from
+        which this peer is allowed to send incoming traffic and to which
+        outgoing traffic for this peer is directed. The catch-all 0.0.0.0/0 may
+        be specified for matching all IPv4 addresses, and ::/0 may be specified
+        for matching all IPv6 addresses.'';
+      };
+
+      endpoint = mkOption {
+        default = null;
+        example = "demo.wireguard.io:12913";
+        type = with types; nullOr str;
+        description = ''Endpoint IP or hostname of the peer, followed by a colon,
+        and then a port number of the peer.'';
+      };
+
+      persistentKeepalive = mkOption {
+        default = null;
+        type = with types; nullOr int;
+        example = 25;
+        description = ''This is optional and is by default off, because most
+        users will not need it. It represents, in seconds, between 1 and 65535
+        inclusive, how often to send an authenticated empty packet to the peer,
+        for the purpose of keeping a stateful firewall or NAT mapping valid
+        persistently. For example, if the interface very rarely sends traffic,
+        but it might at anytime receive traffic from a peer, and it is behind
+        NAT, the interface might benefit from having a persistent keepalive
+        interval of 25 seconds; however, most users will not need this.'';
+      };
+    };
+  };
+
+  writeScriptFile = name: text: ((pkgs.writeShellScriptBin name text) + "/bin/${name}");
+
+  generateUnit = name: values:
+    assert assertMsg ((values.privateKey != null) != (values.privateKeyFile != null)) "Only one of privateKey or privateKeyFile may be set";
+    let
+      preUpFile = if values.preUp != "" then writeScriptFile "preUp.sh" values.preUp else null;
+      postUp =
+            optional (values.privateKeyFile != null) "wg set ${name} private-key <(cat ${values.privateKeyFile})" ++
+            (concatMap (peer: optional (peer.presharedKeyFile != null) "wg set ${name} peer ${peer.publicKey} preshared-key <(cat ${peer.presharedKeyFile})") values.peers) ++
+            optional (values.postUp != null) values.postUp;
+      postUpFile = if postUp != [] then writeScriptFile "postUp.sh" (concatMapStringsSep "\n" (line: line) postUp) else null;
+      preDownFile = if values.preDown != "" then writeScriptFile "preDown.sh" values.preDown else null;
+      postDownFile = if values.postDown != "" then writeScriptFile "postDown.sh" values.postDown else null;
+      configDir = pkgs.writeTextFile {
+        name = "config-${name}";
+        executable = false;
+        destination = "/${name}.conf";
+        text =
+        ''
+        [interface]
+        ${concatMapStringsSep "\n" (address:
+          "Address = ${address}"
+        ) values.address}
+        ${concatMapStringsSep "\n" (dns:
+          "DNS = ${dns}"
+        ) values.dns}
+        '' +
+        optionalString (values.table != null) "Table = ${values.table}\n" +
+        optionalString (values.mtu != null) "MTU = ${toString values.mtu}\n" +
+        optionalString (values.privateKey != null) "PrivateKey = ${values.privateKey}\n" +
+        optionalString (values.listenPort != null) "ListenPort = ${toString values.listenPort}\n" +
+        optionalString (preUpFile != null) "PreUp = ${preUpFile}\n" +
+        optionalString (postUpFile != null) "PostUp = ${postUpFile}\n" +
+        optionalString (preDownFile != null) "PreDown = ${preDownFile}\n" +
+        optionalString (postDownFile != null) "PostDown = ${postDownFile}\n" +
+        concatMapStringsSep "\n" (peer:
+          assert assertMsg (!((peer.presharedKeyFile != null) && (peer.presharedKey != null))) "Only one of presharedKey or presharedKeyFile may be set";
+          "[Peer]\n" +
+          "PublicKey = ${peer.publicKey}\n" +
+          optionalString (peer.presharedKey != null) "PresharedKey = ${peer.presharedKey}\n" +
+          optionalString (peer.endpoint != null) "Endpoint = ${peer.endpoint}\n" +
+          optionalString (peer.persistentKeepalive != null) "PersistentKeepalive = ${toString peer.persistentKeepalive}\n" +
+          optionalString (peer.allowedIPs != []) "AllowedIPs = ${concatStringsSep "," peer.allowedIPs}\n"
+        ) values.peers;
+      };
+      configPath = "${configDir}/${name}.conf";
+    in
+    nameValuePair "wg-quick-${name}"
+      {
+        description = "wg-quick WireGuard Tunnel - ${name}";
+        requires = [ "network-online.target" ];
+        after = [ "network.target" "network-online.target" ];
+        wantedBy = [ "multi-user.target" ];
+        environment.DEVICE = name;
+        path = [ pkgs.kmod pkgs.wireguard-tools ];
+
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = true;
+        };
+
+        script = ''
+          ${optionalString (!config.boot.isContainer) "modprobe wireguard"}
+          wg-quick up ${configPath}
+        '';
+
+        preStop = ''
+          wg-quick down ${configPath}
+        '';
+      };
+in {
+
+  ###### interface
+
+  options = {
+    networking.wg-quick = {
+      interfaces = mkOption {
+        description = "Wireguard interfaces.";
+        default = {};
+        example = {
+          wg0 = {
+            address = [ "192.168.20.4/24" ];
+            privateKey = "yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=";
+            peers = [
+              { allowedIPs = [ "192.168.20.1/32" ];
+                publicKey  = "xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=";
+                endpoint   = "demo.wireguard.io:12913"; }
+            ];
+          };
+        };
+        type = with types; attrsOf (submodule interfaceOpts);
+      };
+    };
+  };
+
+
+  ###### implementation
+
+  config = mkIf (cfg.interfaces != {}) {
+    boot.extraModulePackages = [ kernel.wireguard ];
+    environment.systemPackages = [ pkgs.wireguard-tools ];
+    # This is forced to false for now because the default "--validmark" rpfilter we apply on reverse path filtering
+    # breaks the wg-quick routing because wireguard packets leave with a fwmark from wireguard.
+    networking.firewall.checkReversePath = false;
+    systemd.services = mapAttrs' generateUnit cfg.interfaces;
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/networking/wireguard.nix b/nixpkgs/nixos/modules/services/networking/wireguard.nix
index 41aff1480a05..dd3cb1af2716 100644
--- a/nixpkgs/nixos/modules/services/networking/wireguard.nix
+++ b/nixpkgs/nixos/modules/services/networking/wireguard.nix
@@ -26,19 +26,28 @@ let
         type = with types; nullOr str;
         default = null;
         description = ''
-          Base64 private key generated by wg genkey.
+          Base64 private key generated by <command>wg genkey</command>.
 
           Warning: Consider using privateKeyFile instead if you do not
           want to store the key in the world-readable Nix store.
         '';
       };
 
+      generatePrivateKeyFile = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Automatically generate a private key with
+          <command>wg genkey</command>, at the privateKeyFile location.
+        '';
+      };
+
       privateKeyFile = mkOption {
         example = "/private/wireguard_key";
         type = with types; nullOr str;
         default = null;
         description = ''
-          Private key file as generated by wg genkey.
+          Private key file as generated by <command>wg genkey</command>.
         '';
       };
 
@@ -124,8 +133,8 @@ let
         example = "rVXs/Ni9tu3oDBLS4hOyAUAa1qTWVA3loR8eL20os3I=";
         type = with types; nullOr str;
         description = ''
-          Base64 preshared key generated by wg genpsk. Optional,
-          and may be omitted. This option adds an additional layer of
+          Base64 preshared key generated by <command>wg genpsk</command>.
+          Optional, and may be omitted. This option adds an additional layer of
           symmetric-key cryptography to be mixed into the already existing
           public-key cryptography, for post-quantum resistance.
 
@@ -139,8 +148,8 @@ let
         example = "/private/wireguard_psk";
         type = with types; nullOr str;
         description = ''
-          File pointing to preshared key as generated by wg pensk. Optional,
-          and may be omitted. This option adds an additional layer of
+          File pointing to preshared key as generated by <command>wg pensk</command>.
+          Optional, and may be omitted. This option adds an additional layer of
           symmetric-key cryptography to be mixed into the already existing
           public-key cryptography, for post-quantum resistance.
         '';
@@ -182,9 +191,48 @@ let
 
   };
 
-  generateUnit = name: values:
+
+  generatePathUnit = name: values:
+    assert (values.privateKey == null);
+    assert (values.privateKeyFile != null);
+    nameValuePair "wireguard-${name}"
+      {
+        description = "WireGuard Tunnel - ${name} - Private Key";
+        requiredBy = [ "wireguard-${name}.service" ];
+        before = [ "wireguard-${name}.service" ];
+        pathConfig.PathExists = values.privateKeyFile;
+      };
+
+  generateKeyServiceUnit = name: values:
+    assert values.generatePrivateKeyFile;
+    nameValuePair "wireguard-${name}-key"
+      {
+        description = "WireGuard Tunnel - ${name} - Key Generator";
+        wantedBy = [ "wireguard-${name}.service" ];
+        requiredBy = [ "wireguard-${name}.service" ];
+        before = [ "wireguard-${name}.service" ];
+        path = with pkgs; [ wireguard ];
+
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = true;
+        };
+
+        script = ''
+          mkdir --mode 0644 -p "${dirOf values.privateKeyFile}"
+          if [ ! -f "${values.privateKeyFile}" ]; then
+            touch "${values.privateKeyFile}"
+            chmod 0600 "${values.privateKeyFile}"
+            wg genkey > "${values.privateKeyFile}"
+            chmod 0400 "${values.privateKeyFile}"
+          fi
+        '';
+      };
+
+
+  generateSetupServiceUnit = name: values:
     # exactly one way to specify the private key must be set
-    assert (values.privateKey != null) != (values.privateKeyFile != null);
+    #assert (values.privateKey != null) != (values.privateKeyFile != null);
     let privKey = if values.privateKeyFile != null then values.privateKeyFile else pkgs.writeText "wg-key" values.privateKey;
     in
     nameValuePair "wireguard-${name}"
@@ -279,10 +327,27 @@ in
 
   config = mkIf (cfg.interfaces != {}) {
 
+    assertions = (attrValues (
+        mapAttrs (name: value: {
+          assertion = (value.privateKey != null) != (value.privateKeyFile != null);
+          message = "Either networking.wireguard.interfaces.${name}.privateKey or networking.wireguard.interfaces.${name}.privateKeyFile must be set.";
+        }) cfg.interfaces))
+      ++ (attrValues (
+        mapAttrs (name: value: {
+          assertion = value.generatePrivateKeyFile -> (value.privateKey == null);
+          message = "networking.wireguard.interfaces.${name}.generatePrivateKey must not be set if networking.wireguard.interfaces.${name}.privateKey is set.";
+        }) cfg.interfaces));
+
+
     boot.extraModulePackages = [ kernel.wireguard ];
     environment.systemPackages = [ pkgs.wireguard-tools ];
 
-    systemd.services = mapAttrs' generateUnit cfg.interfaces;
+    systemd.services = (mapAttrs' generateSetupServiceUnit cfg.interfaces)
+      // (mapAttrs' generateKeyServiceUnit
+      (filterAttrs (name: value: value.generatePrivateKeyFile) cfg.interfaces));
+
+    systemd.paths = mapAttrs' generatePathUnit
+      (filterAttrs (name: value: value.privateKeyFile != null) cfg.interfaces);
 
   };
 
diff --git a/nixpkgs/nixos/modules/services/search/kibana.nix b/nixpkgs/nixos/modules/services/search/kibana.nix
index ba58630a467a..2a6e8250850c 100644
--- a/nixpkgs/nixos/modules/services/search/kibana.nix
+++ b/nixpkgs/nixos/modules/services/search/kibana.nix
@@ -31,7 +31,7 @@ let
 
 in {
   options.services.kibana = {
-    enable = mkEnableOption "enable kibana service";
+    enable = mkEnableOption "kibana service";
 
     listenAddress = mkOption {
       description = "Kibana listening host";
diff --git a/nixpkgs/nixos/modules/services/search/solr.nix b/nixpkgs/nixos/modules/services/search/solr.nix
index 6659cc8a2d1e..5ef7d9893a49 100644
--- a/nixpkgs/nixos/modules/services/search/solr.nix
+++ b/nixpkgs/nixos/modules/services/search/solr.nix
@@ -11,7 +11,7 @@ in
 {
   options = {
     services.solr = {
-      enable = mkEnableOption "Enables the solr service.";
+      enable = mkEnableOption "Solr";
 
       # default to the 8.x series not forcing major version upgrade of those on the 7.x series
       package = mkOption {
diff --git a/nixpkgs/nixos/modules/services/security/bitwarden_rs/backup.sh b/nixpkgs/nixos/modules/services/security/bitwarden_rs/backup.sh
new file mode 100644
index 000000000000..264a7da9cbb6
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/security/bitwarden_rs/backup.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+# Based on: https://github.com/dani-garcia/bitwarden_rs/wiki/Backing-up-your-vault
+if ! mkdir -p "$BACKUP_FOLDER"; then
+  echo "Could not create backup folder '$BACKUP_FOLDER'" >&2
+  exit 1
+fi
+
+if [[ ! -f "$DATA_FOLDER"/db.sqlite3 ]]; then
+  echo "Could not find SQLite database file '$DATA_FOLDER/db.sqlite3'" >&2
+  exit 1
+fi
+
+sqlite3 "$DATA_FOLDER"/db.sqlite3 ".backup '$BACKUP_FOLDER/db.sqlite3'"
+cp "$DATA_FOLDER"/rsa_key.{der,pem,pub.der} "$BACKUP_FOLDER"
+cp -r "$DATA_FOLDER"/attachments "$BACKUP_FOLDER"
+cp -r "$DATA_FOLDER"/icon_cache "$BACKUP_FOLDER"
diff --git a/nixpkgs/nixos/modules/services/security/bitwarden_rs/default.nix b/nixpkgs/nixos/modules/services/security/bitwarden_rs/default.nix
new file mode 100644
index 000000000000..bb036ee020f4
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/security/bitwarden_rs/default.nix
@@ -0,0 +1,126 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.bitwarden_rs;
+  user = config.users.users.bitwarden_rs.name;
+  group = config.users.groups.bitwarden_rs.name;
+
+  # Convert name from camel case (e.g. disable2FARemember) to upper case snake case (e.g. DISABLE_2FA_REMEMBER).
+  nameToEnvVar = name:
+    let
+      parts = builtins.split "([A-Z0-9]+)" name;
+      partsToEnvVar = parts: foldl' (key: x: let last = stringLength key - 1; in
+        if isList x then key + optionalString (key != "" && substring last 1 key != "_") "_" + head x
+        else if key != "" && elem (substring 0 1 x) lowerChars then # to handle e.g. [ "disable" [ "2FAR" ] "emember" ]
+          substring 0 last key + optionalString (substring (last - 1) 1 key != "_") "_" + substring last 1 key + toUpper x
+        else key + toUpper x) "" parts;
+    in if builtins.match "[A-Z0-9_]+" name != null then name else partsToEnvVar parts;
+
+  configFile = pkgs.writeText "bitwarden_rs.env" (concatMapStrings (s: s + "\n") (
+    (concatLists (mapAttrsToList (name: value:
+      if value != null then [ "${nameToEnvVar name}=${if isBool value then boolToString value else toString value}" ] else []
+    ) cfg.config))));
+
+in {
+  options.services.bitwarden_rs = with types; {
+    enable = mkEnableOption "bitwarden_rs";
+
+    backupDir = mkOption {
+      type = nullOr str;
+      default = null;
+      description = ''
+        The directory under which bitwarden_rs will backup its persistent data.
+      '';
+    };
+
+    config = mkOption {
+      type = attrsOf (nullOr (either (either bool int) str));
+      default = {};
+      example = literalExample ''
+        {
+          domain = https://bw.domain.tld:8443;
+          signupsAllowed = true;
+          rocketPort = 8222;
+          rocketLog = "critical";
+        }
+      '';
+      description = ''
+        The configuration of bitwarden_rs is done through environment variables,
+        therefore the names are converted from camel case (e.g. disable2FARemember)
+        to upper case snake case (e.g. DISABLE_2FA_REMEMBER).
+        In this conversion digits (0-9) are handled just like upper case characters,
+        so foo2 would be converted to FOO_2.
+        Names already in this format remain unchanged, so FOO2 remains FOO2 if passed as such,
+        even though foo2 would have been converted to FOO_2.
+        This allows working around any potential future conflicting naming conventions.
+
+        Based on the attributes passed to this config option a environment file will be generated
+        that is passed to bitwarden_rs's systemd service.
+
+        The available configuration options can be found in
+        <link xlink:href="https://github.com/dani-garcia/bitwarden_rs/blob/1.8.0/.env.template">the environment template file</link>.
+      '';
+      apply = config: optionalAttrs config.webVaultEnabled {
+        webVaultFolder = "${pkgs.bitwarden_rs-vault}/share/bitwarden_rs/vault";
+      } // config;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.bitwarden_rs.config = {
+      dataFolder = "/var/lib/bitwarden_rs";
+      webVaultEnabled = mkDefault true;
+    };
+
+    users.users.bitwarden_rs = { inherit group; };
+    users.groups.bitwarden_rs = { };
+
+    systemd.services.bitwarden_rs = {
+      after = [ "network.target" ];
+      path = with pkgs; [ openssl ];
+      serviceConfig = {
+        User = user;
+        Group = group;
+        EnvironmentFile = configFile;
+        ExecStart = "${pkgs.bitwarden_rs}/bin/bitwarden_rs";
+        LimitNOFILE = "1048576";
+        LimitNPROC = "64";
+        PrivateTmp = "true";
+        PrivateDevices = "true";
+        ProtectHome = "true";
+        ProtectSystem = "strict";
+        AmbientCapabilities = "CAP_NET_BIND_SERVICE";
+        StateDirectory = "bitwarden_rs";
+      };
+      wantedBy = [ "multi-user.target" ];
+    };
+
+    systemd.services.backup-bitwarden_rs = mkIf (cfg.backupDir != null) {
+      description = "Backup bitwarden_rs";
+      environment = {
+        DATA_FOLDER = "/var/lib/bitwarden_rs";
+        BACKUP_FOLDER = cfg.backupDir;
+      };
+      path = with pkgs; [ sqlite ];
+      serviceConfig = {
+        SyslogIdentifier = "backup-bitwarden_rs";
+        User = mkDefault user;
+        Group = mkDefault group;
+        ExecStart = "${pkgs.bash}/bin/bash ${./backup.sh}";
+      };
+      wantedBy = [ "multi-user.target" ];
+    };
+
+    systemd.timers.backup-bitwarden_rs = mkIf (cfg.backupDir != null) {
+      description = "Backup bitwarden_rs on time";
+      timerConfig = {
+        OnCalendar = mkDefault "23:00";
+        Persistent = "true";
+        Unit = "backup-bitwarden_rs.service";
+      };
+      wantedBy = [ "multi-user.target" ];
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/security/munge.nix b/nixpkgs/nixos/modules/services/security/munge.nix
index 504bc66c6d10..1c4f8e20552f 100644
--- a/nixpkgs/nixos/modules/services/security/munge.nix
+++ b/nixpkgs/nixos/modules/services/security/munge.nix
@@ -49,21 +49,16 @@ in
 
       path = [ pkgs.munge pkgs.coreutils ];
 
-      preStart = ''
-        chmod 0400 ${cfg.password}
-        mkdir -p /var/lib/munge -m 0711
-        chown -R munge:munge /var/lib/munge
-        mkdir -p /run/munge -m 0755
-        chown -R munge:munge /run/munge
-      '';
-
       serviceConfig = {
+        ExecStartPre = "+${pkgs.coreutils}/bin/chmod 0400 ${cfg.password}";
         ExecStart = "${pkgs.munge}/bin/munged --syslog --key-file ${cfg.password}";
         PIDFile = "/run/munge/munged.pid";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-        PermissionsStartOnly = "true";
         User = "munge";
         Group = "munge";
+        StateDirectory = "munge";
+        StateDirectoryMode = "0711";
+        RuntimeDirectory = "munge";
       };
 
     };
diff --git a/nixpkgs/nixos/modules/services/security/vault.nix b/nixpkgs/nixos/modules/services/security/vault.nix
index 0b28bc894458..8176c168ca94 100644
--- a/nixpkgs/nixos/modules/services/security/vault.nix
+++ b/nixpkgs/nixos/modules/services/security/vault.nix
@@ -119,6 +119,10 @@ in
     };
     users.groups.vault.gid = config.ids.gids.vault;
 
+    systemd.tmpfiles.rules = optional (cfg.storagePath != null) [
+      "d '${cfg.storagePath}' 0700 vault vault - -"
+    ];
+
     systemd.services.vault = {
       description = "Vault server daemon";
 
@@ -128,14 +132,9 @@ in
 
       restartIfChanged = false; # do not restart on "nixos-rebuild switch". It would seal the storage and disrupt the clients.
 
-      preStart = optionalString (cfg.storagePath != null) ''
-        install -d -m0700 -o vault -g vault "${cfg.storagePath}"
-      '';
-
       serviceConfig = {
         User = "vault";
         Group = "vault";
-        PermissionsStartOnly = true;
         ExecStart = "${cfg.package}/bin/vault server -config ${configFile}";
         PrivateDevices = true;
         PrivateTmp = true;
diff --git a/nixpkgs/nixos/modules/services/torrent/peerflix.nix b/nixpkgs/nixos/modules/services/torrent/peerflix.nix
index bed6661f84d6..a74f65984328 100644
--- a/nixpkgs/nixos/modules/services/torrent/peerflix.nix
+++ b/nixpkgs/nixos/modules/services/torrent/peerflix.nix
@@ -39,6 +39,10 @@ in {
   ###### implementation
 
   config = mkIf cfg.enable {
+    systemd.tmpfiles.rules = [
+      "d '${cfg.stateDir}' - peerflix - - -"
+    ];
+
     systemd.services.peerflix = {
       description = "Peerflix Daemon";
       wantedBy = [ "multi-user.target" ];
@@ -47,13 +51,11 @@ in {
 
       preStart = ''
         mkdir -p "${cfg.stateDir}"/{torrents,.config/peerflix-server}
-        if [ "$(id -u)" = 0 ]; then chown -R peerflix "${cfg.stateDir}"; fi
         ln -fs "${configFile}" "${cfg.stateDir}/.config/peerflix-server/config.json"
       '';
 
       serviceConfig = {
         ExecStart = "${pkgs.nodePackages.peerflix-server}/bin/peerflix-server";
-        PermissionsStartOnly = true;
         User = "peerflix";
       };
     };
diff --git a/nixpkgs/nixos/modules/services/web-apps/codimd.nix b/nixpkgs/nixos/modules/services/web-apps/codimd.nix
index ee2fc2b9d857..7ae7cd9c52d8 100644
--- a/nixpkgs/nixos/modules/services/web-apps/codimd.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/codimd.nix
@@ -899,10 +899,6 @@ in
       description = "CodiMD Service";
       wantedBy = [ "multi-user.target" ];
       after = [ "networking.target" ];
-      preStart = ''
-        mkdir -p ${cfg.workDir}
-        chown -R codimd: ${cfg.workDir}
-      '';
       serviceConfig = {
         WorkingDirectory = cfg.workDir;
         ExecStart = "${pkgs.codimd}/bin/codimd";
@@ -912,7 +908,6 @@ in
         ];
         Restart = "always";
         User = "codimd";
-        PermissionsStartOnly = true;
         PrivateTmp = true;
       };
     };
diff --git a/nixpkgs/nixos/modules/services/web-apps/nexus.nix b/nixpkgs/nixos/modules/services/web-apps/nexus.nix
index 050f8757fa5f..052dbed6d4f8 100644
--- a/nixpkgs/nixos/modules/services/web-apps/nexus.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/nexus.nix
@@ -83,6 +83,8 @@ in
     users.users."${cfg.user}" = {
       isSystemUser = true;
       group = cfg.group;
+      home = cfg.home;
+      createHome = true;
     };
 
     users.groups."${cfg.group}" = {};
@@ -104,8 +106,6 @@ in
       preStart = ''
         mkdir -p ${cfg.home}/nexus3/etc
 
-        chown -R ${cfg.user}:${cfg.group} ${cfg.home}
-
         if [ ! -f ${cfg.home}/nexus3/etc/nexus.properties ]; then
           echo "# Jetty section" > ${cfg.home}/nexus3/etc/nexus.properties
           echo "application-port=${toString cfg.listenPort}" >> ${cfg.home}/nexus3/etc/nexus.properties
@@ -124,7 +124,6 @@ in
         User = cfg.user;
         Group = cfg.group;
         PrivateTmp = true;
-        PermissionsStartOnly = true;
         LimitNOFILE = 102642;
       };
     };
diff --git a/nixpkgs/nixos/modules/services/web-servers/minio.nix b/nixpkgs/nixos/modules/services/web-servers/minio.nix
index f78a966989b6..cd123000f009 100644
--- a/nixpkgs/nixos/modules/services/web-servers/minio.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/minio.nix
@@ -72,19 +72,16 @@ in
   };
 
   config = mkIf cfg.enable {
+    systemd.tmpfiles.rules = [
+      "d '${cfg.configDir}' - minio minio - -"
+      "d '${cfg.dataDir}' - minio minio - -"
+    ];
+
     systemd.services.minio = {
       description = "Minio Object Storage";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        # Make sure directories exist with correct owner
-        mkdir -p ${cfg.configDir}
-        chown -R minio:minio ${cfg.configDir}
-        mkdir -p ${cfg.dataDir}
-        chown minio:minio ${cfg.dataDir}
-      '';
       serviceConfig = {
-        PermissionsStartOnly = true;
         ExecStart = "${cfg.package}/bin/minio server --json --address ${cfg.listenAddress} --config-dir=${cfg.configDir} ${cfg.dataDir}";
         Type = "simple";
         User = "minio";
diff --git a/nixpkgs/nixos/modules/services/web-servers/traefik.nix b/nixpkgs/nixos/modules/services/web-servers/traefik.nix
index 4674ed0177e6..5bac895d43ac 100644
--- a/nixpkgs/nixos/modules/services/web-servers/traefik.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/traefik.nix
@@ -84,18 +84,16 @@ in {
   };
 
   config = mkIf cfg.enable {
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' 0700 traefik traefik - -"
+    ];
+
     systemd.services.traefik = {
       description = "Traefik web server";
       after = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
       serviceConfig = {
-        PermissionsStartOnly = true;
         ExecStart = ''${cfg.package.bin}/bin/traefik --configfile=${configFile}'';
-        ExecStartPre = [
-          ''${pkgs.coreutils}/bin/mkdir -p "${cfg.dataDir}"''
-          ''${pkgs.coreutils}/bin/chmod 700 "${cfg.dataDir}"''
-          ''${pkgs.coreutils}/bin/chown -R traefik:traefik "${cfg.dataDir}"''
-        ];
         Type = "simple";
         User = "traefik";
         Group = cfg.group;
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 3d748d4308b7..9bf03a494701 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -75,7 +75,7 @@ in {
       debug = mkEnableOption "gnome-session debug messages";
 
       flashback = {
-        enableMetacity = mkEnableOption "Enable the standard GNOME Flashback session with Metacity.";
+        enableMetacity = mkEnableOption "the standard GNOME Flashback session with Metacity";
 
         customSessions = mkOption {
           type = types.listOf (types.submodule {
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/maxx.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/maxx.nix
index d7bd2fc5eb0c..6a698658bdd6 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/maxx.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/maxx.nix
@@ -13,6 +13,12 @@ in {
   config = mkIf (xcfg.enable && cfg.enable) {
     environment.systemPackages = [ pkgs.maxx ];
 
+    # there is hardcoded path in binaries
+    system.activationScripts.setup-maxx = ''
+      mkdir -p /opt
+      ln -sfn ${pkgs.maxx}/opt/MaXX /opt
+    '';
+
     services.xserver.desktopManager.session = [
     { name = "MaXX";
       start = ''
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix b/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix
index 15609540a6e7..570469843586 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix
@@ -20,8 +20,8 @@ in
           Whether to enable the dummy "startx" pseudo-display manager,
           which allows users to start X manually via the "startx" command
           from a vt shell. The X server runs under the user's id, not as root.
-          The user must provide a ~/.xinintrc file containing session startup
-          commands, see startx(1). This is not autmatically generated
+          The user must provide a ~/.xinitrc file containing session startup
+          commands, see startx(1). This is not automatically generated
           from the desktopManager and windowManager settings.
         '';
       };
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/xpra.nix b/nixpkgs/nixos/modules/services/x11/display-managers/xpra.nix
index 40a1680da537..c23e479140f0 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/xpra.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/xpra.nix
@@ -33,7 +33,7 @@ in
         description = "Authentication to use when connecting to xpra";
       };
 
-      pulseaudio = mkEnableOption "pulseaudio audio streaming.";
+      pulseaudio = mkEnableOption "pulseaudio audio streaming";
 
       extraOptions = mkOption {
         description = "Extra xpra options";
diff --git a/nixpkgs/nixos/modules/system/boot/stage-1-init.sh b/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
index 6dafc6cddde7..67cbe720ddc3 100644
--- a/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
@@ -555,7 +555,7 @@ echo /sbin/modprobe > /proc/sys/kernel/modprobe
 # Start stage 2.  `switch_root' deletes all files in the ramfs on the
 # current root.  Note that $stage2Init might be an absolute symlink,
 # in which case "-e" won't work because we're not in the chroot yet.
-if ! test -e "$targetRoot/$stage2Init" -o ! -L "$targetRoot/$stage2Init"; then
+if [ ! -e "$targetRoot/$stage2Init" ] && [ ! -L "$targetRoot/$stage2Init" ] ; then
     echo "stage 2 init script ($targetRoot/$stage2Init) not found"
     fail
 fi
diff --git a/nixpkgs/nixos/modules/system/boot/stage-1.nix b/nixpkgs/nixos/modules/system/boot/stage-1.nix
index 8702abd3df83..788e3f4a2ab1 100644
--- a/nixpkgs/nixos/modules/system/boot/stage-1.nix
+++ b/nixpkgs/nixos/modules/system/boot/stage-1.nix
@@ -32,7 +32,7 @@ let
   fileSystems = filter utils.fsNeededForBoot config.system.build.fileSystems;
 
   # A utility for enumerating the shared-library dependencies of a program
-  findLibs = pkgs.writeShellScriptBin "find-libs" ''
+  findLibs = pkgs.buildPackages.writeShellScriptBin "find-libs" ''
     set -euo pipefail
 
     declare -A seen
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
index 1384873b6631..48be18c71021 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
@@ -19,7 +19,7 @@ in
     # One could also do regular btrfs balances, but that shouldn't be necessary
     # during normal usage and as long as the filesystems aren't filled near capacity
     services.btrfs.autoScrub = {
-      enable = mkEnableOption "Enable regular btrfs scrub";
+      enable = mkEnableOption "regular btrfs scrub";
 
       fileSystems = mkOption {
         type = types.listOf types.path;
diff --git a/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix b/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix
index aaea06bb9a63..f640bb21b133 100644
--- a/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix
+++ b/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix
@@ -274,5 +274,22 @@ let self = {
   "18.09".sa-east-1.hvm-ebs = "ami-0e4a8a47fd6db6112";
   "18.09".ap-south-1.hvm-ebs = "ami-0880a678d3f555313";
 
-  latest = self."18.09";
+  # 19.03.172286.8ea36d73256
+  "19.03".eu-west-1.hvm-ebs = "ami-0fe40176548ff0940";
+  "19.03".eu-west-2.hvm-ebs = "ami-03a40fd3a02fe95ba";
+  "19.03".eu-west-3.hvm-ebs = "ami-0436f9da0f20a638e";
+  "19.03".eu-central-1.hvm-ebs = "ami-0022b8ea9efde5de4";
+  "19.03".us-east-1.hvm-ebs = "ami-0efc58fb70ae9a217";
+  "19.03".us-east-2.hvm-ebs = "ami-0abf711b1b34da1af";
+  "19.03".us-west-1.hvm-ebs = "ami-07d126e8838c40ec5";
+  "19.03".us-west-2.hvm-ebs = "ami-03f8a737546e47fb0";
+  "19.03".ca-central-1.hvm-ebs = "ami-03f9fd0ef2e035ede";
+  "19.03".ap-southeast-1.hvm-ebs = "ami-0cff66114c652c262";
+  "19.03".ap-southeast-2.hvm-ebs = "ami-054c73a7f8d773ea9";
+  "19.03".ap-northeast-1.hvm-ebs = "ami-00db62688900456a4";
+  "19.03".ap-northeast-2.hvm-ebs = "ami-0485cdd1a5fdd2117";
+  "19.03".sa-east-1.hvm-ebs = "ami-0c6a43c6e0ad1f4e2";
+  "19.03".ap-south-1.hvm-ebs = "ami-0303deb1b5890f878";
+
+  latest = self."19.03";
 }; in self
diff --git a/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix b/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix
index 903411799d3e..ab65523592d7 100644
--- a/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix
+++ b/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix
@@ -100,6 +100,11 @@ in {
     boot.growPartition = true;
     boot.loader.grub.device = "/dev/sda";
 
+    swapDevices = [{
+      device = "/var/swap";
+      size = 2048;
+    }];
+
     virtualisation.virtualbox.guest.enable = true;
 
   };
diff --git a/nixpkgs/nixos/tests/all-tests.nix b/nixpkgs/nixos/tests/all-tests.nix
index 8b27ff808e6b..a1871ee5f903 100644
--- a/nixpkgs/nixos/tests/all-tests.nix
+++ b/nixpkgs/nixos/tests/all-tests.nix
@@ -23,6 +23,7 @@ in
 {
   acme = handleTestOn ["x86_64-linux"] ./acme.nix {};
   atd = handleTest ./atd.nix {};
+  automysqlbackup = handleTest ./automysqlbackup.nix {};
   avahi = handleTest ./avahi.nix {};
   bcachefs = handleTestOn ["x86_64-linux"] ./bcachefs.nix {}; # linux-4.18.2018.10.12 is unsupported on aarch64
   beanstalkd = handleTest ./beanstalkd.nix {};
@@ -143,6 +144,7 @@ in
   misc = handleTest ./misc.nix {};
   mongodb = handleTest ./mongodb.nix {};
   morty = handleTest ./morty.nix {};
+  mosquitto = handleTest ./mosquitto.nix {};
   mpd = handleTest ./mpd.nix {};
   mumble = handleTest ./mumble.nix {};
   munin = handleTest ./munin.nix {};
@@ -237,6 +239,7 @@ in
   vault = handleTest ./vault.nix {};
   virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {};
   wireguard = handleTest ./wireguard {};
+  wireguard-generated = handleTest ./wireguard/generated.nix {};
   wordpress = handleTest ./wordpress.nix {};
   xautolock = handleTest ./xautolock.nix {};
   xdg-desktop-portal = handleTest ./xdg-desktop-portal.nix {};
diff --git a/nixpkgs/nixos/tests/automysqlbackup.nix b/nixpkgs/nixos/tests/automysqlbackup.nix
new file mode 100644
index 000000000000..ada104a34de3
--- /dev/null
+++ b/nixpkgs/nixos/tests/automysqlbackup.nix
@@ -0,0 +1,34 @@
+import ./make-test.nix ({ pkgs, lib, ... }:
+
+{
+  name = "automysqlbackup";
+  meta.maintainers = [ lib.maintainers.aanderse ];
+
+  machine =
+    { pkgs, ... }:
+    {
+      services.mysql.enable = true;
+      services.mysql.package = pkgs.mysql;
+      services.mysql.initialDatabases = [ { name = "testdb"; schema = ./testdb.sql; } ];
+
+      services.automysqlbackup.enable = true;
+    };
+
+  testScript = ''
+    startAll;
+
+    # Need to have mysql started so that it can be populated with data.
+    $machine->waitForUnit("mysql.service");
+
+    # Wait for testdb to be fully populated (5 rows).
+    $machine->waitUntilSucceeds("mysql -u root -D testdb -N -B -e 'select count(id) from tests' | grep -q 5");
+
+    # Do a backup and wait for it to start
+    $machine->startJob("automysqlbackup.service");
+    $machine->waitForJob("automysqlbackup.service");
+
+    # wait for backup file and check that data appears in backup
+    $machine->waitForFile("/var/backup/mysql/daily/testdb");
+    $machine->succeed("${pkgs.gzip}/bin/zcat /var/backup/mysql/daily/testdb/daily_testdb_*.sql.gz | grep hello");
+    '';
+})
diff --git a/nixpkgs/nixos/tests/kubernetes/base.nix b/nixpkgs/nixos/tests/kubernetes/base.nix
index ec1a75e74c41..212023859f6d 100644
--- a/nixpkgs/nixos/tests/kubernetes/base.nix
+++ b/nixpkgs/nixos/tests/kubernetes/base.nix
@@ -30,7 +30,10 @@ let
         { config, pkgs, lib, nodes, ... }:
           mkMerge [
             {
-              boot.postBootCommands = "rm -fr /var/lib/kubernetes/secrets /tmp/shared/*";
+              boot = {
+                postBootCommands = "rm -fr /var/lib/kubernetes/secrets /tmp/shared/*";
+                kernel.sysctl = { "fs.inotify.max_user_instances" = 256; };
+              };
               virtualisation.memorySize = mkDefault 1536;
               virtualisation.diskSize = mkDefault 4096;
               networking = {
diff --git a/nixpkgs/nixos/tests/kubernetes/dns.nix b/nixpkgs/nixos/tests/kubernetes/dns.nix
index 46bcb01a5265..e7db0a58ab61 100644
--- a/nixpkgs/nixos/tests/kubernetes/dns.nix
+++ b/nixpkgs/nixos/tests/kubernetes/dns.nix
@@ -77,6 +77,7 @@ let
   singleNodeTest = {
     test = ''
       # prepare machine1 for test
+      $machine1->waitForUnit("kubernetes.target");
       $machine1->waitUntilSucceeds("kubectl get node machine1.${domain} | grep -w Ready");
       $machine1->waitUntilSucceeds("docker load < ${redisImage}");
       $machine1->waitUntilSucceeds("kubectl create -f ${redisPod}");
@@ -102,6 +103,8 @@ let
       # Node token exchange
       $machine1->waitUntilSucceeds("cp -f /var/lib/cfssl/apitoken.secret /tmp/shared/apitoken.secret");
       $machine2->waitUntilSucceeds("cat /tmp/shared/apitoken.secret | nixos-kubernetes-node-join");
+      $machine1->waitForUnit("kubernetes.target");
+      $machine2->waitForUnit("kubernetes.target");
 
       # prepare machines for test
       $machine1->waitUntilSucceeds("kubectl get node machine2.${domain} | grep -w Ready");
diff --git a/nixpkgs/nixos/tests/kubernetes/rbac.nix b/nixpkgs/nixos/tests/kubernetes/rbac.nix
index 3ce7adcd0d71..967fe506004f 100644
--- a/nixpkgs/nixos/tests/kubernetes/rbac.nix
+++ b/nixpkgs/nixos/tests/kubernetes/rbac.nix
@@ -94,6 +94,8 @@ let
 
   singlenode = base // {
     test = ''
+      $machine1->waitForUnit("kubernetes.target");
+
       $machine1->waitUntilSucceeds("kubectl get node machine1.my.zyx | grep -w Ready");
 
       $machine1->waitUntilSucceeds("docker load < ${kubectlImage}");
@@ -116,6 +118,8 @@ let
       # Node token exchange
       $machine1->waitUntilSucceeds("cp -f /var/lib/cfssl/apitoken.secret /tmp/shared/apitoken.secret");
       $machine2->waitUntilSucceeds("cat /tmp/shared/apitoken.secret | nixos-kubernetes-node-join");
+      $machine1->waitForUnit("kubernetes.target");
+      $machine2->waitForUnit("kubernetes.target");
 
       $machine1->waitUntilSucceeds("kubectl get node machine2.my.zyx | grep -w Ready");
 
diff --git a/nixpkgs/nixos/tests/mosquitto.nix b/nixpkgs/nixos/tests/mosquitto.nix
new file mode 100644
index 000000000000..86b7f9c044d8
--- /dev/null
+++ b/nixpkgs/nixos/tests/mosquitto.nix
@@ -0,0 +1,69 @@
+import ./make-test.nix ({ pkgs, ... }:
+
+let
+  port = 1888;
+  username = "mqtt";
+  password = "VERY_secret";
+  topic = "test/foo";
+
+  cmd = bin: pkgs.lib.concatStringsSep " " [
+    "${pkgs.mosquitto}/bin/mosquitto_${bin}"
+    "-V mqttv311"
+    "-h server"
+    "-p ${toString port}"
+    "-u ${username}"
+    "-P '${password}'"
+    "-t ${topic}"
+  ];
+
+in rec {
+  name = "mosquitto";
+  meta = with pkgs.stdenv.lib; {
+    maintainers = with maintainers; [ peterhoeg ];
+  };
+
+  nodes = let
+    client = { pkgs, ... }: {
+      environment.systemPackages = with pkgs; [ mosquitto ];
+    };
+  in {
+    server = { pkgs, ... }: {
+      networking.firewall.allowedTCPPorts = [ port ];
+      services.mosquitto = {
+        inherit port;
+        enable = true;
+        host = "0.0.0.0";
+        checkPasswords = true;
+        users."${username}" = {
+          inherit password;
+          acl = [
+            "topic readwrite ${topic}"
+          ];
+        };
+      };
+    };
+
+    client1 = client;
+    client2 = client;
+  };
+
+  testScript = let
+    file = "/tmp/msg";
+    payload = "wootWOOT";
+  in ''
+    startAll;
+    $server->waitForUnit("mosquitto.service");
+
+    $server->fail("test -f ${file}");
+    $server->execute("(${cmd "sub"} -C 1 | tee ${file} &)");
+
+    $client1->fail("test -f ${file}");
+    $client1->execute("(${cmd "sub"} -C 1 | tee ${file} &)");
+
+    $client2->succeed("${cmd "pub"} -m ${payload}");
+
+    $server->succeed("grep -q ${payload} ${file}");
+
+    $client1->succeed("grep -q ${payload} ${file}");
+  '';
+})
diff --git a/nixpkgs/nixos/tests/nginx.nix b/nixpkgs/nixos/tests/nginx.nix
index a4d14986a146..d66d99821c11 100644
--- a/nixpkgs/nixos/tests/nginx.nix
+++ b/nixpkgs/nixos/tests/nginx.nix
@@ -1,18 +1,19 @@
 # verifies:
 #   1. nginx generates config file with shared http context definitions above
 #      generated virtual hosts config.
+#   2. whether the ETag header is properly generated whenever we're serving
+#      files in Nix store paths
 
-import ./make-test.nix ({ pkgs, ...} : {
+import ./make-test.nix ({ pkgs, ... }: {
   name = "nginx";
   meta = with pkgs.stdenv.lib.maintainers; {
     maintainers = [ mbbx6spp ];
   };
 
-  nodes = {
-    webserver =
-      { ... }:
-      { services.nginx.enable = true;
-        services.nginx.commonHttpConfig = ''
+  nodes = let
+    commonConfig = { pkgs, ... }: {
+      services.nginx.enable = true;
+      services.nginx.commonHttpConfig = ''
         log_format ceeformat '@cee: {"status":"$status",'
           '"request_time":$request_time,'
           '"upstream_response_time":$upstream_response_time,'
@@ -24,20 +25,61 @@ import ./make-test.nix ({ pkgs, ...} : {
           '"request":"$request",'
           '"http_referer":"$http_referer",'
           '"upstream_addr":"$upstream_addr"}';
+      '';
+      services.nginx.virtualHosts."0.my.test" = {
+        extraConfig = ''
+          access_log syslog:server=unix:/dev/log,facility=user,tag=mytag,severity=info ceeformat;
+          location /favicon.ico { allow all; access_log off; log_not_found off; }
         '';
-        services.nginx.virtualHosts."0.my.test" = {
-          extraConfig = ''
-            access_log syslog:server=unix:/dev/log,facility=user,tag=mytag,severity=info ceeformat;
-            location /favicon.ico { allow all; access_log off; log_not_found off; }
-          '';
-        };
       };
+      services.nginx.virtualHosts.localhost = {
+        root = pkgs.runCommand "testdir" {} ''
+          mkdir "$out"
+          echo hello world > "$out/index.html"
+        '';
+      };
+    };
+  in {
+    webserver = commonConfig;
+
+    newwebserver = { pkgs, lib, ... }: {
+      imports = [ commonConfig ];
+      services.nginx.virtualHosts.localhost = {
+        root = lib.mkForce (pkgs.runCommand "testdir2" {} ''
+          mkdir "$out"
+          echo hello world > "$out/index.html"
+        '');
+      };
+    };
   };
 
-  testScript = ''
-    startAll;
+  testScript = { nodes, ... }: let
+    newServerSystem = nodes.newwebserver.config.system.build.toplevel;
+    switch = "${newServerSystem}/bin/switch-to-configuration test";
+  in ''
+    my $url = 'http://localhost/index.html';
+
+    sub checkEtag {
+      my $etag = $webserver->succeed(
+        'curl -v '.$url.' 2>&1 | sed -n -e "s/^< [Ee][Tt][Aa][Gg]: *//p"'
+      );
+      $etag =~ s/\r?\n$//;
+      my $httpCode = $webserver->succeed(
+        'curl -w "%{http_code}" -X HEAD -H \'If-None-Match: '.$etag.'\' '.$url
+      );
+      chomp $httpCode;
+      die "HTTP code is not 304" unless $httpCode == 304;
+      return $etag;
+    }
 
     $webserver->waitForUnit("nginx");
     $webserver->waitForOpenPort("80");
+
+    subtest "check ETag if serving Nix store paths", sub {
+      my $oldEtag = checkEtag;
+      $webserver->succeed('${switch}');
+      my $newEtag = checkEtag;
+      die "Old ETag $oldEtag is the same as $newEtag" if $oldEtag eq $newEtag;
+    };
   '';
 })
diff --git a/nixpkgs/nixos/tests/wireguard/generated.nix b/nixpkgs/nixos/tests/wireguard/generated.nix
new file mode 100644
index 000000000000..897feafe3ff2
--- /dev/null
+++ b/nixpkgs/nixos/tests/wireguard/generated.nix
@@ -0,0 +1,57 @@
+import ../make-test.nix ({ pkgs, ...} : {
+  name = "wireguard-generated";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ ma27 grahamc ];
+  };
+
+  nodes = {
+    peer1 = {
+      networking.firewall.allowedUDPPorts = [ 12345 ];
+      networking.wireguard.interfaces.wg0 = {
+        ips = [ "10.10.10.1/24" ];
+        listenPort = 12345;
+        privateKeyFile = "/etc/wireguard/private";
+        generatePrivateKeyFile = true;
+
+      };
+    };
+
+    peer2 = {
+      networking.firewall.allowedUDPPorts = [ 12345 ];
+      networking.wireguard.interfaces.wg0 = {
+        ips = [ "10.10.10.2/24" ];
+        listenPort = 12345;
+        privateKeyFile = "/etc/wireguard/private";
+        generatePrivateKeyFile = true;
+      };
+    };
+  };
+
+  testScript = ''
+    startAll;
+
+    $peer1->waitForUnit("wireguard-wg0.service");
+    $peer2->waitForUnit("wireguard-wg0.service");
+
+    my ($retcode, $peer1pubkey) = $peer1->execute("wg pubkey < /etc/wireguard/private");
+    $peer1pubkey =~ s/\s+$//;
+    if ($retcode != 0) {
+      die "Could not read public key from peer1";
+    }
+
+    my ($retcode, $peer2pubkey) = $peer2->execute("wg pubkey < /etc/wireguard/private");
+    $peer2pubkey =~ s/\s+$//;
+    if ($retcode != 0) {
+      die "Could not read public key from peer2";
+    }
+
+    $peer1->succeed("wg set wg0 peer $peer2pubkey allowed-ips 10.10.10.2/32 endpoint 192.168.1.2:12345 persistent-keepalive 1");
+    $peer1->succeed("ip route replace 10.10.10.2/32 dev wg0 table main");
+
+    $peer2->succeed("wg set wg0 peer $peer1pubkey allowed-ips 10.10.10.1/32 endpoint 192.168.1.1:12345 persistent-keepalive 1");
+    $peer2->succeed("ip route replace 10.10.10.1/32 dev wg0 table main");
+
+    $peer1->succeed("ping -c1 10.10.10.2");
+    $peer2->succeed("ping -c1 10.10.10.1");
+  '';
+})