about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/services
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/services')
-rw-r--r--nixpkgs/nixos/modules/services/backup/borgbackup.nix3
-rw-r--r--nixpkgs/nixos/modules/services/backup/postgresql-backup.nix51
-rw-r--r--nixpkgs/nixos/modules/services/backup/restic.nix7
-rw-r--r--nixpkgs/nixos/modules/services/databases/cassandra.nix22
-rw-r--r--nixpkgs/nixos/modules/services/databases/mysql.nix6
-rw-r--r--nixpkgs/nixos/modules/services/desktops/gnome3/file-roller.nix32
-rw-r--r--nixpkgs/nixos/modules/services/desktops/gnome3/gnome-keyring.nix2
-rw-r--r--nixpkgs/nixos/modules/services/games/minecraft-server.nix201
-rw-r--r--nixpkgs/nixos/modules/services/hardware/fwupd.nix26
-rw-r--r--nixpkgs/nixos/modules/services/hardware/lirc.nix6
-rw-r--r--nixpkgs/nixos/modules/services/hardware/tlp.nix2
-rw-r--r--nixpkgs/nixos/modules/services/hardware/vdr.nix14
-rw-r--r--nixpkgs/nixos/modules/services/misc/gitea.nix17
-rw-r--r--nixpkgs/nixos/modules/services/misc/gitlab.nix7
-rw-r--r--nixpkgs/nixos/modules/services/misc/home-assistant.nix79
-rw-r--r--nixpkgs/nixos/modules/services/misc/nzbget.nix23
-rw-r--r--nixpkgs/nixos/modules/services/misc/plex.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/pykms.nix67
-rw-r--r--nixpkgs/nixos/modules/services/misc/redmine.nix38
-rw-r--r--nixpkgs/nixos/modules/services/misc/sonarr.nix60
-rw-r--r--nixpkgs/nixos/modules/services/misc/weechat.xml4
-rw-r--r--nixpkgs/nixos/modules/services/misc/zoneminder.nix362
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/collectd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/grafana.nix184
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/munin.nix209
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/netdata.nix25
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix3
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix1
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix55
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix24
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/glusterfs.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/ddclient.nix3
-rw-r--r--nixpkgs/nixos/modules/services/networking/firefox/sync-server.nix26
-rw-r--r--nixpkgs/nixos/modules/services/networking/ndppd.nix170
-rw-r--r--nixpkgs/nixos/modules/services/networking/nsd.nix12
-rw-r--r--nixpkgs/nixos/modules/services/networking/nylon.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/prosody.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/shairport-sync.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/ssh/sshd.nix9
-rw-r--r--nixpkgs/nixos/modules/services/networking/syncthing.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/unifi.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/xrdp.nix6
-rw-r--r--nixpkgs/nixos/modules/services/search/elasticsearch-curator.nix5
-rw-r--r--nixpkgs/nixos/modules/services/security/certmgr.nix11
-rw-r--r--nixpkgs/nixos/modules/services/security/munge.nix2
-rw-r--r--nixpkgs/nixos/modules/services/security/nginx-sso.nix58
-rw-r--r--nixpkgs/nixos/modules/services/security/sks.nix28
-rw-r--r--nixpkgs/nixos/modules/services/security/sshguard.nix99
-rw-r--r--nixpkgs/nixos/modules/services/system/kerberos.nix64
-rw-r--r--nixpkgs/nixos/modules/services/system/kerberos/default.nix80
-rw-r--r--nixpkgs/nixos/modules/services/system/kerberos/heimdal.nix68
-rw-r--r--nixpkgs/nixos/modules/services/system/kerberos/mit.nix68
-rw-r--r--nixpkgs/nixos/modules/services/torrent/transmission.nix3
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/atlassian/confluence.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/atlassian/crowd.nix5
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/atlassian/jira.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/nextcloud.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix25
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/apache-httpd/wordpress.nix8
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/lighttpd/collectd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix31
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/phpfpm/pool-options.nix15
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix65
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/lxqt.nix11
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix10
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/default.nix4
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix35
-rw-r--r--nixpkgs/nixos/modules/services/x11/urxvtd.nix28
70 files changed, 2130 insertions, 375 deletions
diff --git a/nixpkgs/nixos/modules/services/backup/borgbackup.nix b/nixpkgs/nixos/modules/services/backup/borgbackup.nix
index bf41aee8fe0e..2ad116a7872a 100644
--- a/nixpkgs/nixos/modules/services/backup/borgbackup.nix
+++ b/nixpkgs/nixos/modules/services/backup/borgbackup.nix
@@ -191,10 +191,9 @@ in {
         options = {
 
           paths = mkOption {
-            type = with types; either path (listOf str);
+            type = with types; coercedTo str lib.singleton (listOf str);
             description = "Path(s) to back up.";
             example = "/home/user";
-            apply = x: if isList x then x else [ x ];
           };
 
           repo = mkOption {
diff --git a/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix b/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix
index f9f9568faa5c..11efa47ec5b2 100644
--- a/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix
+++ b/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix
@@ -6,11 +6,11 @@ let
 
   cfg = config.services.postgresqlBackup;
 
-  postgresqlBackupService = db :
+  postgresqlBackupService = db: dumpCmd:
     {
       enable = true;
 
-      description = "Backup of database ${db}";
+      description = "Backup of ${db} database(s)";
 
       requires = [ "postgresql.service" ];
 
@@ -26,7 +26,7 @@ let
           ${pkgs.coreutils}/bin/mv ${cfg.location}/${db}.sql.gz ${cfg.location}/${db}.prev.sql.gz
         fi
 
-        ${config.services.postgresql.package}/bin/pg_dump ${cfg.pgdumpOptions} ${db} | \
+        ${dumpCmd} | \
           ${pkgs.gzip}/bin/gzip -c > ${cfg.location}/${db}.sql.gz
       '';
 
@@ -42,9 +42,7 @@ let
 in {
 
   options = {
-
     services.postgresqlBackup = {
-
       enable = mkOption {
         default = false;
         description = ''
@@ -61,6 +59,19 @@ in {
         '';
       };
 
+      backupAll = mkOption {
+        default = cfg.databases == [];
+        defaultText = "services.postgresqlBackup.databases == []";
+        type = lib.types.bool;
+        description = ''
+          Backup all databases using pg_dumpall.
+          This option is mutual exclusive to
+          <literal>services.postgresqlBackup.databases</literal>.
+          The resulting backup dump will have the name all.sql.gz.
+          This option is the default if no databases are specified.
+        '';
+      };
+
       databases = mkOption {
         default = [];
         description = ''
@@ -79,18 +90,36 @@ in {
         type = types.string;
         default = "-Cbo";
         description = ''
-          Command line options for pg_dump.
+          Command line options for pg_dump. This options is not used
+          if <literal>config.services.postgresqlBackup.backupAll</literal> is enabled.
+          Note that config.services.postgresqlBackup.backupAll is also active,
+          when no databases where specified.
         '';
       };
     };
 
   };
 
-  config = mkIf config.services.postgresqlBackup.enable {
-
-    systemd.services = listToAttrs (map (db : {
+  config = mkMerge [
+    {
+      assertions = [{
+        assertion = cfg.backupAll -> cfg.databases == [];
+        message = "config.services.postgresqlBackup.backupAll cannot be used together with config.services.postgresqlBackup.databases";
+      }];
+    }
+    (mkIf (cfg.enable && cfg.backupAll) {
+      systemd.services.postgresqlBackup =
+        postgresqlBackupService "all" "${config.services.postgresql.package}/bin/pg_dumpall";
+    })
+    (mkIf (cfg.enable && !cfg.backupAll) {
+      systemd.services = listToAttrs (map (db:
+        let
+          cmd = "${config.services.postgresql.package}/bin/pg_dump ${cfg.pgdumpOptions} ${db}";
+        in {
           name = "postgresqlBackup-${db}";
-          value = postgresqlBackupService db; } ) cfg.databases);
-  };
+          value = postgresqlBackupService db cmd;
+        }) cfg.databases);
+    })
+  ];
 
 }
diff --git a/nixpkgs/nixos/modules/services/backup/restic.nix b/nixpkgs/nixos/modules/services/backup/restic.nix
index 6ece5a9b5ad6..7e8e91e4b9c3 100644
--- a/nixpkgs/nixos/modules/services/backup/restic.nix
+++ b/nixpkgs/nixos/modules/services/backup/restic.nix
@@ -1,6 +1,11 @@
 { config, lib, pkgs, ... }:
 
 with lib;
+
+let
+  # Type for a valid systemd unit option. Needed for correctly passing "timerConfig" to "systemd.timers"
+  unitOption = (import ../../system/boot/systemd-unit-options.nix { inherit config lib; }).unitOption;
+in
 {
   options.services.restic.backups = mkOption {
     description = ''
@@ -47,7 +52,7 @@ with lib;
         };
 
         timerConfig = mkOption {
-          type = types.attrsOf types.str;
+          type = types.attrsOf unitOption;
           default = {
             OnCalendar = "daily";
           };
diff --git a/nixpkgs/nixos/modules/services/databases/cassandra.nix b/nixpkgs/nixos/modules/services/databases/cassandra.nix
index 86e74d5d5ab4..d741ee48c48f 100644
--- a/nixpkgs/nixos/modules/services/databases/cassandra.nix
+++ b/nixpkgs/nixos/modules/services/databases/cassandra.nix
@@ -34,11 +34,13 @@ let
     { name = "cassandra-etc";
       cassandraYaml = builtins.toJSON cassandraConfigWithAddresses;
       cassandraEnvPkg = "${cfg.package}/conf/cassandra-env.sh";
+      cassandraLogbackConfig = pkgs.writeText "logback.xml" cfg.logbackConfig;
       buildCommand = ''
         mkdir -p "$out"
 
         echo "$cassandraYaml" > "$out/cassandra.yaml"
         ln -s "$cassandraEnvPkg" "$out/cassandra-env.sh"
+        ln -s "$cassandraLogbackConfig" "$out/logback.xml"
       '';
     };
 in {
@@ -139,7 +141,27 @@ in {
         correspond to a single address, IP aliasing is not supported.
       '';
     };
+    logbackConfig = mkOption {
+      type = types.lines;
+      default = ''
+        <configuration scan="false">
+          <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+            <encoder>
+              <pattern>%-5level %date{HH:mm:ss,SSS} %msg%n</pattern>
+            </encoder>
+          </appender>
 
+          <root level="INFO">
+            <appender-ref ref="STDOUT" />
+          </root>
+
+          <logger name="com.thinkaurelius.thrift" level="ERROR"/>
+        </configuration>
+      '';
+      description = ''
+        XML logback configuration for cassandra
+      '';
+    };
     extraConfig = mkOption {
       type = types.attrs;
       default = {};
diff --git a/nixpkgs/nixos/modules/services/databases/mysql.nix b/nixpkgs/nixos/modules/services/databases/mysql.nix
index df6f3876585e..467feb09b3a3 100644
--- a/nixpkgs/nixos/modules/services/databases/mysql.nix
+++ b/nixpkgs/nixos/modules/services/databases/mysql.nix
@@ -249,6 +249,7 @@ in
 
         after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
+        restartTriggers = [ config.environment.etc."my.cnf".source ];
 
         unitConfig.RequiresMountsFor = "${cfg.dataDir}";
 
@@ -274,7 +275,8 @@ in
         serviceConfig = {
           Type = if hasNotify then "notify" else "simple";
           RuntimeDirectory = "mysqld";
-          ExecStart = "${mysql}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions}";
+          # The last two environment variables are used for starting Galera clusters
+          ExecStart = "${mysql}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION";
         };
 
         postStart = ''
@@ -362,7 +364,7 @@ in
             ${optionalString (cfg.ensureDatabases != []) ''
               (
               ${concatMapStrings (database: ''
-                echo "CREATE DATABASE IF NOT EXISTS ${database};"
+                echo "CREATE DATABASE IF NOT EXISTS \`${database}\`;"
               '') cfg.ensureDatabases}
               ) | ${mysql}/bin/mysql -u root -N
             ''}
diff --git a/nixpkgs/nixos/modules/services/desktops/gnome3/file-roller.nix b/nixpkgs/nixos/modules/services/desktops/gnome3/file-roller.nix
new file mode 100644
index 000000000000..7fb558a98953
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/desktops/gnome3/file-roller.nix
@@ -0,0 +1,32 @@
+# File Roller.
+
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.gnome3.file-roller = {
+
+      enable = mkEnableOption "File Roller, an archive manager for GNOME";
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.gnome3.file-roller.enable {
+
+    environment.systemPackages = [ pkgs.gnome3.file-roller ];
+
+    services.dbus.packages = [ pkgs.gnome3.file-roller ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-keyring.nix b/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-keyring.nix
index aa1165ab3bba..5ea4350be5b4 100644
--- a/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-keyring.nix
+++ b/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-keyring.nix
@@ -33,7 +33,7 @@ with lib;
 
     environment.systemPackages = [ pkgs.gnome3.gnome-keyring ];
 
-    services.dbus.packages = [ pkgs.gnome3.gnome-keyring pkgs.gnome3.gcr ];
+    services.dbus.packages = [ pkgs.gnome3.gnome-keyring pkgs.gcr ];
 
   };
 
diff --git a/nixpkgs/nixos/modules/services/games/minecraft-server.nix b/nixpkgs/nixos/modules/services/games/minecraft-server.nix
index f50d2897843a..7d26d1501650 100644
--- a/nixpkgs/nixos/modules/services/games/minecraft-server.nix
+++ b/nixpkgs/nixos/modules/services/games/minecraft-server.nix
@@ -4,8 +4,41 @@ with lib;
 
 let
   cfg = config.services.minecraft-server;
-in
-{
+
+  # We don't allow eula=false anyways
+  eulaFile = builtins.toFile "eula.txt" ''
+    # eula.txt managed by NixOS Configuration
+    eula=true
+  '';
+
+  whitelistFile = pkgs.writeText "whitelist.json"
+    (builtins.toJSON
+      (mapAttrsToList (n: v: { name = n; uuid = v; }) cfg.whitelist));
+
+  cfgToString = v: if builtins.isBool v then boolToString v else toString v;
+
+  serverPropertiesFile = pkgs.writeText "server.properties" (''
+    # server.properties managed by NixOS configuration
+  '' + concatStringsSep "\n" (mapAttrsToList
+    (n: v: "${n}=${cfgToString v}") cfg.serverProperties));
+
+
+  # To be able to open the firewall, we need to read out port values in the
+  # server properties, but fall back to the defaults when those don't exist.
+  # These defaults are from https://minecraft.gamepedia.com/Server.properties#Java_Edition_3
+  defaultServerPort = 25565;
+
+  serverPort = cfg.serverProperties.server-port or defaultServerPort;
+
+  rconPort = if cfg.serverProperties.enable-rcon or false
+    then cfg.serverProperties."rcon.port" or 25575
+    else null;
+
+  queryPort = if cfg.serverProperties.enable-query or false
+    then cfg.serverProperties."query.port" or 25565
+    else null;
+
+in {
   options = {
     services.minecraft-server = {
 
@@ -13,10 +46,32 @@ in
         type = types.bool;
         default = false;
         description = ''
-          If enabled, start a Minecraft Server. The listening port for
-          the server is always <literal>25565</literal>. The server
+          If enabled, start a Minecraft Server. The server
           data will be loaded from and saved to
-          <literal>${cfg.dataDir}</literal>.
+          <option>services.minecraft-server.dataDir</option>.
+        '';
+      };
+
+      declarative = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to use a declarative Minecraft server configuration.
+          Only if set to <literal>true</literal>, the options
+          <option>services.minecraft-server.whitelist</option> and
+          <option>services.minecraft-server.serverProperties</option> will be
+          applied.
+        '';
+      };
+
+      eula = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether you agree to
+          <link xlink:href="https://account.mojang.com/documents/minecraft_eula">
+          Mojangs EULA</link>. This option must be set to
+          <literal>true</literal> to run Minecraft server.
         '';
       };
 
@@ -24,7 +79,7 @@ in
         type = types.path;
         default = "/var/lib/minecraft";
         description = ''
-          Directory to store minecraft database and other state/data files.
+          Directory to store Minecraft database and other state/data files.
         '';
       };
 
@@ -32,21 +87,84 @@ in
         type = types.bool;
         default = false;
         description = ''
-          Whether to open ports in the firewall (if enabled) for the server.
+          Whether to open ports in the firewall for the server.
+        '';
+      };
+
+      whitelist = mkOption {
+        type = let
+          minecraftUUID = types.strMatching
+            "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" // {
+              description = "Minecraft UUID";
+            };
+          in types.attrsOf minecraftUUID;
+        default = {};
+        description = ''
+          Whitelisted players, only has an effect when
+          <option>services.minecraft-server.declarative</option> is
+          <literal>true</literal> and the whitelist is enabled
+          via <option>services.minecraft-server.serverProperties</option> by
+          setting <literal>white-list</literal> to <literal>true</literal>.
+          This is a mapping from Minecraft usernames to UUIDs.
+          You can use <link xlink:href="https://mcuuid.net/"/> to get a
+          Minecraft UUID for a username.
+        '';
+        example = literalExample ''
+          {
+            username1 = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
+            username2 = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy";
+          };
+        '';
+      };
+
+      serverProperties = mkOption {
+        type = with types; attrsOf (either bool (either int str));
+        default = {};
+        example = literalExample ''
+          {
+            server-port = 43000;
+            difficulty = 3;
+            gamemode = 1;
+            max-players = 5;
+            motd = "NixOS Minecraft server!";
+            white-list = true;
+            enable-rcon = true;
+            "rcon.password" = "hunter2";
+          }
+        '';
+        description = ''
+          Minecraft server properties for the server.properties file. Only has
+          an effect when <option>services.minecraft-server.declarative</option>
+          is set to <literal>true</literal>. See
+          <link xlink:href="https://minecraft.gamepedia.com/Server.properties#Java_Edition_3"/>
+          for documentation on these values.
         '';
       };
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.minecraft-server;
+        defaultText = "pkgs.minecraft-server";
+        example = literalExample "pkgs.minecraft-server_1_12_2";
+        description = "Version of minecraft-server to run.";
+      };
+
       jvmOpts = mkOption {
-        type = types.str;
+        type = types.separatedString " ";
         default = "-Xmx2048M -Xms2048M";
-        description = "JVM options for the Minecraft Service.";
+        # Example options from https://minecraft.gamepedia.com/Tutorials/Server_startup_script
+        example = "-Xmx2048M -Xms4092M -XX:+UseG1GC -XX:+CMSIncrementalPacing "
+          + "-XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 "
+          + "-XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10";
+        description = "JVM options for the Minecraft server.";
       };
     };
   };
 
   config = mkIf cfg.enable {
+
     users.users.minecraft = {
-      description     = "Minecraft Server Service user";
+      description     = "Minecraft server service user";
       home            = cfg.dataDir;
       createHome      = true;
       uid             = config.ids.uids.minecraft;
@@ -57,17 +175,60 @@ in
       wantedBy      = [ "multi-user.target" ];
       after         = [ "network.target" ];
 
-      serviceConfig.Restart = "always";
-      serviceConfig.User    = "minecraft";
-      script = ''
-        cd ${cfg.dataDir}
-        exec ${pkgs.minecraft-server}/bin/minecraft-server ${cfg.jvmOpts}
-      '';
-    };
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/minecraft-server ${cfg.jvmOpts}";
+        Restart = "always";
+        User = "minecraft";
+        WorkingDirectory = cfg.dataDir;
+      };
+
+      preStart = ''
+        ln -sf ${eulaFile} eula.txt
+      '' + (if cfg.declarative then ''
+
+        if [ -e .declarative ]; then
+
+          # Was declarative before, no need to back up anything
+          ln -sf ${whitelistFile} whitelist.json
+          cp -f ${serverPropertiesFile} server.properties
+
+        else
 
-    networking.firewall = mkIf cfg.openFirewall {
-      allowedUDPPorts = [ 25565 ];
-      allowedTCPPorts = [ 25565 ];
+          # Declarative for the first time, backup stateful files
+          ln -sb --suffix=.stateful ${whitelistFile} whitelist.json
+          cp -b --suffix=.stateful ${serverPropertiesFile} server.properties
+
+          # server.properties must have write permissions, because every time
+          # the server starts it first parses the file and then regenerates it..
+          chmod +w server.properties
+          echo "Autogenerated file that signifies that this server configuration is managed declaratively by NixOS" \
+            > .declarative
+
+        fi
+      '' else ''
+        if [ -e .declarative ]; then
+          rm .declarative
+        fi
+      '');
     };
+
+    networking.firewall = mkIf cfg.openFirewall (if cfg.declarative then {
+      allowedUDPPorts = [ serverPort ];
+      allowedTCPPorts = [ serverPort ]
+        ++ optional (! isNull queryPort) queryPort
+        ++ optional (! isNull rconPort) rconPort;
+    } else {
+      allowedUDPPorts = [ defaultServerPort ];
+      allowedTCPPorts = [ defaultServerPort ];
+    });
+
+    assertions = [
+      { assertion = cfg.eula;
+        message = "You must agree to Mojangs EULA to run minecraft-server."
+          + " Read https://account.mojang.com/documents/minecraft_eula and"
+          + " set `services.minecraft-server.eula` to `true` if you agree.";
+      }
+    ];
+
   };
 }
diff --git a/nixpkgs/nixos/modules/services/hardware/fwupd.nix b/nixpkgs/nixos/modules/services/hardware/fwupd.nix
index 7743f81fd622..cad9fa20de0f 100644
--- a/nixpkgs/nixos/modules/services/hardware/fwupd.nix
+++ b/nixpkgs/nixos/modules/services/hardware/fwupd.nix
@@ -15,6 +15,19 @@ let
       mkName = p: "pki/fwupd/${baseNameOf (toString p)}";
       mkEtcFile = p: nameValuePair (mkName p) { source = p; };
     in listToAttrs (map mkEtcFile cfg.extraTrustedKeys);
+
+  # We cannot include the file in $out and rely on filesInstalledToEtc
+  # to install it because it would create a cyclic dependency between
+  # the outputs. We also need to enable the remote,
+  # which should not be done by default.
+  testRemote = if cfg.enableTestRemote then {
+    "fwupd/remotes.d/fwupd-tests.conf" = {
+      source = pkgs.runCommand "fwupd-tests-enabled.conf" {} ''
+        sed "s,^Enabled=false,Enabled=true," \
+        "${pkgs.fwupd.installedTests}/etc/fwupd/remotes.d/fwupd-tests.conf" > "$out"
+      '';
+    };
+  } else {};
 in {
 
   ###### interface
@@ -40,7 +53,7 @@ in {
 
       blacklistPlugins = mkOption {
         type = types.listOf types.string;
-        default = [];
+        default = [ "test" ];
         example = [ "udev" ];
         description = ''
           Allow blacklisting specific plugins
@@ -55,6 +68,15 @@ in {
           Installing a public key allows firmware signed with a matching private key to be recognized as trusted, which may require less authentication to install than for untrusted files. By default trusted firmware can be upgraded (but not downgraded) without the user or administrator password. Only very few keys are installed by default.
         '';
       };
+
+      enableTestRemote = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable test remote. This is used by
+          <link xlink:href="https://github.com/hughsie/fwupd/blob/master/data/installed-tests/README.md">installed tests</link>.
+        '';
+      };
     };
   };
 
@@ -78,7 +100,7 @@ in {
         '';
       };
 
-    } // originalEtc // extraTrustedKeys;
+    } // originalEtc // extraTrustedKeys // testRemote;
 
     services.dbus.packages = [ pkgs.fwupd ];
 
diff --git a/nixpkgs/nixos/modules/services/hardware/lirc.nix b/nixpkgs/nixos/modules/services/hardware/lirc.nix
index 0072406a438c..826e512c75d1 100644
--- a/nixpkgs/nixos/modules/services/hardware/lirc.nix
+++ b/nixpkgs/nixos/modules/services/hardware/lirc.nix
@@ -32,7 +32,6 @@ in {
         default = [];
         description = "Extra arguments to lircd.";
       };
-
     };
   };
 
@@ -43,14 +42,15 @@ in {
     # Note: LIRC executables raises a warning, if lirc_options.conf do not exists
     environment.etc."lirc/lirc_options.conf".text = cfg.options;
 
+    passthru.lirc.socket = "/run/lirc/lircd";
+
     environment.systemPackages = [ pkgs.lirc ];
 
     systemd.sockets.lircd = {
       description = "LIRC daemon socket";
       wantedBy = [ "sockets.target" ];
       socketConfig = {
-        # default search path
-        ListenStream = "/run/lirc/lircd";
+        ListenStream = config.passthru.lirc.socket;
         SocketUser = "lirc";
         SocketMode = "0660";
       };
diff --git a/nixpkgs/nixos/modules/services/hardware/tlp.nix b/nixpkgs/nixos/modules/services/hardware/tlp.nix
index 68425822a884..b894025c0fd5 100644
--- a/nixpkgs/nixos/modules/services/hardware/tlp.nix
+++ b/nixpkgs/nixos/modules/services/hardware/tlp.nix
@@ -56,6 +56,8 @@ in
 
     powerManagement.scsiLinkPolicy = null;
     powerManagement.cpuFreqGovernor = null;
+    powerManagement.cpufreq.max = null;
+    powerManagement.cpufreq.min = null;
 
     systemd.sockets."systemd-rfkill".enable = false;
 
diff --git a/nixpkgs/nixos/modules/services/hardware/vdr.nix b/nixpkgs/nixos/modules/services/hardware/vdr.nix
index 75136a2f7964..4822506a899b 100644
--- a/nixpkgs/nixos/modules/services/hardware/vdr.nix
+++ b/nixpkgs/nixos/modules/services/hardware/vdr.nix
@@ -33,12 +33,14 @@ in {
         default = [];
         description = "Additional command line arguments to pass to VDR.";
       };
+
+      enableLirc = mkEnableOption "enable LIRC";
     };
   };
 
   ###### implementation
 
-  config = mkIf cfg.enable {
+  config = mkIf cfg.enable (mkMerge [{
     systemd.tmpfiles.rules = [
       "d ${cfg.videoDir} 0755 vdr vdr -"
       "Z ${cfg.videoDir} - vdr vdr -"
@@ -67,5 +69,13 @@ in {
     };
 
     users.groups.vdr = {};
-  };
+  }
+
+  (mkIf cfg.enableLirc {
+    services.lirc.enable = true;
+    users.users.vdr.extraGroups = [ "lirc" ];
+    services.vdr.extraArguments = [
+      "--lirc=${config.passthru.lirc.socket}"
+    ];
+  })]);
 }
diff --git a/nixpkgs/nixos/modules/services/misc/gitea.nix b/nixpkgs/nixos/modules/services/misc/gitea.nix
index 7a10bd872994..be4d38719785 100644
--- a/nixpkgs/nixos/modules/services/misc/gitea.nix
+++ b/nixpkgs/nixos/modules/services/misc/gitea.nix
@@ -46,6 +46,9 @@ let
     ROOT_PATH = ${cfg.log.rootPath}
     LEVEL = ${cfg.log.level}
 
+    [service]
+    DISABLE_REGISTRATION = ${boolToString cfg.disableRegistration}
+
     ${cfg.extraConfig}
   '';
 in
@@ -248,6 +251,18 @@ in
         description = "Upper level of template and static files path.";
       };
 
+      disableRegistration = mkEnableOption "the registration lock" // {
+        description = ''
+          By default any user can create an account on this <literal>gitea</literal> instance.
+          This can be disabled by using this option.
+
+          <emphasis>Note:</emphasis> please keep in mind that this should be added after the initial
+          deploy unless <link linkend="opt-services.gitea.useWizard">services.gitea.useWizard</link>
+          is <literal>true</literal> as the first registered user will be the administrator if
+          no install wizard is used.
+        '';
+      };
+
       extraConfig = mkOption {
         type = types.str;
         default = "";
@@ -263,7 +278,7 @@ in
       description = "gitea";
       after = [ "network.target" ] ++ lib.optional usePostgresql "postgresql.service" ++ lib.optional useMysql "mysql.service";
       wantedBy = [ "multi-user.target" ];
-      path = [ gitea.bin ];
+      path = [ gitea.bin pkgs.gitAndTools.git ];
 
       preStart = let
         runConfig = "${cfg.stateDir}/custom/conf/app.ini";
diff --git a/nixpkgs/nixos/modules/services/misc/gitlab.nix b/nixpkgs/nixos/modules/services/misc/gitlab.nix
index 769a9526cf64..25c258ebe134 100644
--- a/nixpkgs/nixos/modules/services/misc/gitlab.nix
+++ b/nixpkgs/nixos/modules/services/misc/gitlab.nix
@@ -497,7 +497,12 @@ in {
     systemd.services.gitaly = {
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      path = with pkgs; [ gitAndTools.git cfg.packages.gitaly.rubyEnv cfg.packages.gitaly.rubyEnv.wrappedRuby ];
+      path = with pkgs; [
+        openssh
+        gitAndTools.git
+        cfg.packages.gitaly.rubyEnv
+        cfg.packages.gitaly.rubyEnv.wrappedRuby
+      ];
       serviceConfig = {
         Type = "simple";
         User = cfg.user;
diff --git a/nixpkgs/nixos/modules/services/misc/home-assistant.nix b/nixpkgs/nixos/modules/services/misc/home-assistant.nix
index 2e9aa33aeeee..4eabda1d4188 100644
--- a/nixpkgs/nixos/modules/services/misc/home-assistant.nix
+++ b/nixpkgs/nixos/modules/services/misc/home-assistant.nix
@@ -6,9 +6,18 @@ let
   cfg = config.services.home-assistant;
 
   # cfg.config != null can be assumed here
-  configFile = pkgs.writeText "configuration.json"
+  configJSON = pkgs.writeText "configuration.json"
     (builtins.toJSON (if cfg.applyDefaultConfig then
-    (lib.recursiveUpdate defaultConfig cfg.config) else cfg.config));
+    (recursiveUpdate defaultConfig cfg.config) else cfg.config));
+  configFile = pkgs.runCommand "configuration.yaml" { } ''
+    ${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out
+  '';
+
+  lovelaceConfigJSON = pkgs.writeText "ui-lovelace.json"
+    (builtins.toJSON cfg.lovelaceConfig);
+  lovelaceConfigFile = pkgs.runCommand "ui-lovelace.yaml" { } ''
+    ${pkgs.remarshal}/bin/json2yaml -i ${lovelaceConfigJSON} -o $out
+  '';
 
   availableComponents = pkgs.home-assistant.availableComponents;
 
@@ -45,6 +54,8 @@ let
   defaultConfig = {
     homeassistant.time_zone = config.time.timeZone;
     http.server_port = (toString cfg.port);
+  } // optionalAttrs (cfg.lovelaceConfig != null) {
+    lovelace.mode = "yaml";
   };
 
 in {
@@ -99,6 +110,53 @@ in {
       '';
     };
 
+    configWritable = mkOption {
+      default = false;
+      type = types.bool;
+      description = ''
+        Whether to make <filename>configuration.yaml</filename> writable.
+        This only has an effect if <option>config</option> is set.
+        This will allow you to edit it from Home Assistant's web interface.
+        However, bear in mind that it will be overwritten at every start of the service.
+      '';
+    };
+
+    lovelaceConfig = mkOption {
+      default = null;
+      type = with types; nullOr attrs;
+      # from https://www.home-assistant.io/lovelace/yaml-mode/
+      example = literalExample ''
+        {
+          title = "My Awesome Home";
+          views = [ {
+            title = "Example";
+            cards = [ {
+              type = "markdown";
+              title = "Lovelace";
+              content = "Welcome to your **Lovelace UI**.";
+            } ];
+          } ];
+        }
+      '';
+      description = ''
+        Your <filename>ui-lovelace.yaml</filename> as a Nix attribute set.
+        Setting this option will automatically add
+        <literal>lovelace.mode = "yaml";</literal> to your <option>config</option>.
+        Beware that setting this option will delete your previous <filename>ui-lovelace.yaml</filename>
+      '';
+    };
+
+    lovelaceConfigWritable = mkOption {
+      default = false;
+      type = types.bool;
+      description = ''
+        Whether to make <filename>ui-lovelace.yaml</filename> writable.
+        This only has an effect if <option>lovelaceConfig</option> is set.
+        This will allow you to edit it from Home Assistant's web interface.
+        However, bear in mind that it will be overwritten at every start of the service.
+      '';
+    };
+
     package = mkOption {
       default = pkgs.home-assistant;
       defaultText = "pkgs.home-assistant";
@@ -144,12 +202,17 @@ in {
     systemd.services.home-assistant = {
       description = "Home Assistant";
       after = [ "network.target" ];
-      preStart = lib.optionalString (cfg.config != null) ''
-        config=${cfg.configDir}/configuration.yaml
-        rm -f $config
-        ${pkgs.remarshal}/bin/json2yaml -i ${configFile} -o $config
-        chmod 444 $config
-      '';
+      preStart = optionalString (cfg.config != null) (if cfg.configWritable then ''
+        cp --no-preserve=mode ${configFile} "${cfg.configDir}/configuration.yaml"
+      '' else ''
+        rm -f "${cfg.configDir}/configuration.yaml"
+        ln -s ${configFile} "${cfg.configDir}/configuration.yaml"
+      '') + optionalString (cfg.lovelaceConfig != null) (if cfg.lovelaceConfigWritable then ''
+        cp --no-preserve=mode ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml"
+      '' else ''
+        rm -f "${cfg.configDir}/ui-lovelace.yaml"
+        ln -s ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml"
+      '');
       serviceConfig = {
         ExecStart = "${package}/bin/hass --config '${cfg.configDir}'";
         User = "hass";
diff --git a/nixpkgs/nixos/modules/services/misc/nzbget.nix b/nixpkgs/nixos/modules/services/misc/nzbget.nix
index a472b6c7157c..e24cecf20807 100644
--- a/nixpkgs/nixos/modules/services/misc/nzbget.nix
+++ b/nixpkgs/nixos/modules/services/misc/nzbget.nix
@@ -16,6 +16,20 @@ in {
         description = "The NZBGet package to use";
       };
 
+      dataDir = mkOption {
+        type = types.str;
+        default = "/var/lib/nzbget";
+        description = "The directory where NZBGet stores its configuration files.";
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open ports in the firewall for the NZBGet web interface
+        '';
+      };
+
       user = mkOption {
         type = types.str;
         default = "nzbget";
@@ -40,7 +54,8 @@ in {
         p7zip
       ];
       preStart = ''
-        datadir=/var/lib/nzbget
+        datadir=${cfg.dataDir}
+        configfile=${cfg.dataDir}/nzbget.conf
         cfgtemplate=${cfg.package}/share/nzbget/nzbget.conf
         test -d $datadir || {
           echo "Creating nzbget data directory in $datadir"
@@ -60,7 +75,7 @@ in {
       '';
 
       script = ''
-        configfile=/var/lib/nzbget/nzbget.conf
+        configfile=${cfg.dataDir}/nzbget.conf
         args="--daemon --configfile $configfile"
         # The script in preStart (above) copies nzbget's config template to datadir on first run, containing paths that point to the nzbget derivation installed at the time. 
         # These paths break when nzbget is upgraded & the original derivation is garbage collected. If such broken paths are found in the config file, override them to point to 
@@ -86,6 +101,10 @@ in {
       };
     };
 
+    networking.firewall = mkIf cfg.openFirewall {
+      allowedTCPPorts = [ 8989 ];
+    };
+
     users.users = mkIf (cfg.user == "nzbget") {
       nzbget = {
         group = cfg.group;
diff --git a/nixpkgs/nixos/modules/services/misc/plex.nix b/nixpkgs/nixos/modules/services/misc/plex.nix
index 8fe5879c2764..e4810ce9f876 100644
--- a/nixpkgs/nixos/modules/services/misc/plex.nix
+++ b/nixpkgs/nixos/modules/services/misc/plex.nix
@@ -145,7 +145,7 @@ in
         PLEX_MEDIA_SERVER_HOME="${cfg.package}/usr/lib/plexmediaserver";
         PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS="6";
         PLEX_MEDIA_SERVER_TMPDIR="/tmp";
-        LD_LIBRARY_PATH="${cfg.package}/usr/lib/plexmediaserver";
+        LD_LIBRARY_PATH="/run/opengl-driver/lib:${cfg.package}/usr/lib/plexmediaserver";
         LC_ALL="en_US.UTF-8";
         LANG="en_US.UTF-8";
       };
diff --git a/nixpkgs/nixos/modules/services/misc/pykms.nix b/nixpkgs/nixos/modules/services/misc/pykms.nix
index a11296e1bd02..ef90d124a284 100644
--- a/nixpkgs/nixos/modules/services/misc/pykms.nix
+++ b/nixpkgs/nixos/modules/services/misc/pykms.nix
@@ -5,20 +5,8 @@ with lib;
 let
   cfg = config.services.pykms;
 
-  home = "/var/lib/pykms";
-
-  services = {
-    serviceConfig = {
-      Restart = "on-failure";
-      RestartSec = "10s";
-      StartLimitInterval = "1min";
-      PrivateTmp = true;
-      ProtectSystem = "full";
-      ProtectHome = true;
-    };
-  };
-
 in {
+  meta.maintainers = with lib.maintainers; [ peterhoeg ];
 
   options = {
     services.pykms = rec {
@@ -51,39 +39,38 @@ in {
         default = false;
         description = "Whether the listening port should be opened automatically.";
       };
+
+      memoryLimit = mkOption {
+        type = types.str;
+        default = "64M";
+        description = "How much memory to use at most.";
+      };
     };
   };
 
   config = mkIf cfg.enable {
     networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewallPort [ cfg.port ];
 
-    systemd.services = {
-      pykms = services // {
-        description = "Python KMS";
-        wantedBy = [ "multi-user.target" ];
-        serviceConfig = with pkgs; {
-          User = "pykms";
-          Group = "pykms";
-          ExecStartPre = "${getBin pykms}/bin/create_pykms_db.sh ${home}/clients.db";
-          ExecStart = "${getBin pykms}/bin/server.py ${optionalString cfg.verbose "--verbose"} ${cfg.listenAddress} ${toString cfg.port}";
-          WorkingDirectory = home;
-          MemoryLimit = "64M";
-        };
-      };
-    };
-
-    users = {
-      users.pykms = {
-        name = "pykms";
-        group = "pykms";
-        home  = home;
-        createHome = true;
-        uid = config.ids.uids.pykms;
-        description = "PyKMS daemon user";
-      };
-
-      groups.pykms = {
-        gid = config.ids.gids.pykms;
+    systemd.services.pykms = let
+      home = "/var/lib/pykms";
+    in {
+      description = "Python KMS";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      # python programs with DynamicUser = true require HOME to be set
+      environment.HOME = home;
+      serviceConfig = with pkgs; {
+        DynamicUser = true;
+        StateDirectory = baseNameOf home;
+        ExecStartPre = "${getBin pykms}/bin/create_pykms_db.sh ${home}/clients.db";
+        ExecStart = lib.concatStringsSep " " ([
+          "${getBin pykms}/bin/server.py"
+          cfg.listenAddress
+          (toString cfg.port)
+        ] ++ lib.optional cfg.verbose "--verbose");
+        WorkingDirectory = home;
+        Restart = "on-failure";
+        MemoryLimit = cfg.memoryLimit;
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/services/misc/redmine.nix b/nixpkgs/nixos/modules/services/misc/redmine.nix
index 8d25ac5cb76f..98e9c8953c84 100644
--- a/nixpkgs/nixos/modules/services/misc/redmine.nix
+++ b/nixpkgs/nixos/modules/services/misc/redmine.nix
@@ -30,6 +30,13 @@ let
     ${cfg.extraConfig}
   '';
 
+  additionalEnvironment = pkgs.writeText "additional_environment.rb" ''
+    config.logger = Logger.new("${cfg.stateDir}/log/production.log", 14, 1048576)
+    config.logger.level = Logger::INFO
+
+    ${cfg.extraEnv}
+  '';
+
   unpackTheme = unpack "theme";
   unpackPlugin = unpack "plugin";
   unpack = id: (name: source:
@@ -54,12 +61,20 @@ in
         description = "Enable the Redmine service.";
       };
 
+      # default to the 4.x series not forcing major version upgrade of those on the 3.x series
       package = mkOption {
         type = types.package;
-        default = pkgs.redmine;
+        default = if versionAtLeast config.system.stateVersion "19.03"
+          then pkgs.redmine_4
+          else pkgs.redmine
+        ;
         defaultText = "pkgs.redmine";
-        description = "Which Redmine package to use.";
-        example = "pkgs.redmine.override { ruby = pkgs.ruby_2_3; }";
+        description = ''
+          Which Redmine package to use. This defaults to version 3.x if
+          <literal>system.stateVersion &lt; 19.03</literal> and version 4.x
+          otherwise.
+        '';
+        example = "pkgs.redmine_4.override { ruby = pkgs.ruby_2_4; }";
       };
 
       user = mkOption {
@@ -103,6 +118,19 @@ in
         '';
       };
 
+      extraEnv = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra configuration in additional_environment.rb.
+
+          See https://svn.redmine.org/redmine/trunk/config/additional_environment.rb.example
+        '';
+        example = literalExample ''
+          config.logger.level = Logger::DEBUG
+        '';
+      };
+
       themes = mkOption {
         type = types.attrsOf types.path;
         default = {};
@@ -249,6 +277,9 @@ in
         # link in the application configuration
         ln -fs ${configurationYml} "${cfg.stateDir}/config/configuration.yml"
 
+        # link in the additional environment configuration
+        ln -fs ${additionalEnvironment} "${cfg.stateDir}/config/additional_environment.rb"
+
 
         # link in all user specified themes
         rm -rf "${cfg.stateDir}/public/themes/"*
@@ -292,6 +323,7 @@ in
         # execute redmine required commands prior to starting the application
         # NOTE: su required in case using mysql socket authentication
         /run/wrappers/bin/su -s ${pkgs.bash}/bin/bash -m -l redmine -c '${bundle} exec rake db:migrate'
+        /run/wrappers/bin/su -s ${pkgs.bash}/bin/bash -m -l redmine -c '${bundle} exec rake redmine:plugins:migrate'
         /run/wrappers/bin/su -s ${pkgs.bash}/bin/bash -m -l redmine -c '${bundle} exec rake redmine:load_default_data'
 
 
diff --git a/nixpkgs/nixos/modules/services/misc/sonarr.nix b/nixpkgs/nixos/modules/services/misc/sonarr.nix
index 97b67a0b5033..a99445a268d7 100644
--- a/nixpkgs/nixos/modules/services/misc/sonarr.nix
+++ b/nixpkgs/nixos/modules/services/misc/sonarr.nix
@@ -9,6 +9,32 @@ in
   options = {
     services.sonarr = {
       enable = mkEnableOption "Sonarr";
+
+      dataDir = mkOption {
+        type = types.str;
+        default = "/var/lib/sonarr/.config/NzbDrone";
+        description = "The directory where Sonarr stores its data files.";
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open ports in the firewall for the Sonarr web interface
+        '';
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "sonarr";
+        description = "User account under which Sonaar runs.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "sonarr";
+        description = "Group under which Sonaar runs.";
+      };
     };
   };
 
@@ -18,30 +44,38 @@ in
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       preStart = ''
-        test -d /var/lib/sonarr/ || {
-          echo "Creating sonarr data directory in /var/lib/sonarr/"
-          mkdir -p /var/lib/sonarr/
+        test -d ${cfg.dataDir} || {
+          echo "Creating sonarr data directory in ${cfg.dataDir}"
+          mkdir -p ${cfg.dataDir}
         }
-        chown -R sonarr:sonarr /var/lib/sonarr/
-        chmod 0700 /var/lib/sonarr/
+        chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}
+        chmod 0700 ${cfg.dataDir}
       '';
 
       serviceConfig = {
         Type = "simple";
-        User = "sonarr";
-        Group = "sonarr";
+        User = cfg.user;
+        Group = cfg.group;
         PermissionsStartOnly = "true";
-        ExecStart = "${pkgs.sonarr}/bin/NzbDrone --no-browser";
+        ExecStart = "${pkgs.sonarr}/bin/NzbDrone -nobrowser -data='${cfg.dataDir}'";
         Restart = "on-failure";
       };
     };
 
-    users.users.sonarr = {
-      uid = config.ids.uids.sonarr;
-      home = "/var/lib/sonarr";
-      group = "sonarr";
+    networking.firewall = mkIf cfg.openFirewall {
+      allowedTCPPorts = [ 8989 ];
+    };
+
+    users.users = mkIf (cfg.user == "sonarr") {
+      sonarr = {
+        group = cfg.group;
+        home = cfg.dataDir;
+        uid = config.ids.uids.sonarr;
+      };
     };
-    users.groups.sonarr.gid = config.ids.gids.sonarr;
 
+    users.groups = mkIf (cfg.group == "sonarr") {
+      sonarr.gid = config.ids.gids.sonarr;
+    };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/misc/weechat.xml b/nixpkgs/nixos/modules/services/misc/weechat.xml
index b7f755bbc5c7..7255edfb9da3 100644
--- a/nixpkgs/nixos/modules/services/misc/weechat.xml
+++ b/nixpkgs/nixos/modules/services/misc/weechat.xml
@@ -8,7 +8,7 @@
   <link xlink:href="https://weechat.org/">WeeChat</link> is a fast and
   extensible IRC client.
  </para>
- <section>
+ <section xml:id="module-services-weechat-basic-usage">
   <title>Basic Usage</title>
 
   <para>
@@ -35,7 +35,7 @@
    in the state directory <literal>/var/lib/weechat</literal>.
   </para>
  </section>
- <section>
+ <section xml:id="module-services-weechat-reattach">
   <title>Re-attaching to WeeChat</title>
 
   <para>
diff --git a/nixpkgs/nixos/modules/services/misc/zoneminder.nix b/nixpkgs/nixos/modules/services/misc/zoneminder.nix
new file mode 100644
index 000000000000..a40e9e846137
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/misc/zoneminder.nix
@@ -0,0 +1,362 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.zoneminder;
+  pkg = pkgs.zoneminder;
+
+  dirName = pkg.dirName;
+
+  user = "zoneminder";
+  group = {
+    nginx = config.services.nginx.group;
+    none  = user;
+  }."${cfg.webserver}";
+
+  useNginx = cfg.webserver == "nginx";
+
+  defaultDir = "/var/lib/${user}";
+  home = if useCustomDir then cfg.storageDir else defaultDir;
+
+  useCustomDir = !(builtins.isNull cfg.storageDir);
+
+  socket = "/run/phpfpm/${dirName}.sock";
+
+  zms = "/cgi-bin/zms";
+
+  dirs = dirList: [ dirName ] ++ map (e: "${dirName}/${e}") dirList;
+
+  cacheDirs = [ "swap" ];
+  libDirs   = [ "events" "exports" "images" "sounds" ];
+
+  dirStanzas = baseDir:
+    lib.concatStringsSep "\n" (map (e:
+      "ZM_DIR_${lib.toUpper e}=${baseDir}/${e}"
+      ) libDirs);
+
+  defaultsFile = pkgs.writeText "60-defaults.conf" ''
+    # 01-system-paths.conf
+    ${dirStanzas home}
+    ZM_PATH_ARP=${lib.getBin pkgs.nettools}/bin/arp
+    ZM_PATH_LOGS=/var/log/${dirName}
+    ZM_PATH_MAP=/dev/shm
+    ZM_PATH_SOCKS=/run/${dirName}
+    ZM_PATH_SWAP=/var/cache/${dirName}/swap
+    ZM_PATH_ZMS=${zms}
+
+    # 02-multiserver.conf
+    ZM_SERVER_HOST=
+
+    # Database
+    ZM_DB_TYPE=mysql
+    ZM_DB_HOST=${cfg.database.host}
+    ZM_DB_NAME=${cfg.database.name}
+    ZM_DB_USER=${cfg.database.username}
+    ZM_DB_PASS=${cfg.database.password}
+
+    # Web
+    ZM_WEB_USER=${user}
+    ZM_WEB_GROUP=${group}
+  '';
+
+  configFile = pkgs.writeText "80-nixos.conf" ''
+    # You can override defaults here
+
+    ${cfg.extraConfig}
+  '';
+
+  phpExtensions = with pkgs.phpPackages; [
+    { pkg = apcu; name = "apcu"; }
+  ];
+
+in {
+  options = {
+    services.zoneminder = with lib; {
+      enable = lib.mkEnableOption ''
+        ZoneMinder
+        </para><para>
+        If you intend to run the database locally, you should set
+        `config.services.zoneminder.database.createLocally` to true. Otherwise,
+        when set to `false` (the default), you will have to create the database
+        and database user as well as populate the database yourself.
+      '';
+
+      webserver = mkOption {
+        type = types.enum [ "nginx" "none" ];
+        default = "nginx";
+        description = ''
+          The webserver to configure for the PHP frontend.
+          </para>
+          <para>
+
+          Set it to `none` if you want to configure it yourself. PRs are welcome
+          for support for other web servers.
+        '';
+      };
+
+      hostname = mkOption {
+        type = types.str;
+        default = "localhost";
+        description = ''
+          The hostname on which to listen.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 8095;
+        description = ''
+          The port on which to listen.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open the firewall port(s).
+        '';
+      };
+
+      database = {
+        createLocally = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Create the database and database user locally.
+          '';
+        };
+
+        host = mkOption {
+          type = types.str;
+          default = "localhost";
+          description = ''
+            Hostname hosting the database.
+          '';
+        };
+
+        name = mkOption {
+          type = types.str;
+          default = "zm";
+          description = ''
+            Name of database.
+          '';
+        };
+
+        username = mkOption {
+          type = types.str;
+          default = "zmuser";
+          description = ''
+            Username for accessing the database.
+          '';
+        };
+
+        password = mkOption {
+          type = types.str;
+          default = "zmpass";
+          description = ''
+            Username for accessing the database.
+          '';
+        };
+      };
+
+      cameras = mkOption {
+        type = types.int;
+        default = 1;
+        description = ''
+          Set this to the number of cameras you expect to support.
+        '';
+      };
+
+      storageDir = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "/storage/tank";
+        description = ''
+          ZoneMinder can generate quite a lot of data, so in case you don't want
+          to use the default ${home}, you can override the path here.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional configuration added verbatim to the configuration file.
+        '';
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+
+    environment.etc = {
+      "zoneminder/60-defaults.conf".source = defaultsFile;
+      "zoneminder/80-nixos.conf".source    = configFile;
+    };
+
+    networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ];
+
+    services = {
+      fcgiwrap = lib.mkIf useNginx {
+        enable = true;
+        preforkProcesses = cfg.cameras;
+        inherit user group;
+      };
+
+      mysql = lib.mkIf cfg.database.createLocally {
+        ensureDatabases = [ cfg.database.name ];
+        ensureUsers = {
+          name = cfg.database.username;
+          ensurePermissions = [
+            { "${cfg.database.name}.*" = "ALL PRIVILEGES"; }
+          ];
+          initialDatabases = [
+            { inherit (cfg.database) name; schema = "${pkg}/share/zoneminder/db/zm_create.sql"; }
+          ];
+        };
+      };
+
+      nginx = lib.mkIf useNginx {
+        enable = true;
+        virtualHosts = {
+          "${cfg.hostname}" = {
+            default = true;
+            root = "${pkg}/share/zoneminder/www";
+            listen = [ { addr = "0.0.0.0"; inherit (cfg) port; } ];
+            extraConfig = let
+              fcgi = config.services.fcgiwrap;
+            in ''
+              index index.php;
+
+              location / {
+                try_files $uri $uri/ /index.php?$args =404;
+
+                location ~ /api/(css|img|ico) {
+                  rewrite ^/api(.+)$ /api/app/webroot/$1 break;
+                  try_files $uri $uri/ =404;
+                }
+
+                location ~ \.(gif|ico|jpg|jpeg|png)$ {
+                  access_log off;
+                  expires 30d;
+                }
+
+                location /api {
+                  rewrite ^/api(.+)$ /api/app/webroot/index.php?p=$1 last;
+                }
+
+                location /cgi-bin {
+                  gzip off;
+
+                  include ${pkgs.nginx}/conf/fastcgi_params;
+                  fastcgi_param SCRIPT_FILENAME ${pkg}/libexec/zoneminder/${zms};
+                  fastcgi_param HTTP_PROXY "";
+                  fastcgi_intercept_errors on;
+
+                  fastcgi_pass ${fcgi.socketType}:${fcgi.socketAddress};
+                }
+
+                location /cache {
+                  alias /var/cache/${dirName};
+                }
+
+                location ~ \.php$ {
+                  try_files $uri =404;
+                  fastcgi_index index.php;
+
+                  include ${pkgs.nginx}/conf/fastcgi_params;
+                  fastcgi_param SCRIPT_FILENAME $request_filename;
+                  fastcgi_param HTTP_PROXY "";
+
+                  fastcgi_pass unix:${socket};
+                }
+              }
+            '';
+          };
+        };
+      };
+
+      phpfpm = lib.mkIf useNginx {
+        phpOptions = ''
+          date.timezone = "${config.time.timeZone}"
+
+          ${lib.concatStringsSep "\n" (map (e:
+          "extension=${e.pkg}/lib/php/extensions/${e.name}.so") phpExtensions)}
+        '';
+        pools.zoneminder = {
+          listen = socket;
+          extraConfig = ''
+            user = ${user}
+            group = ${group}
+
+            listen.owner = ${user}
+            listen.group = ${group}
+            listen.mode = 0660
+
+            pm = dynamic
+            pm.start_servers = 1
+            pm.min_spare_servers = 1
+            pm.max_spare_servers = 2
+            pm.max_requests = 500
+            pm.max_children = 5
+            pm.status_path = /$pool-status
+            ping.path = /$pool-ping
+          '';
+        };
+      };
+    };
+
+    systemd.services = {
+      zoneminder = with pkgs; rec {
+        inherit (zoneminder.meta) description;
+        documentation = [ "https://zoneminder.readthedocs.org/en/latest/" ];
+        path = [
+          coreutils
+          procps
+          psmisc
+        ];
+        after = [ "mysql.service" "nginx.service" ];
+        wantedBy = [ "multi-user.target" ];
+        restartTriggers = [ defaultsFile configFile ];
+        preStart = lib.mkIf useCustomDir ''
+          install -dm775 -o ${user} -g ${group} ${cfg.storageDir}/{${lib.concatStringsSep "," libDirs}}
+        '';
+        serviceConfig = {
+          User = user;
+          Group = group;
+          SupplementaryGroups = [ "video" ];
+          ExecStart  = "${zoneminder}/bin/zmpkg.pl start";
+          ExecStop   = "${zoneminder}/bin/zmpkg.pl stop";
+          ExecReload = "${zoneminder}/bin/zmpkg.pl restart";
+          PIDFile = "/run/${dirName}/zm.pid";
+          Type = "forking";
+          Restart = "on-failure";
+          RestartSec = "10s";
+          CacheDirectory = dirs cacheDirs;
+          RuntimeDirectory = dirName;
+          ReadWriteDirectories = lib.mkIf useCustomDir [ cfg.storageDir ];
+          StateDirectory = dirs (if useCustomDir then [] else libDirs);
+          LogsDirectory = dirName;
+          PrivateTmp = true;
+          ProtectSystem = "strict";
+          ProtectKernelTunables = true;
+          SystemCallArchitectures = "native";
+          NoNewPrivileges = true;
+        };
+      };
+    };
+
+    users.groups."${user}" = {
+      gid = config.ids.gids.zoneminder;
+    };
+
+    users.users."${user}" = {
+      uid = config.ids.uids.zoneminder;
+      group = user;
+      inherit home;
+      inherit (pkgs.zoneminder.meta) description;
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ peterhoeg ];
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/collectd.nix b/nixpkgs/nixos/modules/services/monitoring/collectd.nix
index 6606980cdad8..45e3312c0f44 100644
--- a/nixpkgs/nixos/modules/services/monitoring/collectd.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/collectd.nix
@@ -88,6 +88,8 @@ in {
         ExecStart = "${cfg.package}/sbin/collectd -C ${conf} -f";
         User = cfg.user;
         PermissionsStartOnly = true;
+        Restart = "on-failure";
+        RestartSec = 3;
       };
 
       preStart = ''
diff --git a/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix b/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix
index 5434fe99347d..a4d29d45bacf 100644
--- a/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix
@@ -186,7 +186,7 @@ in {
       type = types.attrs;
       default = {
         init_config = {};
-        instances = [ { use-mount = "no"; } ];
+        instances = [ { use_mount = "false"; } ];
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/monitoring/grafana.nix b/nixpkgs/nixos/modules/services/monitoring/grafana.nix
index 5fb3e3771221..85879cfe0b33 100644
--- a/nixpkgs/nixos/modules/services/monitoring/grafana.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/grafana.nix
@@ -50,6 +50,158 @@ let
     SMTP_FROM_ADDRESS = cfg.smtp.fromAddress;
   } // cfg.extraOptions;
 
+  datasourceConfiguration = {
+    apiVersion = 1;
+    datasources = cfg.provision.datasources;
+  };
+
+  datasourceFile = pkgs.writeText "datasource.yaml" (builtins.toJSON datasourceConfiguration);
+
+  dashboardConfiguration = {
+    apiVersion = 1;
+    providers = cfg.provision.dashboards;
+  };
+
+  dashboardFile = pkgs.writeText "dashboard.yaml" (builtins.toJSON dashboardConfiguration);
+
+  provisionConfDir =  pkgs.runCommand "grafana-provisioning" { } ''
+    mkdir -p $out/{datasources,dashboards}
+    ln -sf ${datasourceFile} $out/datasources/datasource.yaml
+    ln -sf ${dashboardFile} $out/dashboards/dashboard.yaml
+  '';
+
+  # Get a submodule without any embedded metadata:
+  _filter = x: filterAttrs (k: v: k != "_module") x;
+
+  # http://docs.grafana.org/administration/provisioning/#datasources
+  grafanaTypes.datasourceConfig = types.submodule {
+    options = {
+      name = mkOption {
+        type = types.str;
+        description = "Name of the datasource. Required";
+      };
+      type = mkOption {
+        type = types.enum ["graphite" "prometheus" "cloudwatch" "elasticsearch" "influxdb" "opentsdb" "mysql" "mssql" "postgres" "loki"];
+        description = "Datasource type. Required";
+      };
+      access = mkOption {
+        type = types.enum ["proxy" "direct"];
+        default = "proxy";
+        description = "Access mode. proxy or direct (Server or Browser in the UI). Required";
+      };
+      orgId = mkOption {
+        type = types.int;
+        default = 1;
+        description = "Org id. will default to orgId 1 if not specified";
+      };
+      url = mkOption {
+        type = types.str;
+        description = "Url of the datasource";
+      };
+      password = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "Database password, if used";
+      };
+      user = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "Database user, if used";
+      };
+      database = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "Database name, if used";
+      };
+      basicAuth = mkOption {
+        type = types.nullOr types.bool;
+        default = null;
+        description = "Enable/disable basic auth";
+      };
+      basicAuthUser = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "Basic auth username";
+      };
+      basicAuthPassword = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "Basic auth password";
+      };
+      withCredentials = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Enable/disable with credentials headers";
+      };
+      isDefault = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Mark as default datasource. Max one per org";
+      };
+      jsonData = mkOption {
+        type = types.nullOr types.attrs;
+        default = null;
+        description = "Datasource specific configuration";
+      };
+      secureJsonData = mkOption {
+        type = types.nullOr types.attrs;
+        default = null;
+        description = "Datasource specific secure configuration";
+      };
+      version = mkOption {
+        type = types.int;
+        default = 1;
+        description = "Version";
+      };
+      editable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Allow users to edit datasources from the UI.";
+      };
+    };
+  };
+
+  # http://docs.grafana.org/administration/provisioning/#dashboards
+  grafanaTypes.dashboardConfig = types.submodule {
+    options = {
+      name = mkOption {
+        type = types.str;
+        default = "default";
+        description = "Provider name";
+      };
+      orgId = mkOption {
+        type = types.int;
+        default = 1;
+        description = "Organization ID";
+      };
+      folder = mkOption {
+        type = types.str;
+        default = "";
+        description = "Add dashboards to the speciied folder";
+      };
+      type = mkOption {
+        type = types.str;
+        default = "file";
+        description = "Dashboard provider type";
+      };
+      disableDeletion = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Disable deletion when JSON file is removed";
+      };
+      updateIntervalSeconds = mkOption {
+        type = types.int;
+        default = 10;
+        description = "How often Grafana will scan for changed dashboards";
+      };
+      options = {
+        path = mkOption {
+          type = types.path;
+          description = "Path grafana will watch for dashboards";
+        };
+      };
+    };
+  };
 in {
   options.services.grafana = {
     enable = mkEnableOption "grafana";
@@ -175,6 +327,22 @@ in {
       };
     };
 
+    provision = {
+      enable = mkEnableOption "provision";
+      datasources = mkOption {
+        description = "Grafana datasources configuration";
+        default = [];
+        type = types.listOf grafanaTypes.datasourceConfig;
+        apply = x: map _filter x;
+      };
+      dashboards = mkOption {
+        description = "Grafana dashboard configuration";
+        default = [];
+        type = types.listOf grafanaTypes.dashboardConfig;
+        apply = x: map _filter x;
+      };
+    };
+
     security = {
       adminUser = mkOption {
         description = "Default admin username.";
@@ -313,10 +481,15 @@ in {
   };
 
   config = mkIf cfg.enable {
-    warnings = optional (
-      cfg.database.password != opt.database.password.default ||
-      cfg.security.adminPassword != opt.security.adminPassword.default
-    ) "Grafana passwords will be stored as plaintext in the Nix store!";
+    warnings = flatten [
+      (optional (
+        cfg.database.password != opt.database.password.default ||
+        cfg.security.adminPassword != opt.security.adminPassword.default
+      ) "Grafana passwords will be stored as plaintext in the Nix store!")
+      (optional (
+        any (x: x.password != null || x.basicAuthPassword != null || x.secureJsonData != null) cfg.provision.datasources
+      ) "Datasource passwords will be stored as plaintext in the Nix store!")
+    ];
 
     environment.systemPackages = [ cfg.package ];
 
@@ -359,6 +532,9 @@ in {
         ${optionalString (cfg.smtp.passwordFile != null) ''
           export GF_SMTP_PASSWORD="$(cat ${escapeShellArg cfg.smtp.passwordFile})"
         ''}
+        ${optionalString cfg.provision.enable ''
+          export GF_PATHS_PROVISIONING=${provisionConfDir};
+        ''}
         exec ${cfg.package.bin}/bin/grafana-server -homepath ${cfg.dataDir}
       '';
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/monitoring/munin.nix b/nixpkgs/nixos/modules/services/monitoring/munin.nix
index 2b265d5b5a90..f67986327245 100644
--- a/nixpkgs/nixos/modules/services/monitoring/munin.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/munin.nix
@@ -4,7 +4,7 @@
 # TODO: LWP/Pg perl libs aren't recognized
 
 # TODO: support fastcgi
-# http://munin-monitoring.org/wiki/CgiHowto2
+# http://guide.munin-monitoring.org/en/latest/example/webserver/apache-cgi.html
 # 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
@@ -24,6 +24,8 @@ let
       logdir    /var/log/munin
       rundir    /run/munin
 
+      ${lib.optionalString (cronCfg.extraCSS != "") "staticdir ${customStaticDir}"}
+
       ${cronCfg.extraGlobalConfig}
 
       ${cronCfg.hosts}
@@ -63,6 +65,11 @@ let
       [ipmi*]
       user root
       group root
+
+      [munin*]
+      env.UPDATE_STATSFILE /var/lib/munin/munin-update.stats
+
+      ${nodeCfg.extraPluginConfig}
     '';
 
   pluginConfDir = pkgs.stdenv.mkDerivation {
@@ -72,6 +79,54 @@ let
       ln -s ${pluginConf} $out/nixos-config
     '';
   };
+
+  # Copy one Munin plugin into the Nix store with a specific name.
+  # This is suitable for use with plugins going directly into /etc/munin/plugins,
+  # i.e. munin.extraPlugins.
+  internOnePlugin = name: path:
+    "cp -a '${path}' '${name}'";
+
+  # Copy an entire tree of Munin plugins into a single directory in the Nix
+  # store, with no renaming.
+  # This is suitable for use with munin-node-configure --suggest, i.e.
+  # munin.extraAutoPlugins.
+  internManyPlugins = name: path:
+    "find '${path}' -type f -perm /a+x -exec cp -a -t . '{}' '+'";
+
+  # Use the appropriate intern-fn to copy the plugins into the store and patch
+  # them afterwards in an attempt to get them to run on NixOS.
+  internAndFixPlugins = name: intern-fn: paths:
+    pkgs.runCommand name {} ''
+      mkdir -p "$out"
+      cd "$out"
+      ${lib.concatStringsSep "\n"
+          (lib.attrsets.mapAttrsToList intern-fn paths)}
+      chmod -R u+w .
+      find . -type f -exec sed -E -i '
+        s,(/usr)?/s?bin/,/run/current-system/sw/bin/,g
+      ' '{}' '+'
+    '';
+
+  # TODO: write a derivation for munin-contrib, so that for contrib plugins
+  # you can just refer to them by name rather than needing to include a copy
+  # of munin-contrib in your nixos configuration.
+  extraPluginDir = internAndFixPlugins "munin-extra-plugins.d"
+    internOnePlugin nodeCfg.extraPlugins;
+
+  extraAutoPluginDir = internAndFixPlugins "munin-extra-auto-plugins.d"
+    internManyPlugins
+    (builtins.listToAttrs
+      (map
+        (path: { name = baseNameOf path; value = path; })
+        nodeCfg.extraAutoPlugins));
+
+  customStaticDir = pkgs.runCommand "munin-custom-static-data" {} ''
+    cp -a "${pkgs.munin}/etc/opt/munin/static" "$out"
+    cd "$out"
+    chmod -R u+w .
+    echo "${cronCfg.extraCSS}" >> style.css
+    echo "${cronCfg.extraCSS}" >> style-new.css
+  '';
 in
 
 {
@@ -82,11 +137,12 @@ in
 
       enable = mkOption {
         default = false;
+        type = types.bool;
         description = ''
           Enable Munin Node agent. Munin node listens on 0.0.0.0 and
           by default accepts connections only from 127.0.0.1 for security reasons.
 
-          See <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' />.
+          See <link xlink:href='http://guide.munin-monitoring.org/en/latest/architecture/index.html' />.
         '';
       };
 
@@ -95,18 +151,108 @@ in
         type = types.lines;
         description = ''
           <filename>munin-node.conf</filename> extra configuration. See
-          <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' />
+          <link xlink:href='http://guide.munin-monitoring.org/en/latest/reference/munin-node.conf.html' />
+        '';
+      };
+
+      extraPluginConfig = mkOption {
+        default = "";
+        type = types.lines;
+        description = ''
+          <filename>plugin-conf.d</filename> extra plugin configuration. See
+          <link xlink:href='http://guide.munin-monitoring.org/en/latest/plugin/use.html' />
+        '';
+        example = ''
+          [fail2ban_*]
+          user root
         '';
       };
 
-      # TODO: add option to add additional plugins
+      extraPlugins = mkOption {
+        default = {};
+        type = with types; attrsOf path;
+        description = ''
+          Additional Munin plugins to activate. Keys are the name of the plugin
+          symlink, values are the path to the underlying plugin script. You
+          can use the same plugin script multiple times (e.g. for wildcard
+          plugins).
+
+          Note that these plugins do not participate in autoconfiguration. If
+          you want to autoconfigure additional plugins, use
+          <option>services.munin-node.extraAutoPlugins</option>.
+
+          Plugins enabled in this manner take precedence over autoconfigured
+          plugins.
+
+          Plugins will be copied into the Nix store, and it will attempt to
+          modify them to run properly by fixing hardcoded references to
+          <literal>/bin</literal>, <literal>/usr/bin</literal>,
+          <literal>/sbin</literal>, and <literal>/usr/sbin</literal>.
+        '';
+        example = literalExample ''
+          {
+            zfs_usage_bigpool = /src/munin-contrib/plugins/zfs/zfs_usage_;
+            zfs_usage_smallpool = /src/munin-contrib/plugins/zfs/zfs_usage_;
+            zfs_list = /src/munin-contrib/plugins/zfs/zfs_list;
+          };
+        '';
+      };
 
+      extraAutoPlugins = mkOption {
+        default = [];
+        type = with types; listOf path;
+        description = ''
+          Additional Munin plugins to autoconfigure, using
+          <literal>munin-node-configure --suggest</literal>. These should be
+          the actual paths to the plugin files (or directories containing them),
+          not just their names.
+
+          If you want to manually enable individual plugins instead, use
+          <option>services.munin-node.extraPlugins</option>.
+
+          Note that only plugins that have the 'autoconfig' capability will do
+          anything if listed here, since plugins that cannot autoconfigure
+          won't be automatically enabled by
+          <literal>munin-node-configure</literal>.
+
+          Plugins will be copied into the Nix store, and it will attempt to
+          modify them to run properly by fixing hardcoded references to
+          <literal>/bin</literal>, <literal>/usr/bin</literal>,
+          <literal>/sbin</literal>, and <literal>/usr/sbin</literal>.
+        '';
+        example = literalExample ''
+          [
+            /src/munin-contrib/plugins/zfs
+            /src/munin-contrib/plugins/ssh
+          ];
+        '';
+      };
+
+      disabledPlugins = mkOption {
+        # TODO: figure out why Munin isn't writing the log file and fix it.
+        # In the meantime this at least suppresses a useless graph full of
+        # NaNs in the output.
+        default = [ "munin_stats" ];
+        type = with types; listOf string;
+        description = ''
+          Munin plugins to disable, even if
+          <literal>munin-node-configure --suggest</literal> tries to enable
+          them. To disable a wildcard plugin, use an actual wildcard, as in
+          the example.
+
+          munin_stats is disabled by default as it tries to read
+          <literal>/var/log/munin/munin-update.log</literal> for timing
+          information, and the NixOS build of Munin does not write this file.
+        '';
+        example = [ "diskstats" "zfs_usage_*" ];
+      };
     };
 
     services.munin-cron = {
 
       enable = mkOption {
         default = false;
+        type = types.bool;
         description = ''
           Enable munin-cron. Takes care of all heavy lifting to collect data from
           nodes and draws graphs to html. Runs munin-update, munin-limits,
@@ -119,11 +265,12 @@ in
 
       extraGlobalConfig = mkOption {
         default = "";
+        type = types.lines;
         description = ''
           <filename>munin.conf</filename> extra global configuration.
-          See <link xlink:href='http://munin-monitoring.org/wiki/munin.conf' />.
+          See <link xlink:href='http://guide.munin-monitoring.org/en/latest/reference/munin.conf.html' />.
           Useful to setup notifications, see
-          <link xlink:href='http://munin-monitoring.org/wiki/HowToContact' />
+          <link xlink:href='http://guide.munin-monitoring.org/en/latest/tutorial/alert.html' />
         '';
         example = ''
           contact.email.command mail -s "Munin notification for ''${var:host}" someone@example.com
@@ -131,14 +278,34 @@ in
       };
 
       hosts = mkOption {
+        default = "";
+        type = types.lines;
+        description = ''
+          Definitions of hosts of nodes to collect data from. Needs at least one
+          host for cron to succeed. See
+          <link xlink:href='http://guide.munin-monitoring.org/en/latest/reference/munin.conf.html' />
+        '';
         example = ''
           [''${config.networking.hostName}]
           address localhost
         '';
+      };
+
+      extraCSS = mkOption {
+        default = "";
+        type = types.lines;
         description = ''
-          Definitions of hosts of nodes to collect data from. Needs at least one
-          hosts for cron to succeed. See
-          <link xlink:href='http://munin-monitoring.org/wiki/munin.conf' />
+          Custom styling for the HTML that munin-cron generates. This will be
+          appended to the CSS files used by munin-cron and will thus take
+          precedence over the builtin styles.
+        '';
+        example = ''
+          /* A simple dark theme. */
+          html, body { background: #222222; }
+          #header, #footer { background: #333333; }
+          img.i, img.iwarn, img.icrit, img.iunkn {
+            filter: invert(100%) hue-rotate(-30deg);
+          }
         '';
       };
 
@@ -155,6 +322,7 @@ in
       description = "Munin monitoring user";
       group = "munin";
       uid = config.ids.uids.munin;
+      home = "/var/lib/munin";
     }];
 
     users.groups = [{
@@ -173,14 +341,27 @@ in
       environment.MUNIN_PLUGSTATE = "/run/munin";
       environment.MUNIN_LOGDIR = "/var/log/munin";
       preStart = ''
-        echo "updating munin plugins..."
+        echo "Updating munin plugins..."
 
         mkdir -p /etc/munin/plugins
         rm -rf /etc/munin/plugins/*
+
+        # Autoconfigure builtin plugins
         ${pkgs.munin}/bin/munin-node-configure --suggest --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${pkgs.munin}/lib/plugins --servicedir=/etc/munin/plugins --sconfdir=${pluginConfDir} 2>/dev/null | ${pkgs.bash}/bin/bash
 
-        # NOTE: we disable disktstats because plugin seems to fail and it hangs html generation (100% CPU + memory leak)
-        rm /etc/munin/plugins/diskstats || true
+        # Autoconfigure extra plugins
+        ${pkgs.munin}/bin/munin-node-configure --suggest --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${extraAutoPluginDir} --servicedir=/etc/munin/plugins --sconfdir=${pluginConfDir} 2>/dev/null | ${pkgs.bash}/bin/bash
+
+        ${lib.optionalString (nodeCfg.extraPlugins != {}) ''
+            # Link in manually enabled plugins
+            ln -f -s -t /etc/munin/plugins ${extraPluginDir}/*
+          ''}
+
+        ${lib.optionalString (nodeCfg.disabledPlugins != []) ''
+            # Disable plugins
+            cd /etc/munin/plugins
+            rm -f ${toString nodeCfg.disabledPlugins}
+          ''}
       '';
       serviceConfig = {
         ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/ --sconfdir=${pluginConfDir}";
@@ -192,6 +373,10 @@ in
 
   }) (mkIf cronCfg.enable {
 
+    # Munin is hardcoded to use DejaVu Mono and the graphs come out wrong if
+    # it's not available.
+    fonts.fonts = [ pkgs.dejavu_fonts ];
+
     systemd.timers.munin-cron = {
       description = "batch Munin master programs";
       wantedBy = [ "timers.target" ];
diff --git a/nixpkgs/nixos/modules/services/monitoring/netdata.nix b/nixpkgs/nixos/modules/services/monitoring/netdata.nix
index 4873ab1fc608..1d86c5d893de 100644
--- a/nixpkgs/nixos/modules/services/monitoring/netdata.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/netdata.nix
@@ -10,9 +10,14 @@ let
     ln -s /run/wrappers/bin/apps.plugin $out/libexec/netdata/plugins.d/apps.plugin
   '';
 
+  plugins = [
+    "${pkgs.netdata}/libexec/netdata/plugins.d"
+    "${wrappedPlugins}/libexec/netdata/plugins.d"
+  ] ++ cfg.extraPluginPaths;
+
   localConfig = {
     global = {
-      "plugins directory" = "${pkgs.netdata}/libexec/netdata/plugins.d ${wrappedPlugins}/libexec/netdata/plugins.d";
+      "plugins directory" = concatStringsSep " " plugins;
     };
     web = {
       "web files owner" = "root";
@@ -78,6 +83,24 @@ in {
         };
       };
 
+      extraPluginPaths = mkOption {
+        type = types.listOf types.path;
+        default = [ ];
+        example = literalExample ''
+          [ "/path/to/plugins.d" ]
+        '';
+        description = ''
+          Extra paths to add to the netdata global "plugins directory"
+          option.  Useful for when you want to include your own
+          collection scripts.
+          </para><para>
+          Details about writing a custom netdata plugin are available at:
+          <link xlink:href="https://docs.netdata.cloud/collectors/plugins.d/"/>
+          </para><para>
+          Cannot be combined with configText.
+        '';
+      };
+
       config = mkOption {
         type = types.attrsOf types.attrs;
         default = {};
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
index bf4dfc666bb6..1b1503ab5fc0 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
@@ -325,7 +325,8 @@ let
   promTypes.relabel_config = types.submodule {
     options = {
       source_labels = mkOption {
-        type = types.listOf types.str;
+        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
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
index 5308c9c4ee08..0a084561002f 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -33,6 +33,7 @@ let
     tor       = import ./exporters/tor.nix       { inherit config lib pkgs; };
     unifi     = import ./exporters/unifi.nix     { inherit config lib pkgs; };
     varnish   = import ./exporters/varnish.nix   { inherit config lib pkgs; };
+    bind      = import ./exporters/bind.nix      { inherit config lib pkgs; };
   };
 
   mkExporterOpts = ({ name, port }: {
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix
new file mode 100644
index 000000000000..a9746c4d65d5
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix
@@ -0,0 +1,55 @@
+{ config, lib, pkgs }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.exporters.bind;
+in
+{
+  port = 9119;
+  extraOpts = {
+    bindURI = mkOption {
+      type = types.str;
+      default = "http://localhost:8053/";
+      description = ''
+        HTTP XML API address of an Bind server.
+      '';
+    };
+    bindTimeout = mkOption {
+      type = types.str;
+      default = "10s";
+      description = ''
+        Timeout for trying to get stats from Bind.
+      '';
+    };
+    bindVersion = mkOption {
+      type = types.enum [ "xml.v2" "xml.v3" "auto" ];
+      default = "auto";
+      description = ''
+        BIND statistics version. Can be detected automatically.
+      '';
+    };
+    bindGroups = mkOption {
+      type = types.listOf (types.enum [ "server" "view" "tasks" ]);
+      default = [ "server" "view" ];
+      description = ''
+        List of statistics to collect. Available: [server, view, tasks]
+      '';
+    };
+  };
+  serviceOpts = {
+    serviceConfig = {
+      DynamicUser = true;
+      ExecStart = ''
+        ${pkgs.prometheus-bind-exporter}/bin/bind_exporter \
+          -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+          -bind.pid-file /var/run/named/named.pid \
+          -bind.timeout ${toString cfg.bindTimeout} \
+          -bind.stats-url ${cfg.bindURI} \
+          -bind.stats-version ${cfg.bindVersion} \
+          -bind.stats-groups ${concatStringsSep "," cfg.bindGroups} \
+          ${concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix
index 4ca6d4e5f8b6..c47e87a3dc35 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix
@@ -18,12 +18,34 @@ in
     socketPath = mkOption {
       type = types.path;
       default = "/var/run/dovecot/stats";
-      example = "/var/run/dovecot2/stats";
+      example = "/var/run/dovecot2/old-stats";
       description = ''
         Path under which the stats socket is placed.
         The user/group under which the exporter runs,
         should be able to access the socket in order
         to scrape the metrics successfully.
+
+        Please keep in mind that the stats module has changed in
+        <link xlink:href="https://wiki2.dovecot.org/Upgrading/2.3">Dovecot 2.3+</link> which
+        is not <link xlink:href="https://github.com/kumina/dovecot_exporter/issues/8">compatible with this exporter</link>.
+
+        The following extra config has to be passed to Dovecot to ensure that recent versions
+        work with this exporter:
+        <programlisting>
+        {
+          <xref linkend="opt-services.prometheus.exporters.dovecot.enable" /> = true;
+          <xref linkend="opt-services.prometheus.exporters.dovecot.socketPath" /> = "/var/run/dovecot2/old-stats";
+          <xref linkend="opt-services.dovecot2.extraConfig" /> = '''
+            mail_plugins = $mail_plugins old_stats
+            service old-stats {
+              unix_listener old-stats {
+                user = nobody
+                group = nobody
+              }
+            }
+          ''';
+        }
+        </programlisting>
       '';
     };
     scopes = mkOption {
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/glusterfs.nix b/nixpkgs/nixos/modules/services/network-filesystems/glusterfs.nix
index eb7f060c7da0..00875c6c4a18 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/glusterfs.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/glusterfs.nix
@@ -201,7 +201,6 @@ in
 
       serviceConfig = {
         Type="simple";
-        Environment="PYTHONPATH=${glusterfs}/usr/lib/python2.7/site-packages";
         PIDFile="/run/glustereventsd.pid";
         ExecStart="${glusterfs}/sbin/glustereventsd --pid-file /run/glustereventsd.pid";
         ExecReload="/bin/kill -SIGUSR2 $MAINPID";
diff --git a/nixpkgs/nixos/modules/services/networking/ddclient.nix b/nixpkgs/nixos/modules/services/networking/ddclient.nix
index a70967820b32..9a2e13e9553c 100644
--- a/nixpkgs/nixos/modules/services/networking/ddclient.nix
+++ b/nixpkgs/nixos/modules/services/networking/ddclient.nix
@@ -182,10 +182,9 @@ with lib;
       serviceConfig = rec {
         DynamicUser = true;
         RuntimeDirectory = StateDirectory;
-        RuntimeDirectoryMode = "0750";
         StateDirectory = builtins.baseNameOf dataDir;
         Type = "oneshot";
-        ExecStartPre = "!${lib.getBin pkgs.coreutils}/bin/install -m660 ${cfg.configFile} /run/${RuntimeDirectory}/ddclient.conf";
+        ExecStartPre = "!${lib.getBin pkgs.coreutils}/bin/install -m666 ${cfg.configFile} /run/${RuntimeDirectory}/ddclient.conf";
         ExecStart = "${lib.getBin pkgs.ddclient}/bin/ddclient -file /run/${RuntimeDirectory}/ddclient.conf";
       };
     };
diff --git a/nixpkgs/nixos/modules/services/networking/firefox/sync-server.nix b/nixpkgs/nixos/modules/services/networking/firefox/sync-server.nix
index 97d223a56cab..6842aa735617 100644
--- a/nixpkgs/nixos/modules/services/networking/firefox/sync-server.nix
+++ b/nixpkgs/nixos/modules/services/networking/firefox/sync-server.nix
@@ -13,7 +13,7 @@ let
     overrides = ${cfg.privateConfig}
 
     [server:main]
-    use = egg:Paste#http
+    use = egg:gunicorn
     host = ${cfg.listen.address}
     port = ${toString cfg.listen.port}
 
@@ -30,6 +30,8 @@ let
     audiences = ${removeSuffix "/" cfg.publicUrl}
   '';
 
+  user = "syncserver";
+  group = "syncserver";
 in
 
 {
@@ -126,15 +128,14 @@ in
 
   config = mkIf cfg.enable {
 
-    systemd.services.syncserver = let
-      syncServerEnv = pkgs.python.withPackages(ps: with ps; [ syncserver pasteScript requests ]);
-      user = "syncserver";
-      group = "syncserver";
-    in {
+    systemd.services.syncserver = {
       after = [ "network.target" ];
       description = "Firefox Sync Server";
       wantedBy = [ "multi-user.target" ];
-      path = [ pkgs.coreutils syncServerEnv ];
+      path = [
+        pkgs.coreutils
+        (pkgs.python.withPackages (ps: [ pkgs.syncserver ps.gunicorn ]))
+      ];
 
       serviceConfig = {
         User = user;
@@ -166,14 +167,17 @@ in
           chown ${user}:${group} ${defaultDbLocation}
         fi
       '';
-      serviceConfig.ExecStart = "${syncServerEnv}/bin/paster serve ${syncServerIni}";
+
+      script = ''
+        gunicorn --paste ${syncServerIni}
+      '';
     };
 
-    users.users.syncserver = {
-      group = "syncserver";
+    users.users.${user} = {
+      inherit group;
       isSystemUser = true;
     };
 
-    users.groups.syncserver = {};
+    users.groups.${group} = {};
   };
 }
diff --git a/nixpkgs/nixos/modules/services/networking/ndppd.nix b/nixpkgs/nixos/modules/services/networking/ndppd.nix
index 1d6c48dd8d37..ba17f1ba825a 100644
--- a/nixpkgs/nixos/modules/services/networking/ndppd.nix
+++ b/nixpkgs/nixos/modules/services/networking/ndppd.nix
@@ -5,43 +5,163 @@ with lib;
 let
   cfg = config.services.ndppd;
 
-  configFile = pkgs.runCommand "ndppd.conf" {} ''
-    substitute ${pkgs.ndppd}/etc/ndppd.conf $out \
-      --replace eth0 ${cfg.interface} \
-      --replace 1111:: ${cfg.network}
-  '';
-in {
-  options = {
-    services.ndppd = {
-      enable = mkEnableOption "daemon that proxies NDP (Neighbor Discovery Protocol) messages between interfaces";
+  render = s: f: concatStringsSep "\n" (mapAttrsToList f s);
+  prefer = a: b: if a != null then a else b;
+
+  ndppdConf = prefer cfg.configFile (pkgs.writeText "ndppd.conf" ''
+    route-ttl ${toString cfg.routeTTL}
+    ${render cfg.proxies (proxyInterfaceName: proxy: ''
+    proxy ${prefer proxy.interface proxyInterfaceName} {
+      router ${boolToString proxy.router}
+      timeout ${toString proxy.timeout}
+      ttl ${toString proxy.ttl}
+      ${render proxy.rules (ruleNetworkName: rule: ''
+      rule ${prefer rule.network ruleNetworkName} {
+        ${rule.method}${if rule.method == "iface" then " ${rule.interface}" else ""}
+      }'')}
+    }'')}
+  '');
+
+  proxy = types.submodule {
+    options = {
       interface = mkOption {
-        type = types.string;
-        default = "eth0";
-        example = "ens3";
-        description = "Interface which is on link-level with router.";
+        type = types.nullOr types.str;
+        description = ''
+          Listen for any Neighbor Solicitation messages on this interface,
+          and respond to them according to a set of rules.
+          Defaults to the name of the attrset.
+        '';
+        default = null;
+      };
+      router = mkOption {
+        type = types.bool;
+        description = ''
+          Turns on or off the router flag for Neighbor Advertisement Messages.
+        '';
+        default = true;
+      };
+      timeout = mkOption {
+        type = types.int;
+        description = ''
+          Controls how long to wait for a Neighbor Advertisment Message before 
+          invalidating the entry, in milliseconds.
+        '';
+        default = 500;
+      };
+      ttl = mkOption {
+        type = types.int;
+        description = ''
+          Controls how long a valid or invalid entry remains in the cache, in 
+          milliseconds.
+        '';
+        default = 30000;
       };
+      rules = mkOption {
+        type = types.attrsOf rule;
+        description = ''
+          This is a rule that the target address is to match against. If no netmask
+          is provided, /128 is assumed. You may have several rule sections, and the
+          addresses may or may not overlap.
+        '';
+        default = {};
+      };
+    };
+  };
+
+  rule = types.submodule {
+    options = {
       network = mkOption {
-        type = types.string;
-        default = "1111::";
-        example = "2001:DB8::/32";
-        description = "Network that we proxy.";
+        type = types.nullOr types.str;
+        description = ''
+          This is the target address is to match against. If no netmask
+          is provided, /128 is assumed. The addresses of serveral rules
+          may or may not overlap.
+          Defaults to the name of the attrset.
+        '';
+        default = null;
+      };
+      method = mkOption {
+        type = types.enum [ "static" "iface" "auto" ];
+        description = ''
+          static: Immediately answer any Neighbor Solicitation Messages
+            (if they match the IP rule).
+          iface: Forward the Neighbor Solicitation Message through the specified
+            interface and only respond if a matching Neighbor Advertisement
+            Message is received.
+          auto: Same as iface, but instead of manually specifying the outgoing
+            interface, check for a matching route in /proc/net/ipv6_route.
+        '';
+        default = "auto";
       };
-      configFile = mkOption {
-        type = types.nullOr types.path;
+      interface = mkOption {
+        type = types.nullOr types.str;
+        description = "Interface to use when method is iface.";
         default = null;
-        description = "Path to configuration file.";
       };
     };
   };
 
+in {
+  options.services.ndppd = {
+    enable = mkEnableOption "daemon that proxies NDP (Neighbor Discovery Protocol) messages between interfaces";
+    interface = mkOption {
+      type = types.nullOr types.str;
+      description = ''
+        Interface which is on link-level with router.
+        (Legacy option, use services.ndppd.proxies.&lt;interface&gt;.rules.&lt;network&gt; instead)
+      '';
+      default = null;
+      example = "eth0";
+    };
+    network = mkOption {
+      type = types.nullOr types.str;
+      description = ''
+        Network that we proxy.
+        (Legacy option, use services.ndppd.proxies.&lt;interface&gt;.rules.&lt;network&gt; instead)
+      '';
+      default = null;
+      example = "1111::/64";
+    };
+    configFile = mkOption {
+      type = types.nullOr types.path;
+      description = "Path to configuration file.";
+      default = null;
+    };
+    routeTTL = mkOption {
+      type = types.int;
+      description = ''
+        This tells 'ndppd' how often to reload the route file /proc/net/ipv6_route,
+        in milliseconds.
+      '';
+      default = 30000;
+    };
+    proxies = mkOption {
+      type = types.attrsOf proxy;
+      description = ''
+        This sets up a listener, that will listen for any Neighbor Solicitation
+        messages, and respond to them according to a set of rules.
+      '';
+      default = {};
+      example = { "eth0".rules."1111::/64" = {}; };
+    };
+  };
+
   config = mkIf cfg.enable {
-    systemd.packages = [ pkgs.ndppd ];
-    environment.etc."ndppd.conf".source = if (cfg.configFile != null) then cfg.configFile else configFile;
+    warnings = mkIf (cfg.interface != null && cfg.network != null) [ ''
+      The options services.ndppd.interface and services.ndppd.network will probably be removed soon,
+      please use services.ndppd.proxies.<interface>.rules.<network> instead.
+    '' ];
+
+    services.ndppd.proxies = mkIf (cfg.interface != null && cfg.network != null) {
+      "${cfg.interface}".rules."${cfg.network}" = {};
+    };
+
     systemd.services.ndppd = {
-      serviceConfig.RuntimeDirectory = [ "ndppd" ];
+      description = "NDP Proxy Daemon";
+      documentation = [ "man:ndppd(1)" "man:ndppd.conf(5)" ];
+      after = [ "network-pre.target" ];
       wantedBy = [ "multi-user.target" ];
+      serviceConfig.ExecStart = "${pkgs.ndppd}/bin/ndppd -c ${ndppdConf}";
     };
   };
-
-  meta.maintainers = with maintainers; [ gnidorah ];
 }
diff --git a/nixpkgs/nixos/modules/services/networking/nsd.nix b/nixpkgs/nixos/modules/services/networking/nsd.nix
index cde47bf23eae..8b918dab86dd 100644
--- a/nixpkgs/nixos/modules/services/networking/nsd.nix
+++ b/nixpkgs/nixos/modules/services/networking/nsd.nix
@@ -435,7 +435,9 @@ let
 
   dnssecZones = (filterAttrs (n: v: if v ? dnssec then v.dnssec else false) zoneConfigs);
 
-  dnssec = length (attrNames dnssecZones) != 0; 
+  dnssec = dnssecZones != {};
+
+  dnssecTools = pkgs.bind.override { enablePython = true; };
 
   signZones = optionalString dnssec ''
     mkdir -p ${stateDir}/dnssec
@@ -445,8 +447,8 @@ let
     ${concatStrings (mapAttrsToList signZone dnssecZones)}
   '';
   signZone = name: zone: ''
-    ${pkgs.bind}/bin/dnssec-keymgr -g ${pkgs.bind}/bin/dnssec-keygen -s ${pkgs.bind}/bin/dnssec-settime -K ${stateDir}/dnssec -c ${policyFile name zone.dnssecPolicy} ${name}
-    ${pkgs.bind}/bin/dnssec-signzone -S -K ${stateDir}/dnssec -o ${name} -O full -N date ${stateDir}/zones/${name}
+    ${dnssecTools}/bin/dnssec-keymgr -g ${dnssecTools}/bin/dnssec-keygen -s ${dnssecTools}/bin/dnssec-settime -K ${stateDir}/dnssec -c ${policyFile name zone.dnssecPolicy} ${name}
+    ${dnssecTools}/bin/dnssec-signzone -S -K ${stateDir}/dnssec -o ${name} -O full -N date ${stateDir}/zones/${name}
     ${nsdPkg}/sbin/nsd-checkzone ${name} ${stateDir}/zones/${name}.signed && mv -v ${stateDir}/zones/${name}.signed ${stateDir}/zones/${name}
   '';
   policyFile = name: policy: pkgs.writeText "${name}.policy" ''
@@ -953,10 +955,6 @@ in
       '';
     };
 
-    nixpkgs.config = mkIf dnssec {
-      bind.enablePython = true;
-    };
-
     systemd.timers."nsd-dnssec" = mkIf dnssec {
       description = "Automatic DNSSEC key rollover";
 
diff --git a/nixpkgs/nixos/modules/services/networking/nylon.nix b/nixpkgs/nixos/modules/services/networking/nylon.nix
index 613b0e0fb51a..b061ce34ed2c 100644
--- a/nixpkgs/nixos/modules/services/networking/nylon.nix
+++ b/nixpkgs/nixos/modules/services/networking/nylon.nix
@@ -142,7 +142,6 @@ in
       description = "Collection of named nylon instances";
       type = with types; loaOf (submodule nylonOpts);
       internal = true;
-      options = [ nylonOpts ];
     };
 
   };
diff --git a/nixpkgs/nixos/modules/services/networking/prosody.nix b/nixpkgs/nixos/modules/services/networking/prosody.nix
index 25b7d6dbeba2..de316e5f4669 100644
--- a/nixpkgs/nixos/modules/services/networking/prosody.nix
+++ b/nixpkgs/nixos/modules/services/networking/prosody.nix
@@ -513,6 +513,7 @@ in
         RuntimeDirectory = [ "prosody" ];
         PIDFile = "/run/prosody/prosody.pid";
         ExecStart = "${cfg.package}/bin/prosodyctl start";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/networking/shairport-sync.nix b/nixpkgs/nixos/modules/services/networking/shairport-sync.nix
index 90c0689dc7bf..68e005ab81da 100644
--- a/nixpkgs/nixos/modules/services/networking/shairport-sync.nix
+++ b/nixpkgs/nixos/modules/services/networking/shairport-sync.nix
@@ -27,7 +27,7 @@ in
       };
 
       arguments = mkOption {
-        default = "-v pulse";
+        default = "-v -o pa";
         description = ''
           Arguments to pass to the daemon. Defaults to a local pulseaudio
           server.
diff --git a/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix b/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
index 5fab79f1b3d7..95dc8a62a454 100644
--- a/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
@@ -11,7 +11,7 @@ let
 
   userOptions = {
 
-    openssh.authorizedKeys = {
+    options.openssh.authorizedKeys = {
       keys = mkOption {
         type = types.listOf types.str;
         default = [];
@@ -320,7 +320,7 @@ in
     };
 
     users.users = mkOption {
-      options = [ userOptions ];
+      type = with types; loaOf (submodule userOptions);
     };
 
   };
@@ -352,6 +352,10 @@ in
             path = [ cfgc.package pkgs.gawk ];
             environment.LD_LIBRARY_PATH = nssModulesPath;
 
+            restartTriggers = optionals (!cfg.startWhenNeeded) [
+              config.environment.etc."ssh/sshd_config".source
+            ];
+
             preStart =
               ''
                 # Make sure we don't write to stdout, since in case of
@@ -387,6 +391,7 @@ in
                 Restart = "always";
                 Type = "simple";
               });
+
           };
       in
 
diff --git a/nixpkgs/nixos/modules/services/networking/syncthing.nix b/nixpkgs/nixos/modules/services/networking/syncthing.nix
index b2ef1885a955..702481ec5177 100644
--- a/nixpkgs/nixos/modules/services/networking/syncthing.nix
+++ b/nixpkgs/nixos/modules/services/networking/syncthing.nix
@@ -122,7 +122,7 @@ in {
 
     systemd.packages = [ pkgs.syncthing ];
 
-    users = mkIf (cfg.user == defaultUser) {
+    users = mkIf (cfg.systemService && cfg.user == defaultUser) {
       users."${defaultUser}" =
         { group = cfg.group;
           home  = cfg.dataDir;
diff --git a/nixpkgs/nixos/modules/services/networking/unifi.nix b/nixpkgs/nixos/modules/services/networking/unifi.nix
index ac10e77ba306..89b9ac4eadf5 100644
--- a/nixpkgs/nixos/modules/services/networking/unifi.nix
+++ b/nixpkgs/nixos/modules/services/networking/unifi.nix
@@ -184,4 +184,5 @@ in
 
   };
 
+  meta.maintainers = with lib.maintainers; [ erictapen ];
 }
diff --git a/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix b/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix
index c788528fa47b..8622212f0856 100644
--- a/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix
@@ -1,4 +1,4 @@
-{ config, lib, pkgs, ... }:
+{ config, lib, pkgs, utils, ... }:
 
 with lib;
 
@@ -193,7 +193,7 @@ in {
     # FIXME: start a separate wpa_supplicant instance per interface.
     systemd.services.wpa_supplicant = let
       ifaces = cfg.interfaces;
-      deviceUnit = interface: [ "sys-subsystem-net-devices-${interface}.device" ];
+      deviceUnit = interface: [ "sys-subsystem-net-devices-${utils.escapeSystemdPath interface}.device" ];
     in {
       description = "WPA Supplicant";
 
diff --git a/nixpkgs/nixos/modules/services/networking/xrdp.nix b/nixpkgs/nixos/modules/services/networking/xrdp.nix
index 9ed3025e47d4..a1c5d879f3cb 100644
--- a/nixpkgs/nixos/modules/services/networking/xrdp.nix
+++ b/nixpkgs/nixos/modules/services/networking/xrdp.nix
@@ -26,6 +26,12 @@ let
     substituteInPlace $out/sesman.ini \
       --replace LogFile=xrdp-sesman.log LogFile=/dev/null \
       --replace EnableSyslog=1 EnableSyslog=0
+
+    # Ensure that clipboard works for non-ASCII characters
+    sed -i -e '/.*SessionVariables.*/ a\
+    LANG=${config.i18n.defaultLocale}\
+    LOCALE_ARCHIVE=${config.i18n.glibcLocales}/lib/locale/locale-archive
+    ' $out/sesman.ini
   '';
 in
 {
diff --git a/nixpkgs/nixos/modules/services/search/elasticsearch-curator.nix b/nixpkgs/nixos/modules/services/search/elasticsearch-curator.nix
index 43785c392fee..8cb1275284a3 100644
--- a/nixpkgs/nixos/modules/services/search/elasticsearch-curator.nix
+++ b/nixpkgs/nixos/modules/services/search/elasticsearch-curator.nix
@@ -82,11 +82,12 @@ in {
   };
 
   config = mkIf cfg.enable {
-
     systemd.services.elasticsearch-curator = {
       startAt = cfg.interval;
       serviceConfig = {
-        ExecStart = ''${pkgs.python36Packages.elasticsearch-curator}/bin/curator --config ${curatorConfig} ${curatorAction}'';
+        ExecStart =
+          "${pkgs.python3Packages.elasticsearch-curator}/bin/curator" +
+          " --config ${curatorConfig} ${curatorAction}";
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/services/security/certmgr.nix b/nixpkgs/nixos/modules/services/security/certmgr.nix
index 22d5817ec4f0..e89078883ebe 100644
--- a/nixpkgs/nixos/modules/services/security/certmgr.nix
+++ b/nixpkgs/nixos/modules/services/security/certmgr.nix
@@ -30,13 +30,20 @@ let
 
   preStart = ''
     ${concatStringsSep " \\\n" (["mkdir -p"] ++ map escapeShellArg specPaths)}
-    ${pkgs.certmgr}/bin/certmgr -f ${certmgrYaml} check
+    ${cfg.package}/bin/certmgr -f ${certmgrYaml} check
   '';
 in
 {
   options.services.certmgr = {
     enable = mkEnableOption "certmgr";
 
+    package = mkOption {
+      type = types.package;
+      default = pkgs.certmgr;
+      defaultText = "pkgs.certmgr";
+      description = "Which certmgr package to use in the service.";
+    };
+
     defaultRemote = mkOption {
       type = types.str;
       default = "127.0.0.1:8888";
@@ -187,7 +194,7 @@ in
       serviceConfig = {
         Restart = "always";
         RestartSec = "10s";
-        ExecStart = "${pkgs.certmgr}/bin/certmgr -f ${certmgrYaml}";
+        ExecStart = "${cfg.package}/bin/certmgr -f ${certmgrYaml}";
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/services/security/munge.nix b/nixpkgs/nixos/modules/services/security/munge.nix
index fda864f2c30a..504bc66c6d10 100644
--- a/nixpkgs/nixos/modules/services/security/munge.nix
+++ b/nixpkgs/nixos/modules/services/security/munge.nix
@@ -50,7 +50,7 @@ in
       path = [ pkgs.munge pkgs.coreutils ];
 
       preStart = ''
-        chmod 0700 ${cfg.password}
+        chmod 0400 ${cfg.password}
         mkdir -p /var/lib/munge -m 0711
         chown -R munge:munge /var/lib/munge
         mkdir -p /run/munge -m 0755
diff --git a/nixpkgs/nixos/modules/services/security/nginx-sso.nix b/nixpkgs/nixos/modules/services/security/nginx-sso.nix
new file mode 100644
index 000000000000..d792f90abe64
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/security/nginx-sso.nix
@@ -0,0 +1,58 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.nginx.sso;
+  pkg = getBin pkgs.nginx-sso;
+  configYml = pkgs.writeText "nginx-sso.yml" (builtins.toJSON cfg.configuration);
+in {
+  options.services.nginx.sso = {
+    enable = mkEnableOption "nginx-sso service";
+
+    configuration = mkOption {
+      type = types.attrsOf types.unspecified;
+      default = {};
+      example = literalExample ''
+        {
+          listen = { addr = "127.0.0.1"; port = 8080; };
+
+          providers.token.tokens = {
+            myuser = "MyToken";
+          };
+
+          acl = {
+            rule_sets = [
+              {
+                rules = [ { field = "x-application"; equals = "MyApp"; } ];
+                allow = [ "myuser" ];
+              }
+            ];
+          };
+        }
+      '';
+      description = ''
+        nginx-sso configuration
+        (<link xlink:href="https://github.com/Luzifer/nginx-sso/wiki/Main-Configuration">documentation</link>)
+        as a Nix attribute set.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.nginx-sso = {
+      description = "Nginx SSO Backend";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = ''
+          ${pkg}/bin/nginx-sso \
+            --config ${configYml} \
+            --frontend-dir ${pkg}/share/frontend
+        '';
+        Restart = "always";
+        DynamicUser = true;
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/security/sks.nix b/nixpkgs/nixos/modules/services/security/sks.nix
index 9f0261038d5b..8136a5c763a9 100644
--- a/nixpkgs/nixos/modules/services/security/sks.nix
+++ b/nixpkgs/nixos/modules/services/security/sks.nix
@@ -5,6 +5,9 @@ with lib;
 let
   cfg = config.services.sks;
   sksPkg = cfg.package;
+  dbConfig = pkgs.writeText "DB_CONFIG" ''
+    ${cfg.extraDbConfig}
+  '';
 
 in {
   meta.maintainers = with maintainers; [ primeos calbrecht jcumming ];
@@ -39,6 +42,20 @@ in {
         '';
       };
 
+      extraDbConfig = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Set contents of the files "KDB/DB_CONFIG" and "PTree/DB_CONFIG" within
+          the ''${dataDir} directory. This is used to configure options for the
+          database for the sks key server.
+
+          Documentation of available options are available in the file named
+          "sampleConfig/DB_CONFIG" in the following repository:
+          https://bitbucket.org/skskeyserver/sks-keyserver/src
+        '';
+      };
+
       hkpAddress = mkOption {
         default = [ "127.0.0.1" "::1" ];
         type = types.listOf types.str;
@@ -99,6 +116,17 @@ in {
           ${lib.optionalString (cfg.webroot != null)
             "ln -sfT \"${cfg.webroot}\" web"}
           mkdir -p dump
+          # Check that both database configs are symlinks before overwriting them
+          if [ -e KDB/DB_CONFIG ] && [ ! -L KBD/DB_CONFIG ]; then
+            echo "KDB/DB_CONFIG exists but is not a symlink." >&2
+            exit 1
+          fi
+          if [ -e PTree/DB_CONFIG ] && [ ! -L PTree/DB_CONFIG ]; then
+            echo "PTree/DB_CONFIG exists but is not a symlink." >&2
+            exit 1
+          fi
+          ln -sf ${dbConfig} KDB/DB_CONFIG
+          ln -sf ${dbConfig} PTree/DB_CONFIG
           ${sksPkg}/bin/sks build dump/*.gpg -n 10 -cache 100 || true #*/
           ${sksPkg}/bin/sks cleandb || true
           ${sksPkg}/bin/sks pbuild -cache 20 -ptree_cache 70 || true
diff --git a/nixpkgs/nixos/modules/services/security/sshguard.nix b/nixpkgs/nixos/modules/services/security/sshguard.nix
index 137c3d610186..3892cd5c72b8 100644
--- a/nixpkgs/nixos/modules/services/security/sshguard.nix
+++ b/nixpkgs/nixos/modules/services/security/sshguard.nix
@@ -4,6 +4,7 @@ with lib;
 
 let
   cfg = config.services.sshguard;
+
 in {
 
   ###### interface
@@ -77,65 +78,65 @@ in {
             Systemd services sshguard should receive logs of.
           '';
       };
-
     };
-
   };
 
-
   ###### implementation
 
   config = mkIf cfg.enable {
 
-    environment.systemPackages = [ pkgs.sshguard pkgs.iptables pkgs.ipset ];
-
     environment.etc."sshguard.conf".text = let
-        list_services = ( name:  "-t ${name} ");
-      in ''
-        BACKEND="${pkgs.sshguard}/libexec/sshg-fw-ipset"
-        LOGREADER="LANG=C ${pkgs.systemd}/bin/journalctl -afb -p info -n1 ${toString (map list_services cfg.services)} -o cat"
+      args = lib.concatStringsSep " " ([
+        "-afb"
+        "-p info"
+        "-o cat"
+        "-n1"
+      ] ++ (map (name: "-t ${escapeShellArg name}") cfg.services));
+    in ''
+      BACKEND="${pkgs.sshguard}/libexec/sshg-fw-ipset"
+      LOGREADER="LANG=C ${pkgs.systemd}/bin/journalctl ${args}"
+    '';
+
+    systemd.services.sshguard = {
+      description = "SSHGuard brute-force attacks protection system";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      partOf = optional config.networking.firewall.enable "firewall.service";
+
+      path = with pkgs; [ iptables ipset iproute systemd ];
+
+      postStart = ''
+        ${pkgs.ipset}/bin/ipset -quiet create -exist sshguard4 hash:ip family inet
+        ${pkgs.ipset}/bin/ipset -quiet create -exist sshguard6 hash:ip family inet6
+        ${pkgs.iptables}/bin/iptables  -I INPUT -m set --match-set sshguard4 src -j DROP
+        ${pkgs.iptables}/bin/ip6tables -I INPUT -m set --match-set sshguard6 src -j DROP
+      '';
+
+      preStop = ''
+        ${pkgs.iptables}/bin/iptables  -D INPUT -m set --match-set sshguard4 src -j DROP
+        ${pkgs.iptables}/bin/ip6tables -D INPUT -m set --match-set sshguard6 src -j DROP
       '';
 
-    systemd.services.sshguard =
-      { description = "SSHGuard brute-force attacks protection system";
-
-        wantedBy = [ "multi-user.target" ];
-        after = [ "network.target" ];
-        partOf = optional config.networking.firewall.enable "firewall.service";
-
-        path = [ pkgs.iptables pkgs.ipset pkgs.iproute pkgs.systemd ];
-
-        postStart = ''
-          mkdir -p /var/lib/sshguard
-          ${pkgs.ipset}/bin/ipset -quiet create -exist sshguard4 hash:ip family inet
-          ${pkgs.ipset}/bin/ipset -quiet create -exist sshguard6 hash:ip family inet6
-          ${pkgs.iptables}/bin/iptables -I INPUT -m set --match-set sshguard4 src -j DROP
-          ${pkgs.iptables}/bin/ip6tables -I INPUT -m set --match-set sshguard6 src -j DROP
-        '';
-
-        preStop = ''
-          ${pkgs.iptables}/bin/iptables -D INPUT -m set --match-set sshguard4 src -j DROP
-          ${pkgs.iptables}/bin/ip6tables -D INPUT -m set --match-set sshguard6 src -j DROP
-        '';
-
-        unitConfig.Documentation = "man:sshguard(8)";
-
-        serviceConfig = {
-            Type = "simple";
-            ExecStart = let
-                list_whitelist = ( name:  "-w ${name} ");
-              in ''
-                 ${pkgs.sshguard}/bin/sshguard -a ${toString cfg.attack_threshold} ${optionalString (cfg.blacklist_threshold != null) "-b ${toString cfg.blacklist_threshold}:${cfg.blacklist_file} "}-i /run/sshguard/sshguard.pid -p ${toString cfg.blocktime} -s ${toString cfg.detection_time} ${toString (map list_whitelist cfg.whitelist)}
-              '';
-            PIDFile = "/run/sshguard/sshguard.pid";
-            Restart = "always";
-
-            ReadOnlyDirectories = "/";
-            ReadWriteDirectories = "/run/sshguard /var/lib/sshguard";
-            RuntimeDirectory = "sshguard";
-            StateDirectory = "sshguard";
-            CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW";
-         };
+      unitConfig.Documentation = "man:sshguard(8)";
+
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = let
+          args = lib.concatStringsSep " " ([
+            "-a ${toString cfg.attack_threshold}"
+            "-p ${toString cfg.blocktime}"
+            "-s ${toString cfg.detection_time}"
+            (optionalString (cfg.blacklist_threshold != null) "-b ${toString cfg.blacklist_threshold}:${cfg.blacklist_file}")
+          ] ++ (map (name: "-w ${escapeShellArg name}") cfg.whitelist));
+        in "${pkgs.sshguard}/bin/sshguard ${args}";
+        Restart = "always";
+        ProtectSystem = "strict";
+        ProtectHome = "tmpfs";
+        RuntimeDirectory = "sshguard";
+        StateDirectory = "sshguard";
+        CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW";
       };
+    };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/system/kerberos.nix b/nixpkgs/nixos/modules/services/system/kerberos.nix
deleted file mode 100644
index e2c45ed64ac0..000000000000
--- a/nixpkgs/nixos/modules/services/system/kerberos.nix
+++ /dev/null
@@ -1,64 +0,0 @@
-{pkgs, config, lib, ...}:
-
-let
-
-  inherit (lib) mkOption mkIf;
-
-  inherit (pkgs) heimdalFull;
-
-  stateDir = "/var/heimdal";
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    services.kerberos_server = {
-
-      enable = mkOption {
-        default = false;
-        description = ''
-          Enable the kerberos authentification server.
-        '';
-      };
-
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = mkIf config.services.kerberos_server.enable {
-
-    environment.systemPackages = [ heimdalFull ];
-
-    services.xinetd.enable = true;
-    services.xinetd.services = lib.singleton
-      { name = "kerberos-adm";
-        flags = "REUSE NAMEINARGS";
-        protocol = "tcp";
-        user = "root";
-        server = "${pkgs.tcp_wrappers}/bin/tcpd";
-        serverArgs = "${pkgs.heimdalFull}/libexec/heimdal/kadmind";
-      };
-
-    systemd.services.kdc = {
-      description = "Key Distribution Center daemon";
-      wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        mkdir -m 0755 -p ${stateDir}
-      '';
-      script = "${heimdalFull}/libexec/heimdal/kdc";
-    };
-
-    systemd.services.kpasswdd = {
-      description = "Kerberos Password Changing daemon";
-      wantedBy = [ "multi-user.target" ];
-      script = "${heimdalFull}/libexec/heimdal/kpasswdd";
-    };
-  };
-
-}
diff --git a/nixpkgs/nixos/modules/services/system/kerberos/default.nix b/nixpkgs/nixos/modules/services/system/kerberos/default.nix
new file mode 100644
index 000000000000..26ac85de402f
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/system/kerberos/default.nix
@@ -0,0 +1,80 @@
+{pkgs, config, lib, ...}:
+
+let
+  inherit (lib) mkOption mkIf types length attrNames;
+  cfg = config.services.kerberos_server;
+  kerberos = config.krb5.kerberos;
+
+  aclEntry = {
+    options = {
+      principal = mkOption {
+        type = types.str;
+        description = "Which principal the rule applies to";
+      };
+      access = mkOption {
+        type = types.either
+          (types.listOf (types.enum ["add" "cpw" "delete" "get" "list" "modify"]))
+          (types.enum ["all"]);
+        default = "all";
+        description = "The changes the principal is allowed to make.";
+      };
+      target = mkOption {
+        type = types.str;
+        default = "*";
+        description = "The principals that 'access' applies to.";
+      };
+    };
+  };
+
+  realm = {
+    options = {
+      acl = mkOption {
+        type = types.listOf (types.submodule aclEntry);
+        default = [
+          { principal = "*/admin"; access = "all"; }
+          { principal = "admin"; access = "all"; }
+        ];
+        description = ''
+          The privileges granted to a user.
+        '';
+      };
+    };
+  };
+in
+
+{
+  imports = [
+    ./mit.nix
+    ./heimdal.nix
+  ];
+
+  ###### interface
+  options = {
+    services.kerberos_server = {
+      enable = mkOption {
+        default = false;
+        description = ''
+          Enable the kerberos authentification server.
+        '';
+      };
+
+      realms = mkOption {
+        type = types.attrsOf (types.submodule realm);
+        description = ''
+          The realm(s) to serve keys for.
+        '';
+      };
+    };
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ kerberos ];
+    assertions = [{
+      assertion = length (attrNames cfg.realms) <= 1;
+      message = "Only one realm per server is currently supported.";
+    }];
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/system/kerberos/heimdal.nix b/nixpkgs/nixos/modules/services/system/kerberos/heimdal.nix
new file mode 100644
index 000000000000..d0f470f836ed
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/system/kerberos/heimdal.nix
@@ -0,0 +1,68 @@
+{ pkgs, config, lib, ... } :
+
+let
+  inherit (lib) mkIf concatStringsSep concatMapStrings toList mapAttrs
+    mapAttrsToList attrValues;
+  cfg = config.services.kerberos_server;
+  kerberos = config.krb5.kerberos;
+  stateDir = "/var/heimdal";
+  aclFiles = mapAttrs
+    (name: {acl, ...}: pkgs.writeText "${name}.acl" (concatMapStrings ((
+      {principal, access, target, ...} :
+      "${principal}\t${concatStringsSep "," (toList access)}\t${target}\n"
+    )) acl)) cfg.realms;
+
+  kdcConfigs = mapAttrsToList (name: value: ''
+    database = {
+      dbname = ${stateDir}/heimdal
+      acl_file = ${value}
+    }
+  '') aclFiles;
+  kdcConfFile = pkgs.writeText "kdc.conf" ''
+    [kdc]
+    ${concatStringsSep "\n" kdcConfigs}
+  '';
+in
+
+{
+  # No documentation about correct triggers, so guessing at them.
+
+  config = mkIf (cfg.enable && kerberos == pkgs.heimdalFull) {
+    systemd.services.kadmind = {
+      description = "Kerberos Administration Daemon";
+      wantedBy = [ "multi-user.target" ];
+      preStart = ''
+        mkdir -m 0755 -p ${stateDir}
+      '';
+      serviceConfig.ExecStart =
+        "${kerberos}/libexec/heimdal/kadmind --config-file=/etc/heimdal-kdc/kdc.conf";
+      restartTriggers = [ kdcConfFile ];
+    };
+
+    systemd.services.kdc = {
+      description = "Key Distribution Center daemon";
+      wantedBy = [ "multi-user.target" ];
+      preStart = ''
+        mkdir -m 0755 -p ${stateDir}
+      '';
+      serviceConfig.ExecStart =
+        "${kerberos}/libexec/heimdal/kdc --config-file=/etc/heimdal-kdc/kdc.conf";
+      restartTriggers = [ kdcConfFile ];
+    };
+
+    systemd.services.kpasswdd = {
+      description = "Kerberos Password Changing daemon";
+      wantedBy = [ "multi-user.target" ];
+      preStart = ''
+        mkdir -m 0755 -p ${stateDir}
+      '';
+      serviceConfig.ExecStart = "${kerberos}/libexec/heimdal/kpasswdd";
+      restartTriggers = [ kdcConfFile ];
+    };
+
+    environment.etc = {
+      # Can be set via the --config-file option to KDC
+      "heimdal-kdc/kdc.conf".source = kdcConfFile;
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/system/kerberos/mit.nix b/nixpkgs/nixos/modules/services/system/kerberos/mit.nix
new file mode 100644
index 000000000000..a53d9dd0c6b5
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/system/kerberos/mit.nix
@@ -0,0 +1,68 @@
+{ pkgs, config, lib, ... } :
+
+let
+  inherit (lib) mkIf concatStrings concatStringsSep concatMapStrings toList
+    mapAttrs mapAttrsToList attrValues;
+  cfg = config.services.kerberos_server;
+  kerberos = config.krb5.kerberos;
+  stateDir = "/var/lib/krb5kdc";
+  PIDFile = "/run/kdc.pid";
+  aclMap = {
+    add = "a"; cpw = "c"; delete = "d"; get = "i"; list = "l"; modify = "m";
+    all = "*";
+  };
+  aclFiles = mapAttrs
+    (name: {acl, ...}: (pkgs.writeText "${name}.acl" (concatMapStrings (
+      {principal, access, target, ...} :
+      let access_code = map (a: aclMap.${a}) (toList access); in
+      "${principal} ${concatStrings access_code} ${target}\n"
+    ) acl))) cfg.realms;
+  kdcConfigs = mapAttrsToList (name: value: ''
+    ${name} = {
+      acl_file = ${value}
+    }
+  '') aclFiles;
+  kdcConfFile = pkgs.writeText "kdc.conf" ''
+    [realms]
+    ${concatStringsSep "\n" kdcConfigs}
+  '';
+  env = {
+    # What Debian uses, could possibly link directly to Nix store?
+    KRB5_KDC_PROFILE = "/etc/krb5kdc/kdc.conf";
+  };
+in
+
+{
+  config = mkIf (cfg.enable && kerberos == pkgs.krb5Full) {
+    systemd.services.kadmind = {
+      description = "Kerberos Administration Daemon";
+      wantedBy = [ "multi-user.target" ];
+      preStart = ''
+        mkdir -m 0755 -p ${stateDir}
+      '';
+      serviceConfig.ExecStart = "${kerberos}/bin/kadmind -nofork";
+      restartTriggers = [ kdcConfFile ];
+      environment = env;
+    };
+
+    systemd.services.kdc = {
+      description = "Key Distribution Center daemon";
+      wantedBy = [ "multi-user.target" ];
+      preStart = ''
+        mkdir -m 0755 -p ${stateDir}
+      '';
+      serviceConfig = {
+        Type = "forking";
+        PIDFile = PIDFile;
+        ExecStart = "${kerberos}/bin/krb5kdc -P ${PIDFile}";
+      };
+      restartTriggers = [ kdcConfFile ];
+      environment = env;
+    };
+
+    environment.etc = {
+      "krb5kdc/kdc.conf".source = kdcConfFile;
+    };
+    environment.variables = env;
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/torrent/transmission.nix b/nixpkgs/nixos/modules/services/torrent/transmission.nix
index 719eb76f42c2..f544928fb6b1 100644
--- a/nixpkgs/nixos/modules/services/torrent/transmission.nix
+++ b/nixpkgs/nixos/modules/services/torrent/transmission.nix
@@ -143,6 +143,9 @@ in
           ${getLib pkgs.lz4}/lib/liblz4*.so*               mr,
           ${getLib pkgs.libkrb5}/lib/lib*.so*              mr,
           ${getLib pkgs.keyutils}/lib/libkeyutils*.so*     mr,
+          ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so.* mr,
+          ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so.* mr,
+          ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so.* mr,
 
           @{PROC}/sys/kernel/random/uuid   r,
           @{PROC}/sys/vm/overcommit_memory r,
diff --git a/nixpkgs/nixos/modules/services/web-apps/atlassian/confluence.nix b/nixpkgs/nixos/modules/services/web-apps/atlassian/confluence.nix
index f896d92fd6fc..b71887fcc6ee 100644
--- a/nixpkgs/nixos/modules/services/web-apps/atlassian/confluence.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/atlassian/confluence.nix
@@ -166,7 +166,7 @@ in
         ln -sf ${cfg.home}/{logs,work,temp,server.xml} /run/confluence
         ln -sf ${cfg.home} /run/confluence/home
 
-        chown -R ${cfg.user} ${cfg.home}
+        chown ${cfg.user} ${cfg.home}
 
         sed -e 's,port="8090",port="${toString cfg.listenPort}" address="${cfg.listenAddress}",' \
         '' + (lib.optionalString cfg.proxy.enable ''
diff --git a/nixpkgs/nixos/modules/services/web-apps/atlassian/crowd.nix b/nixpkgs/nixos/modules/services/web-apps/atlassian/crowd.nix
index b6cb9f3b7c41..9f48d1e16a44 100644
--- a/nixpkgs/nixos/modules/services/web-apps/atlassian/crowd.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/atlassian/crowd.nix
@@ -130,9 +130,10 @@ in
         mkdir -p ${cfg.home}/{logs,database,work}
 
         mkdir -p /run/atlassian-crowd
-        ln -sf ${cfg.home}/{database,work,server.xml} /run/atlassian-crowd
+        ln -sf ${cfg.home}/{database,logs,work,server.xml} /run/atlassian-crowd
 
-        chown -R ${cfg.user}:${cfg.group} ${cfg.home}
+        chown ${cfg.user}:${cfg.group} ${cfg.home}
+        chown ${cfg.user}:${cfg.group} ${cfg.home}/{logs,database,work}
 
         sed -e 's,port="8095",port="${toString cfg.listenPort}" address="${cfg.listenAddress}",' \
         '' + (lib.optionalString cfg.proxy.enable ''
diff --git a/nixpkgs/nixos/modules/services/web-apps/atlassian/jira.nix b/nixpkgs/nixos/modules/services/web-apps/atlassian/jira.nix
index f5ec0a5f31b8..dba970c612bc 100644
--- a/nixpkgs/nixos/modules/services/web-apps/atlassian/jira.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/atlassian/jira.nix
@@ -171,7 +171,7 @@ in
         ln -sf ${cfg.home}/{logs,work,temp,server.xml} /run/atlassian-jira
         ln -sf ${cfg.home} /run/atlassian-jira/home
 
-        chown -R ${cfg.user} ${cfg.home}
+        chown ${cfg.user} ${cfg.home}
 
         sed -e 's,port="8080",port="${toString cfg.listenPort}" address="${cfg.listenAddress}",' \
         '' + (lib.optionalString cfg.proxy.enable ''
diff --git a/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix b/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
index ecb1c5615d58..ee1354d6a997 100644
--- a/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
@@ -426,7 +426,7 @@ in {
               "~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\\.php(?:$|/)" = {
                 priority = 500;
                 extraConfig = ''
-                  include ${pkgs.nginxMainline}/conf/fastcgi.conf;
+                  include ${config.services.nginx.package}/conf/fastcgi.conf;
                   fastcgi_split_path_info ^(.+\.php)(/.*)$;
                   fastcgi_param PATH_INFO $fastcgi_path_info;
                   fastcgi_param HTTPS ${if cfg.https then "on" else "off"};
diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
index 73607c6f9a3b..bb9623347869 100644
--- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -151,7 +151,7 @@ let
 
 
   loggingConf = (if mainCfg.logFormat != "none" then ''
-    ErrorLog ${mainCfg.logDir}/error_log
+    ErrorLog ${mainCfg.logDir}/error.log
 
     LogLevel notice
 
@@ -160,7 +160,7 @@ let
     LogFormat "%{Referer}i -> %U" referer
     LogFormat "%{User-agent}i" agent
 
-    CustomLog ${mainCfg.logDir}/access_log ${mainCfg.logFormat}
+    CustomLog ${mainCfg.logDir}/access.log ${mainCfg.logFormat}
   '' else ''
     ErrorLog /dev/null
   '');
@@ -187,8 +187,8 @@ let
     SSLRandomSeed startup builtin
     SSLRandomSeed connect builtin
 
-    SSLProtocol All -SSLv2 -SSLv3
-    SSLCipherSuite HIGH:!aNULL:!MD5:!EXP
+    SSLProtocol ${mainCfg.sslProtocols}
+    SSLCipherSuite ${mainCfg.sslCiphers}
     SSLHonorCipherOrder on
   '';
 
@@ -261,8 +261,8 @@ let
     '' else ""}
 
     ${if !isMainServer && mainCfg.logPerVirtualHost then ''
-      ErrorLog ${mainCfg.logDir}/error_log-${cfg.hostName}
-      CustomLog ${mainCfg.logDir}/access_log-${cfg.hostName} ${cfg.logFormat}
+      ErrorLog ${mainCfg.logDir}/error-${cfg.hostName}.log
+      CustomLog ${mainCfg.logDir}/access-${cfg.hostName}.log ${cfg.logFormat}
     '' else ""}
 
     ${optionalString (robotsTxt != "") ''
@@ -630,6 +630,19 @@ in
         description =
           "Maximum number of httpd requests answered per httpd child (prefork), 0 means unlimited";
       };
+
+      sslCiphers = mkOption {
+        type = types.str;
+        default = "HIGH:!aNULL:!MD5:!EXP";
+        description = "Cipher Suite available for negotiation in SSL proxy handshake.";
+      };
+
+      sslProtocols = mkOption {
+        type = types.str;
+        default = "All -SSLv2 -SSLv3";
+        example = "All -SSLv2 -SSLv3 -TLSv1";
+        description = "Allowed SSL/TLS protocol versions.";
+      };
     }
 
     # Include the options shared between the main server and virtual hosts.
diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/wordpress.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
index c810b914e258..c68bfd25f6a8 100644
--- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
@@ -85,10 +85,10 @@ let
       # remove bundled themes(s) coming with wordpress
       rm -Rf $out/wp-content/themes/*
 
-      # symlink additional theme(s)
-      ${concatMapStrings (theme: "ln -s ${theme} $out/wp-content/themes/${theme.name}\n") config.themes}
-      # symlink additional plugin(s)
-      ${concatMapStrings (plugin: "ln -s ${plugin} $out/wp-content/plugins/${plugin.name}\n") (config.plugins) }
+      # copy additional theme(s)
+      ${concatMapStrings (theme: "cp -r ${theme} $out/wp-content/themes/${theme.name}\n") config.themes}
+      # copy additional plugin(s)
+      ${concatMapStrings (plugin: "cp -r ${plugin} $out/wp-content/plugins/${plugin.name}\n") (config.plugins) }
 
       # symlink additional translation(s)
       mkdir -p $out/wp-content/languages
diff --git a/nixpkgs/nixos/modules/services/web-servers/lighttpd/collectd.nix b/nixpkgs/nixos/modules/services/web-servers/lighttpd/collectd.nix
index 35b5edced68b..e70c980d5243 100644
--- a/nixpkgs/nixos/modules/services/web-servers/lighttpd/collectd.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/lighttpd/collectd.nix
@@ -48,7 +48,7 @@ in
           "/collectd" => "${cfg.collectionCgi}"
         )
         setenv.add-environment = (
-          "PERL5LIB" => "${with pkgs; lib.makePerlPath [ perlPackages.CGI perlPackages.HTMLParser perlPackages.URI rrdtool ]}",
+          "PERL5LIB" => "${with pkgs.perlPackages; makePerlPath [ CGI HTMLParser URI pkgs.rrdtool ]}",
           "COLLECTION_CONF" => "${collectionConf}"
         )
       }
diff --git a/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix b/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix
index e1f4ff5db7f2..152c89a2caec 100644
--- a/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix
@@ -8,21 +8,31 @@ let
 
   stateDir = "/run/phpfpm";
 
-  poolConfigs = cfg.poolConfigs // mapAttrs mkPool cfg.pools;
+  poolConfigs =
+    (mapAttrs mapPoolConfig cfg.poolConfigs) //
+    (mapAttrs mapPool cfg.pools);
 
-  mkPool = n: p: ''
-    listen = ${p.listen}
-    ${p.extraConfig}
-  '';
+  mapPoolConfig = n: p: {
+    phpPackage = cfg.phpPackage;
+    config = p;
+  };
+
+  mapPool = n: p: {
+    phpPackage = p.phpPackage;
+    config = ''
+      listen = ${p.listen}
+      ${p.extraConfig}
+    '';
+  };
 
-  fpmCfgFile = pool: poolConfig: pkgs.writeText "phpfpm-${pool}.conf" ''
+  fpmCfgFile = pool: conf: pkgs.writeText "phpfpm-${pool}.conf" ''
     [global]
     error_log = syslog
     daemonize = no
     ${cfg.extraConfig}
 
     [${pool}]
-    ${poolConfig}
+    ${conf}
   '';
 
   phpIni = pkgs.runCommand "php.ini" {
@@ -97,13 +107,14 @@ in {
 
       pools = mkOption {
         type = types.attrsOf (types.submodule (import ./pool-options.nix {
-          inherit lib;
+          inherit lib config;
         }));
         default = {};
         example = literalExample ''
          {
            mypool = {
              listen = "/path/to/unix/socket";
+             phpPackage = pkgs.php;
              extraConfig = '''
                user = nobody
                pm = dynamic
@@ -144,7 +155,7 @@ in {
           mkdir -p ${stateDir}
         '';
         serviceConfig = let
-          cfgFile = fpmCfgFile pool poolConfig;
+          cfgFile = fpmCfgFile pool poolConfig.config;
         in {
           Slice = "phpfpm.slice";
           PrivateDevices = true;
@@ -153,7 +164,7 @@ in {
           # XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work
           RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
           Type = "notify";
-          ExecStart = "${cfg.phpPackage}/bin/php-fpm -y ${cfgFile} -c ${phpIni}";
+          ExecStart = "${poolConfig.phpPackage}/bin/php-fpm -y ${cfgFile} -c ${phpIni}";
           ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
         };
       }
diff --git a/nixpkgs/nixos/modules/services/web-servers/phpfpm/pool-options.nix b/nixpkgs/nixos/modules/services/web-servers/phpfpm/pool-options.nix
index cc688c2c48a2..40c83cddb957 100644
--- a/nixpkgs/nixos/modules/services/web-servers/phpfpm/pool-options.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/phpfpm/pool-options.nix
@@ -1,4 +1,8 @@
-{ lib }:
+{ lib, config }:
+
+let
+  fpmCfg = config.services.phpfpm;
+in
 
 with lib; {
 
@@ -12,6 +16,15 @@ with lib; {
       '';
     };
 
+    phpPackage = mkOption {
+      type = types.package;
+      default = fpmCfg.phpPackage;
+      defaultText = "config.services.phpfpm.phpPackage";
+      description = ''
+        The PHP package to use for running this PHP-FPM pool.
+      '';
+    };
+
     extraConfig = mkOption {
       type = types.lines;
       example = ''
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix
index ba6d333b534e..7544ba4638ac 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -5,14 +5,6 @@ with lib;
 let
   cfg = config.services.xserver.desktopManager.gnome3;
 
-  # Remove packages of ys from xs, based on their names
-  removePackagesByName = xs: ys:
-    let
-      pkgName = drv: (builtins.parseDrvName drv.name).name;
-      ysNames = map pkgName ys;
-    in
-      filter (x: !(builtins.elem (pkgName x) ysNames)) xs;
-
   # Prioritize nautilus by default when opening directories
   mimeAppsList = pkgs.writeTextFile {
     name = "gnome-mimeapps";
@@ -44,6 +36,8 @@ let
      ${pkgs.glib.dev}/bin/glib-compile-schemas $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/
     '';
 
+  flashbackEnabled = cfg.flashback.enableMetacity || length cfg.flashback.customSessions > 0;
+
 in {
 
   options = {
@@ -79,6 +73,36 @@ in {
       };
 
       debug = mkEnableOption "gnome-session debug messages";
+
+      flashback = {
+        enableMetacity = mkEnableOption "Enable the standard GNOME Flashback session with Metacity.";
+
+        customSessions = mkOption {
+          type = types.listOf (types.submodule {
+            options = {
+              wmName = mkOption {
+                type = types.str;
+                description = "The filename-compatible name of the window manager to use.";
+                example = "xmonad";
+              };
+
+              wmLabel = mkOption {
+                type = types.str;
+                description = "The pretty name of the window manager to use.";
+                example = "XMonad";
+              };
+
+              wmCommand = mkOption {
+                type = types.str;
+                description = "The executable of the window manager to use.";
+                example = "\${pkgs.haskellPackages.xmonad}/bin/xmonad";
+              };
+            };
+          });
+          default = [];
+          description = "Other GNOME Flashback sessions to enable.";
+        };
+      };
     };
 
     environment.gnome3.excludePackages = mkOption {
@@ -103,6 +127,7 @@ in {
     services.dleyna-server.enable = mkDefault true;
     services.gnome3.at-spi2-core.enable = true;
     services.gnome3.evolution-data-server.enable = true;
+    services.gnome3.file-roller.enable = mkDefault true;
     services.gnome3.gnome-disks.enable = mkDefault true;
     services.gnome3.gnome-documents.enable = mkDefault true;
     services.gnome3.gnome-keyring.enable = true;
@@ -120,7 +145,9 @@ in {
     services.telepathy.enable = mkDefault true;
     networking.networkmanager.enable = mkDefault true;
     services.upower.enable = config.powerManagement.enable;
-    services.dbus.packages = mkIf config.services.printing.enable [ pkgs.system-config-printer ];
+    services.dbus.packages =
+      optional config.services.printing.enable pkgs.system-config-printer ++
+      optional flashbackEnabled pkgs.gnome3.gnome-screensaver;
     services.colord.enable = mkDefault true;
     services.packagekit.enable = mkDefault true;
     hardware.bluetooth.enable = mkDefault true;
@@ -134,7 +161,15 @@ in {
 
     fonts.fonts = [ pkgs.dejavu_fonts pkgs.cantarell-fonts ];
 
-    services.xserver.displayManager.extraSessionFilePackages = [ pkgs.gnome3.gnome-session ];
+    services.xserver.displayManager.extraSessionFilePackages = [ pkgs.gnome3.gnome-session ]
+      ++ map
+        (wm: pkgs.gnome3.gnome-flashback.mkSessionForWm {
+          inherit (wm) wmName wmLabel wmCommand;
+        }) (optional cfg.flashback.enableMetacity {
+              wmName = "metacity";
+              wmLabel = "Metacity";
+              wmCommand = "${pkgs.gnome3.metacity}/bin/metacity";
+            } ++ cfg.flashback.customSessions);
 
     environment.extraInit = ''
       ${concatMapStrings (p: ''
@@ -167,7 +202,7 @@ in {
                                                 "${pkgs.gnome3.glib-networking.out}/lib/gio/modules"
                                                 "${pkgs.gnome3.gvfs}/lib/gio/modules" ];
     environment.systemPackages = pkgs.gnome3.corePackages ++ cfg.sessionPath
-      ++ (removePackagesByName pkgs.gnome3.optionalPackages config.environment.gnome3.excludePackages) ++ [
+      ++ (pkgs.gnome3.removePackagesByName pkgs.gnome3.optionalPackages config.environment.gnome3.excludePackages) ++ [
       pkgs.xdg-user-dirs # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/
     ];
 
@@ -179,8 +214,14 @@ in {
                               networkmanager-iodine networkmanager-l2tp; };
 
     # Needed for themes and backgrounds
-    environment.pathsToLink = [ "/share" ];
+    environment.pathsToLink = [
+      "/share"
+      "/share/nautilus-python/extensions"
+    ];
 
+    security.pam.services.gnome-screensaver = mkIf flashbackEnabled {
+      enableGnomeKeyring = true;
+    };
   };
 
 
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/lxqt.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/lxqt.nix
index 896f70c86ebb..686bbd0dcf98 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/lxqt.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/lxqt.nix
@@ -3,15 +3,6 @@
 with lib;
 
 let
-
-  # Remove packages of ys from xs, based on their names
-  removePackagesByName = xs: ys:
-    let
-      pkgName = drv: (builtins.parseDrvName drv.name).name;
-      ysNames = map pkgName ys;
-    in
-      filter (x: !(builtins.elem (pkgName x) ysNames)) xs;
-
   xcfg = config.services.xserver;
   cfg = xcfg.desktopManager.lxqt;
 
@@ -60,7 +51,7 @@ in
     environment.systemPackages =
       pkgs.lxqt.preRequisitePackages ++
       pkgs.lxqt.corePackages ++
-      (removePackagesByName
+      (pkgs.gnome3.removePackagesByName
         pkgs.lxqt.optionalPackages
         config.environment.lxqt.excludePackages);
 
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix
index db83aaf3c19f..4d2fafd14961 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix
@@ -4,14 +4,6 @@ with lib;
 
 let
 
-  # Remove packages of ys from xs, based on their names
-  removePackagesByName = xs: ys:
-    let
-      pkgName = drv: (builtins.parseDrvName drv.name).name;
-      ysNames = map pkgName ys;
-    in
-      filter (x: !(builtins.elem (pkgName x) ysNames)) xs;
-
   addToXDGDirs = p: ''
     if [ -d "${p}/share/gsettings-schemas/${p.name}" ]; then
       export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${p}/share/gsettings-schemas/${p.name}
@@ -96,7 +88,7 @@ in
 
     environment.systemPackages =
       pkgs.mate.basePackages ++
-      (removePackagesByName
+      (pkgs.gnome3.removePackagesByName
         pkgs.mate.extraPackages
         config.environment.mate.excludePackages);
 
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/default.nix b/nixpkgs/nixos/modules/services/x11/display-managers/default.nix
index 047321bd9495..0e87e6adbab8 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/default.nix
@@ -191,7 +191,9 @@ let
       '') names}
 
       ${concatMapStrings (pkg: ''
-        ${xorg.lndir}/bin/lndir ${pkg}/share/xsessions $out/share/xsessions
+        if test -d ${pkg}/share/xsessions; then
+          ${xorg.lndir}/bin/lndir ${pkg}/share/xsessions $out/share/xsessions
+        fi
       '') cfg.displayManager.extraSessionFilePackages}
 
       
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
index d1ee076e9185..efec943c0075 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
@@ -6,12 +6,14 @@ let
 
   dmcfg = config.services.xserver.displayManager;
   ldmcfg = dmcfg.lightdm;
+  xcfg = config.services.xserver;
   cfg = ldmcfg.greeters.gtk;
 
   inherit (pkgs) writeText;
 
   theme = cfg.theme.package;
   icons = cfg.iconTheme.package;
+  cursors = cfg.cursorTheme.package;
 
   # The default greeter provided with this expression is the GTK greeter.
   # Again, we need a few things in the environment for the greeter to run with
@@ -28,7 +30,8 @@ let
         --set GTK_EXE_PREFIX "${theme}" \
         --set GTK_DATA_PREFIX "${theme}" \
         --set XDG_DATA_DIRS "${theme}/share:${icons}/share" \
-        --set XDG_CONFIG_HOME "${theme}/share"
+        --set XDG_CONFIG_HOME "${theme}/share" \
+        --set XCURSOR_PATH "${cursors}/share/icons"
 
       cat - > $out/lightdm-gtk-greeter.desktop << EOF
       [Desktop Entry]
@@ -44,9 +47,12 @@ let
     [greeter]
     theme-name = ${cfg.theme.name}
     icon-theme-name = ${cfg.iconTheme.name}
+    cursor-theme-name = ${cfg.cursorTheme.name}
+    cursor-theme-size = ${toString cfg.cursorTheme.size}
     background = ${ldmcfg.background}
     ${optionalString (cfg.clock-format != null) "clock-format = ${cfg.clock-format}"}
     ${optionalString (cfg.indicators != null) "indicators = ${concatStringsSep ";" cfg.indicators}"}
+    ${optionalString (xcfg.dpi != null) "xft-dpi=${toString xcfg.dpi}"}
     ${cfg.extraConfig}
     '';
 
@@ -106,6 +112,33 @@ in
 
       };
 
+      cursorTheme = {
+
+        package = mkOption {
+          default = pkgs.gnome3.defaultIconTheme;
+          defaultText = "pkgs.gnome3.defaultIconTheme";
+          description = ''
+            The package path that contains the cursor theme given in the name option.
+          '';
+        };
+
+        name = mkOption {
+          type = types.str;
+          default = "Adwaita";
+          description = ''
+            Name of the cursor theme to use for the lightdm-gtk-greeter.
+          '';
+        };
+
+        size = mkOption {
+          type = types.int;
+          default = 16;
+          description = ''
+            Size of the cursor theme to use for the lightdm-gtk-greeter.
+          '';
+        };
+      };
+
       clock-format = mkOption {
         type = types.nullOr types.str;
         default = null;
diff --git a/nixpkgs/nixos/modules/services/x11/urxvtd.nix b/nixpkgs/nixos/modules/services/x11/urxvtd.nix
index 5531d7f153c2..d916fa5bb393 100644
--- a/nixpkgs/nixos/modules/services/x11/urxvtd.nix
+++ b/nixpkgs/nixos/modules/services/x11/urxvtd.nix
@@ -7,14 +7,24 @@ with lib;
 let
   cfg = config.services.urxvtd;
 in {
+  options.services.urxvtd = {
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable urxvtd, the urxvt terminal daemon. To use urxvtd, run
+        "urxvtc".
+      '';
+    };
 
-  options.services.urxvtd.enable = mkOption {
-    type = types.bool;
-    default = false;
-    description = ''
-      Enable urxvtd, the urxvt terminal daemon. To use urxvtd, run
-      "urxvtc".
-    '';
+    package = mkOption {
+      default = pkgs.rxvt_unicode-with-plugins;
+      defaultText = "pkgs.rxvt_unicode-with-plugins";
+      description = ''
+        Package to install. Usually pkgs.rxvt_unicode-with-plugins or pkgs.rxvt_unicode
+      '';
+      type = types.package;
+    };
   };
 
   config = mkIf cfg.enable {
@@ -24,14 +34,14 @@ in {
       partOf = [ "graphical-session.target" ];
       path = [ pkgs.xsel ];
       serviceConfig = {
-        ExecStart = "${pkgs.rxvt_unicode-with-plugins}/bin/urxvtd -o";
+        ExecStart = "${cfg.package}/bin/urxvtd -o";
         Environment = "RXVT_SOCKET=%t/urxvtd-socket";
         Restart = "on-failure";
         RestartSec = "5s";
       };
     };
 
-    environment.systemPackages = [ pkgs.rxvt_unicode-with-plugins ];
+    environment.systemPackages = [ cfg.package ];
     environment.variables.RXVT_SOCKET = "/run/user/$(id -u)/urxvtd-socket";
   };