summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/config/debug-info.nix7
-rw-r--r--nixos/modules/config/nsswitch.nix2
-rw-r--r--nixos/modules/config/system-path.nix1
-rw-r--r--nixos/modules/config/timezone.nix5
-rw-r--r--nixos/modules/hardware/network/intel-2030.nix3
-rw-r--r--nixos/modules/hardware/network/intel-2100bg.nix30
-rw-r--r--nixos/modules/hardware/network/intel-3945abg.nix29
-rw-r--r--nixos/modules/hardware/network/intel-4965agn.nix3
-rw-r--r--nixos/modules/hardware/network/intel-5000.nix3
-rw-r--r--nixos/modules/hardware/network/intel-5150.nix3
-rw-r--r--nixos/modules/hardware/network/intel-6000.nix3
-rw-r--r--nixos/modules/hardware/network/intel-6000g2a.nix3
-rw-r--r--nixos/modules/hardware/network/intel-6000g2b.nix3
-rw-r--r--nixos/modules/hardware/network/ralink.nix26
-rw-r--r--nixos/modules/hardware/network/rtl8192c.nix26
-rw-r--r--nixos/modules/installer/scan/detected.nix5
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl14
-rw-r--r--nixos/modules/misc/ids.nix6
-rw-r--r--nixos/modules/misc/locate.nix16
-rw-r--r--nixos/modules/module-list.nix13
-rw-r--r--nixos/modules/profiles/all-hardware.nix5
-rw-r--r--nixos/modules/programs/command-not-found/command-not-found.nix9
-rw-r--r--nixos/modules/programs/sway.nix19
-rw-r--r--nixos/modules/programs/zsh/zsh-syntax-highlighting.nix116
-rw-r--r--nixos/modules/rename.nix9
-rw-r--r--nixos/modules/security/pam.nix11
-rw-r--r--nixos/modules/service-managers/docker.nix29
-rw-r--r--nixos/modules/service-managers/trivial.nix35
-rw-r--r--nixos/modules/services/continuous-integration/buildkite-agent.nix47
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/default.nix9
-rw-r--r--nixos/modules/services/desktops/geoclue2.nix2
-rw-r--r--nixos/modules/services/mail/opendkim.nix26
-rw-r--r--nixos/modules/services/mail/postfix.nix2
-rw-r--r--nixos/modules/services/misc/gitea.nix270
-rw-r--r--nixos/modules/services/misc/gitlab.nix12
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix1
-rw-r--r--nixos/modules/services/misc/plex.nix2
-rw-r--r--nixos/modules/services/misc/pykms.nix90
-rw-r--r--nixos/modules/services/misc/tzupdate.nix45
-rw-r--r--nixos/modules/services/monitoring/graphite.nix54
-rw-r--r--nixos/modules/services/monitoring/munin.nix13
-rw-r--r--nixos/modules/services/monitoring/prometheus/minio-exporter.nix117
-rw-r--r--nixos/modules/services/monitoring/prometheus/node-exporter.nix9
-rw-r--r--nixos/modules/services/network-filesystems/kbfs.nix3
-rw-r--r--nixos/modules/services/network-filesystems/openafs-client/default.nix1
-rw-r--r--nixos/modules/services/networking/connman.nix5
-rw-r--r--nixos/modules/services/networking/dnscache.nix11
-rw-r--r--nixos/modules/services/networking/firewall.nix8
-rw-r--r--nixos/modules/services/networking/keybase.nix3
-rw-r--r--nixos/modules/services/networking/libreswan.nix7
-rw-r--r--nixos/modules/services/networking/unbound.nix2
-rw-r--r--nixos/modules/services/networking/znc.nix2
-rw-r--r--nixos/modules/services/scheduling/atd.nix4
-rw-r--r--nixos/modules/services/scheduling/fcron.nix7
-rw-r--r--nixos/modules/services/search/elasticsearch.nix12
-rw-r--r--nixos/modules/services/security/hologram-server.nix14
-rw-r--r--nixos/modules/services/security/oauth2_proxy.nix2
-rw-r--r--nixos/modules/services/security/sshguard.nix2
-rw-r--r--nixos/modules/services/web-apps/atlassian/crowd.nix2
-rw-r--r--nixos/modules/services/web-apps/mattermost.nix10
-rw-r--r--nixos/modules/services/web-servers/lighttpd/default.nix6
-rw-r--r--nixos/modules/services/web-servers/nginx/vhost-options.nix4
-rw-r--r--nixos/modules/services/x11/compton.nix72
-rw-r--r--nixos/modules/services/x11/desktop-managers/mate.nix1
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix9
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix9
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix11
-rw-r--r--nixos/modules/services/x11/hardware/libinput.nix15
-rw-r--r--nixos/modules/services/x11/redshift.nix44
-rw-r--r--nixos/modules/services/x11/xautolock.nix92
-rw-r--r--nixos/modules/system/boot/kernel.nix17
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl2
-rw-r--r--nixos/modules/system/boot/resolved.nix72
-rw-r--r--nixos/modules/tasks/encrypted-devices.nix3
-rw-r--r--nixos/modules/tasks/filesystems/ecryptfs.nix14
-rw-r--r--nixos/modules/tasks/filesystems/ext.nix3
-rw-r--r--nixos/modules/tasks/powertop.nix1
-rw-r--r--nixos/modules/virtualisation/brightbox-image.nix6
78 files changed, 1134 insertions, 475 deletions
diff --git a/nixos/modules/config/debug-info.nix b/nixos/modules/config/debug-info.nix
index 49991d22a933..2942ae5905d1 100644
--- a/nixos/modules/config/debug-info.nix
+++ b/nixos/modules/config/debug-info.nix
@@ -30,14 +30,15 @@ with lib;
   };
 
 
-  config = {
+  config = mkIf config.environment.enableDebugInfo {
 
     # FIXME: currently disabled because /lib is already in
     # environment.pathsToLink, and we can't have both.
     #environment.pathsToLink = [ "/lib/debug/.build-id" ];
 
-    environment.extraOutputsToInstall =
-      optional config.environment.enableDebugInfo "debug";
+    environment.extraOutputsToInstall = [ "debug" ];
+
+    environment.variables.NIX_DEBUG_INFO_DIRS = [ "/run/current-system/sw/lib/debug" ];
 
   };
 
diff --git a/nixos/modules/config/nsswitch.nix b/nixos/modules/config/nsswitch.nix
index 97278238dcd5..7b36d4f1cbdf 100644
--- a/nixos/modules/config/nsswitch.nix
+++ b/nixos/modules/config/nsswitch.nix
@@ -18,7 +18,7 @@ let
 
   hostArray = [ "files" ]
     ++ optionals mymachines [ "mymachines" ]
-    ++ optionals nssmdns [ "mdns_minimal [!UNAVAIL=return]" ]
+    ++ optionals nssmdns [ "mdns_minimal [NOTFOUND=return]" ]
     ++ optionals nsswins [ "wins" ]
     ++ optionals resolved ["resolve [!UNAVAIL=return]"]
     ++ [ "dns" ]
diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix
index 5d339eaea485..d3212d931605 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -31,6 +31,7 @@ let
       pkgs.nano
       pkgs.ncurses
       pkgs.netcat
+      pkgs.nix-info
       config.programs.ssh.package
       pkgs.perl
       pkgs.procps
diff --git a/nixos/modules/config/timezone.nix b/nixos/modules/config/timezone.nix
index aa030a816d04..b15948f6e2e5 100644
--- a/nixos/modules/config/timezone.nix
+++ b/nixos/modules/config/timezone.nix
@@ -5,6 +5,9 @@ with lib;
 let
 
   tzdir = "${pkgs.tzdata}/share/zoneinfo";
+  nospace  = str: filter (c: c == " ") (stringToCharacters str) == [];
+  timezone = types.nullOr (types.addCheck types.str nospace)
+    // { description = "null or string without spaces"; };
 
 in
 
@@ -15,7 +18,7 @@ in
 
       timeZone = mkOption {
         default = null;
-        type = types.nullOr types.str;
+        type = timezone;
         example = "America/New_York";
         description = ''
           The time zone used when displaying times and dates. See <link
diff --git a/nixos/modules/hardware/network/intel-2030.nix b/nixos/modules/hardware/network/intel-2030.nix
deleted file mode 100644
index c92b7a0509d0..000000000000
--- a/nixos/modules/hardware/network/intel-2030.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  hardware.enableRedistributableFirmware = true;
-}
diff --git a/nixos/modules/hardware/network/intel-2100bg.nix b/nixos/modules/hardware/network/intel-2100bg.nix
deleted file mode 100644
index 0ec81474ad3e..000000000000
--- a/nixos/modules/hardware/network/intel-2100bg.nix
+++ /dev/null
@@ -1,30 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-{
-
-  ###### interface
-
-  options = {
-
-    networking.enableIntel2100BGFirmware = lib.mkOption {
-      default = false;
-      type = lib.types.bool;
-      description = ''
-        Turn on this option if you want firmware for the Intel
-        PRO/Wireless 2100BG to be loaded automatically.  This is
-        required if you want to use this device.
-      '';
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = lib.mkIf config.networking.enableIntel2100BGFirmware {
-
-    hardware.enableRedistributableFirmware = true;
-
-  };
-
-}
diff --git a/nixos/modules/hardware/network/intel-3945abg.nix b/nixos/modules/hardware/network/intel-3945abg.nix
deleted file mode 100644
index 27a3f228b7d1..000000000000
--- a/nixos/modules/hardware/network/intel-3945abg.nix
+++ /dev/null
@@ -1,29 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-{
-
-  ###### interface
-
-  options = {
-
-    networking.enableIntel3945ABGFirmware = lib.mkOption {
-      default = false;
-      type = lib.types.bool;
-      description = ''
-        This option enables automatic loading of the firmware for the Intel
-        PRO/Wireless 3945ABG.
-      '';
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = lib.mkIf config.networking.enableIntel3945ABGFirmware {
-
-    hardware.enableRedistributableFirmware = true;
-
-  };
-
-}
diff --git a/nixos/modules/hardware/network/intel-4965agn.nix b/nixos/modules/hardware/network/intel-4965agn.nix
deleted file mode 100644
index c92b7a0509d0..000000000000
--- a/nixos/modules/hardware/network/intel-4965agn.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  hardware.enableRedistributableFirmware = true;
-}
diff --git a/nixos/modules/hardware/network/intel-5000.nix b/nixos/modules/hardware/network/intel-5000.nix
deleted file mode 100644
index c92b7a0509d0..000000000000
--- a/nixos/modules/hardware/network/intel-5000.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  hardware.enableRedistributableFirmware = true;
-}
diff --git a/nixos/modules/hardware/network/intel-5150.nix b/nixos/modules/hardware/network/intel-5150.nix
deleted file mode 100644
index c92b7a0509d0..000000000000
--- a/nixos/modules/hardware/network/intel-5150.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  hardware.enableRedistributableFirmware = true;
-}
diff --git a/nixos/modules/hardware/network/intel-6000.nix b/nixos/modules/hardware/network/intel-6000.nix
deleted file mode 100644
index c92b7a0509d0..000000000000
--- a/nixos/modules/hardware/network/intel-6000.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  hardware.enableRedistributableFirmware = true;
-}
diff --git a/nixos/modules/hardware/network/intel-6000g2a.nix b/nixos/modules/hardware/network/intel-6000g2a.nix
deleted file mode 100644
index c92b7a0509d0..000000000000
--- a/nixos/modules/hardware/network/intel-6000g2a.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  hardware.enableRedistributableFirmware = true;
-}
diff --git a/nixos/modules/hardware/network/intel-6000g2b.nix b/nixos/modules/hardware/network/intel-6000g2b.nix
deleted file mode 100644
index c92b7a0509d0..000000000000
--- a/nixos/modules/hardware/network/intel-6000g2b.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  hardware.enableRedistributableFirmware = true;
-}
diff --git a/nixos/modules/hardware/network/ralink.nix b/nixos/modules/hardware/network/ralink.nix
deleted file mode 100644
index 36182e2cb996..000000000000
--- a/nixos/modules/hardware/network/ralink.nix
+++ /dev/null
@@ -1,26 +0,0 @@
-{pkgs, config, lib, ...}:
-
-{
-
-  ###### interface
-
-  options = {
-
-    networking.enableRalinkFirmware = lib.mkOption {
-      default = false;
-      type = lib.types.bool;
-      description = ''
-        Turn on this option if you want firmware for the RT73 NIC.
-      '';
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = lib.mkIf config.networking.enableRalinkFirmware {
-    hardware.enableRedistributableFirmware = true;
-  };
-
-}
diff --git a/nixos/modules/hardware/network/rtl8192c.nix b/nixos/modules/hardware/network/rtl8192c.nix
deleted file mode 100644
index bf328c2d3224..000000000000
--- a/nixos/modules/hardware/network/rtl8192c.nix
+++ /dev/null
@@ -1,26 +0,0 @@
-{pkgs, config, lib, ...}:
-
-{
-
-  ###### interface
-
-  options = {
-
-    networking.enableRTL8192cFirmware = lib.mkOption {
-      default = false;
-      type = lib.types.bool;
-      description = ''
-        Turn on this option if you want firmware for the RTL8192c (and related) NICs.
-      '';
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = lib.mkIf config.networking.enableRTL8192cFirmware {
-    hardware.enableRedistributableFirmware = true;
-  };
-
-}
diff --git a/nixos/modules/installer/scan/detected.nix b/nixos/modules/installer/scan/detected.nix
index e72c78532943..7e181acb93b1 100644
--- a/nixos/modules/installer/scan/detected.nix
+++ b/nixos/modules/installer/scan/detected.nix
@@ -6,8 +6,7 @@ with lib;
 
 {
   config = mkDefault {
-    # Wireless card firmware
-    networking.enableIntel2200BGFirmware = true;
-    networking.enableIntel3945ABGFirmware = true;
+    # Common firmware, i.e. for wifi cards
+    hardware.enableRedistributableFirmware = true;
   };
 }
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index 4ec48b773358..c0df2977856e 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -103,7 +103,7 @@ if (-e "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") {
 
     foreach $e (@desired_governors) {
         if (index($governors, $e) != -1) {
-            last if (push @attrs, "powerManagement.cpuFreqGovernor = \"$e\";");
+            last if (push @attrs, "powerManagement.cpuFreqGovernor = lib.mkDefault \"$e\";");
         }
     }
 }
@@ -398,19 +398,15 @@ EOF
 
     # Is this a btrfs filesystem?
     if ($fsType eq "btrfs") {
-        my ($status, @id_info) = runCommand("btrfs subvol show $rootDir$mountPoint");
-        if ($status != 0 || join("", @id_info) =~ /ERROR:/) {
+        my ($status, @info) = runCommand("btrfs subvol show $rootDir$mountPoint");
+        if ($status != 0 || join("", @info) =~ /ERROR:/) {
             die "Failed to retrieve subvolume info for $mountPoint\n";
         }
-        my @ids = join("", @id_info) =~ m/Subvolume ID:[ \t\n]*([^ \t\n]*)/;
+        my @ids = join("\n", @info) =~ m/^(?!\/\n).*Subvolume ID:[ \t\n]*([0-9]+)/s;
         if ($#ids > 0) {
             die "Btrfs subvol name for $mountPoint listed multiple times in mount\n"
         } elsif ($#ids == 0) {
-            my ($status, @path_info) = runCommand("btrfs subvol list $rootDir$mountPoint");
-            if ($status != 0) {
-                die "Failed to find $mountPoint subvolume id from btrfs\n";
-            }
-            my @paths = join("", @path_info) =~ m/ID $ids[0] [^\n]* path ([^\n]*)/;
+            my @paths = join("", @info) =~ m/^([^\n]*)/;
             if ($#paths > 0) {
                 die "Btrfs returned multiple paths for a single subvolume id, mountpoint $mountPoint\n";
             } elsif ($#paths != 0) {
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 508a76d3cab5..7d9d9984cf28 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -296,6 +296,9 @@
       clickhouse = 278;
       rslsync = 279;
       minio = 280;
+      kanboard = 281;
+      pykms = 282;
+      kodi = 283;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -561,6 +564,9 @@
       clickhouse = 278;
       rslsync = 279;
       minio = 280;
+      kanboard = 281;
+      pykms = 282;
+      kodi = 283;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix
index 0fe91435ce8c..51953d1110c4 100644
--- a/nixos/modules/misc/locate.nix
+++ b/nixos/modules/misc/locate.nix
@@ -125,13 +125,16 @@ in {
     warnings = optional (isMLocate && cfg.localuser != null) "mlocate does not support searching as user other than root"
             ++ optional (isFindutils && cfg.pruneNames != []) "findutils locate does not support pruning by directory component"
             ++ optional (isFindutils && cfg.pruneBindMounts) "findutils locate does not support skipping bind mounts";
-  
+
+    # directory creation needs to be separated from main service
+    # because ReadWritePaths fails when the directory doesn't already exist
+    systemd.tmpfiles.rules = [ "d ${dirOf cfg.output} 0755 root root -" ];
+
     systemd.services.update-locatedb =
       { description = "Update Locate Database";
         path = mkIf (!isMLocate) [ pkgs.su ];
         script =
           ''
-            mkdir -m 0755 -p ${dirOf cfg.output}
             exec ${cfg.locate}/bin/updatedb \
               ${optionalString (cfg.localuser != null && ! isMLocate) ''--localuser=${cfg.localuser}''} \
               --output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags}
@@ -147,8 +150,13 @@ in {
         serviceConfig.PrivateTmp = "yes";
         serviceConfig.PrivateNetwork = "yes";
         serviceConfig.NoNewPrivileges = "yes";
-        serviceConfig.ReadOnlyDirectories = "/";
-        serviceConfig.ReadWriteDirectories = dirOf cfg.output;
+        serviceConfig.ReadOnlyPaths = "/";
+        # Use dirOf cfg.output because mlocate creates temporary files next to
+        # the actual database. We could specify and create them as well,
+        # but that would make this quite brittle when they change something.
+        # NOTE: If /var/cache does not exist, this leads to the misleading error message:
+        # update-locatedb.service: Failed at step NAMESPACE spawning …/update-locatedb-start: No such file or directory
+        serviceConfig.ReadWritePaths = dirOf cfg.output;
       };
 
     systemd.timers.update-locatedb =
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 8ac7e5b52d69..6f00a97dd3ff 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -35,11 +35,6 @@
   ./hardware/ksm.nix
   ./hardware/mcelog.nix
   ./hardware/network/b43.nix
-  ./hardware/network/intel-2100bg.nix
-  ./hardware/network/intel-2200bg.nix
-  ./hardware/network/intel-3945abg.nix
-  ./hardware/network/ralink.nix
-  ./hardware/network/rtl8192c.nix
   ./hardware/nitrokey.nix
   ./hardware/opengl.nix
   ./hardware/pcmcia.nix
@@ -104,6 +99,7 @@
   ./programs/ssh.nix
   ./programs/ssmtp.nix
   ./programs/sysdig.nix
+  ./programs/sway.nix
   ./programs/thefuck.nix
   ./programs/tmux.nix
   ./programs/venus.nix
@@ -136,8 +132,6 @@
   ./security/rtkit.nix
   ./security/wrappers/default.nix
   ./security/sudo.nix
-  ./service-managers/docker.nix
-  ./service-managers/trivial.nix
   ./services/admin/salt/master.nix
   ./services/admin/salt/minion.nix
   ./services/amqp/activemq/default.nix
@@ -303,6 +297,7 @@
   ./services/misc/fstrim.nix
   ./services/misc/gammu-smsd.nix
   ./services/misc/geoip-updater.nix
+  ./services/misc/gitea.nix
   #./services/misc/gitit.nix
   ./services/misc/gitlab.nix
   ./services/misc/gitolite.nix
@@ -333,6 +328,7 @@
   ./services/misc/parsoid.nix
   ./services/misc/phd.nix
   ./services/misc/plex.nix
+  ./services/misc/pykms.nix
   ./services/misc/radarr.nix
   ./services/misc/redmine.nix
   ./services/misc/rippled.nix
@@ -349,6 +345,7 @@
   ./services/misc/svnserve.nix
   ./services/misc/synergy.nix
   ./services/misc/taskserver
+  ./services/misc/tzupdate.nix
   ./services/misc/uhub.nix
   ./services/misc/zookeeper.nix
   ./services/monitoring/apcupsd.nix
@@ -375,6 +372,7 @@
   ./services/monitoring/prometheus/collectd-exporter.nix
   ./services/monitoring/prometheus/fritzbox-exporter.nix
   ./services/monitoring/prometheus/json-exporter.nix
+  ./services/monitoring/prometheus/minio-exporter.nix
   ./services/monitoring/prometheus/nginx-exporter.nix
   ./services/monitoring/prometheus/node-exporter.nix
   ./services/monitoring/prometheus/snmp-exporter.nix
@@ -698,6 +696,7 @@
   ./tasks/filesystems/bcachefs.nix
   ./tasks/filesystems/btrfs.nix
   ./tasks/filesystems/cifs.nix
+  ./tasks/filesystems/ecryptfs.nix
   ./tasks/filesystems/exfat.nix
   ./tasks/filesystems/ext.nix
   ./tasks/filesystems/f2fs.nix
diff --git a/nixos/modules/profiles/all-hardware.nix b/nixos/modules/profiles/all-hardware.nix
index 6e6ae98e19fc..3c7e516c497f 100644
--- a/nixos/modules/profiles/all-hardware.nix
+++ b/nixos/modules/profiles/all-hardware.nix
@@ -41,15 +41,12 @@
 
       # Virtio (QEMU, KVM etc.) support.
       "virtio_net" "virtio_pci" "virtio_blk" "virtio_scsi" "virtio_balloon" "virtio_console"
-      
+
       # VMware support.
       "mptspi" "vmw_balloon" "vmwgfx" "vmw_vmci" "vmw_vsock_vmci_transport" "vmxnet3" "vsock"
 
       # Hyper-V support.
       "hv_storvsc"
-
-      # Keyboards
-      "usbhid" "hid_apple" "hid_logitech_dj" "hid_lenovo_tpkbd" "hid_roccat"
     ];
 
   # Include lots of firmware.
diff --git a/nixos/modules/programs/command-not-found/command-not-found.nix b/nixos/modules/programs/command-not-found/command-not-found.nix
index 55529d73cb60..bbe7165c62fb 100644
--- a/nixos/modules/programs/command-not-found/command-not-found.nix
+++ b/nixos/modules/programs/command-not-found/command-not-found.nix
@@ -25,7 +25,14 @@ in
 {
   options.programs.command-not-found = {
 
-    enable = mkEnableOption "command-not-found hook for interactive shell";
+    enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether interactive shells should show which Nix package (if
+        any) provides a missing command.
+      '';
+    };
 
     dbPath = mkOption {
       default = "/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite" ;
diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix
new file mode 100644
index 000000000000..fc8a06d106ae
--- /dev/null
+++ b/nixos/modules/programs/sway.nix
@@ -0,0 +1,19 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+{
+  options.programs.sway.enable = mkEnableOption "sway";
+
+  config = mkIf config.programs.sway.enable {
+    environment.systemPackages = [ pkgs.sway pkgs.xwayland ];
+    security.wrappers.sway = {
+      source = "${pkgs.sway}/bin/sway";
+      capabilities = "cap_sys_ptrace,cap_sys_tty_config=eip";
+      owner = "root";
+      group = "sway";
+      permissions = "u+rx,g+rx";
+    };
+
+    users.extraGroups.sway = {};
+  };
+}
diff --git a/nixos/modules/programs/zsh/zsh-syntax-highlighting.nix b/nixos/modules/programs/zsh/zsh-syntax-highlighting.nix
index 9452489e2fb4..e7cf17c2c00c 100644
--- a/nixos/modules/programs/zsh/zsh-syntax-highlighting.nix
+++ b/nixos/modules/programs/zsh/zsh-syntax-highlighting.nix
@@ -5,74 +5,74 @@ with lib;
 let
   cfg = config.programs.zsh.syntaxHighlighting;
 in
-  {
-    options = {
-      programs.zsh.syntaxHighlighting = {
-        enable = mkEnableOption "zsh-syntax-highlighting";
+{
+  options = {
+    programs.zsh.syntaxHighlighting = {
+      enable = mkEnableOption "zsh-syntax-highlighting";
 
-        highlighters = mkOption {
-          default = [ "main" ];
+      highlighters = mkOption {
+        default = [ "main" ];
 
-          # https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters.md
-          type = types.listOf(types.enum([
-            "main"
-            "brackets"
-            "pattern"
-            "cursor"
-            "root"
-            "line"
-          ]));
+        # https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters.md
+        type = types.listOf(types.enum([
+          "main"
+          "brackets"
+          "pattern"
+          "cursor"
+          "root"
+          "line"
+        ]));
 
-          description = ''
-            Specifies the highlighters to be used by zsh-syntax-highlighting.
+        description = ''
+          Specifies the highlighters to be used by zsh-syntax-highlighting.
 
-            The following defined options can be found here:
-            https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters.md
-          '';
-        };
+          The following defined options can be found here:
+          https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters.md
+        '';
+      };
 
-        patterns = mkOption {
-          default = {};
-          type = types.attrsOf types.string;
+      patterns = mkOption {
+        default = {};
+        type = types.attrsOf types.string;
 
-          example = literalExample ''
-            {
-              "rm -rf *" = "fg=white,bold,bg=red";
-            }
-          '';
+        example = literalExample ''
+          {
+            "rm -rf *" = "fg=white,bold,bg=red";
+          }
+        '';
 
-          description = ''
-            Specifies custom patterns to be highlighted by zsh-syntax-highlighting.
+        description = ''
+          Specifies custom patterns to be highlighted by zsh-syntax-highlighting.
 
-            Please refer to the docs for more information about the usage:
-            https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters/pattern.md
-          '';
-        };
+          Please refer to the docs for more information about the usage:
+          https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters/pattern.md
+        '';
       };
     };
+  };
 
-    config = mkIf cfg.enable {
-      environment.systemPackages = with pkgs; [ zsh-syntax-highlighting ];
-
-      programs.zsh.interactiveShellInit = with pkgs; with builtins; ''
-        source ${zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
+  config = mkIf cfg.enable {
+    environment.systemPackages = with pkgs; [ zsh-syntax-highlighting ];
 
-        ${optionalString (length(cfg.highlighters) > 0)
-          "ZSH_HIGHLIGHT_HIGHLIGHTERS=(${concatStringsSep " " cfg.highlighters})"
-        }
+    assertions = [
+      {
+        assertion = length(attrNames cfg.patterns) > 0 -> elem "pattern" cfg.highlighters;
+        message = ''
+          When highlighting patterns, "pattern" needs to be included in the list of highlighters.
+        '';
+      }
+    ];
 
-        ${let
-            n = attrNames cfg.patterns;
-          in
-            optionalString (length(n) > 0)
-              (assert(elem "pattern" cfg.highlighters); (foldl (
-                a: b:
-                  ''
-                    ${a}
-                    ZSH_HIGHLIGHT_PATTERNS+=('${b}' '${attrByPath [b] "" cfg.patterns}')
-                  ''
-              ) "") n)
-        }
-      '';
-    };
-  }
+    programs.zsh.interactiveShellInit = with pkgs;
+      lib.concatStringsSep "\n" ([
+        "source ${zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
+      ] ++ optional (length(cfg.highlighters) > 0)
+        "ZSH_HIGHLIGHT_HIGHLIGHTERS=(${concatStringsSep " " cfg.highlighters})"
+        ++ optionals (length(attrNames cfg.patterns) > 0)
+          (mapAttrsToList (
+            pattern: design:
+            "ZSH_HIGHLIGHT_PATTERNS+=('${pattern}' '${design}')"
+          ) cfg.patterns)
+      );
+  };
+}
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index deff4067957a..f30cbe427f09 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -11,7 +11,11 @@ with lib;
     (mkRenamedOptionModule [ "fonts" "extraFonts" ] [ "fonts" "fonts" ])
 
     (mkRenamedOptionModule [ "networking" "enableWLAN" ] [ "networking" "wireless" "enable" ])
-    (mkRenamedOptionModule [ "networking" "enableRT73Firmware" ] [ "networking" "enableRalinkFirmware" ])
+    (mkRenamedOptionModule [ "networking" "enableRT73Firmware" ] [ "hardware" "enableRedistributableFirmware" ])
+    (mkRenamedOptionModule [ "networking" "enableIntel3945ABGFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
+    (mkRenamedOptionModule [ "networking" "enableIntel2100BGFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
+    (mkRenamedOptionModule [ "networking" "enableRalinkFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
+    (mkRenamedOptionModule [ "networking" "enableRTL8192cFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
 
     (mkRenamedOptionModule [ "services" "cadvisor" "host" ] [ "services" "cadvisor" "listenAddress" ])
     (mkChangedOptionModule [ "services" "printing" "gutenprint" ] [ "services" "printing" "drivers" ]
@@ -108,6 +112,9 @@ with lib;
 
     (mkAliasOptionModule [ "environment" "checkConfigurationOptions" ] [ "_module" "check" ])
 
+    # opendkim
+    (mkRenamedOptionModule [ "services" "opendkim" "keyFile" ] [ "services" "opendkim" "keyPath" ])
+
     # XBMC
     (mkRenamedOptionModule [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ])
     (mkRenamedOptionModule [ "services" "xserver" "desktopManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ])
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index ede4ace5ed03..5ded36329f33 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -486,8 +486,9 @@ in
       ++ optionals config.krb5.enable [pam_krb5 pam_ccreds]
       ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ]
       ++ optionals config.security.pam.oath.enable [ pkgs.oathToolkit ]
-      ++ optionals config.security.pam.enableU2F [ pkgs.pam_u2f ]
-      ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ];
+      ++ optionals config.security.pam.enableU2F [ pkgs.pam_u2f ];
+
+    boot.supportedFilesystems = optionals config.security.pam.enableEcryptfs [ "ecryptfs" ];
 
     security.wrappers = {
       unix_chkpwd = {
@@ -495,10 +496,7 @@ in
         owner = "root";
         setuid = true;
       };
-    } // (if config.security.pam.enableEcryptfs then {
-      "mount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/mount.ecryptfs_private";
-       "umount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/umount.ecryptfs_private";
-    } else {});
+    };
 
     environment.etc =
       mapAttrsToList (n: v: makePAMService v) config.security.pam.services;
@@ -521,6 +519,7 @@ in
         ftp = {};
         i3lock = {};
         i3lock-color = {};
+        swaylock = {};
         screen = {};
         vlock = {};
         xlock = {};
diff --git a/nixos/modules/service-managers/docker.nix b/nixos/modules/service-managers/docker.nix
deleted file mode 100644
index 8e9c763b18af..000000000000
--- a/nixos/modules/service-managers/docker.nix
+++ /dev/null
@@ -1,29 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-  cfg = config.docker-containers;
-
-  containerModule = {
-    script = mkOption {
-      type = types.lines;
-      description = "Shell commands executed as the service's main process.";
-    };
-  };
-
-  toContainer = name: value: pkgs.dockerTools.buildImage {
-    inherit name;
-    config = {
-      Cmd = [ value.script ];
-    };
-  };
-in {
-  options.docker-containers = mkOption {
-    default = {};
-    type = with types; attrsOf (types.submodule containerModule);
-    description = "Definition of docker containers";
-  };
-
-  config.system.build.toplevel-docker = lib.mapAttrs toContainer cfg;
-}
diff --git a/nixos/modules/service-managers/trivial.nix b/nixos/modules/service-managers/trivial.nix
deleted file mode 100644
index 77e615d1e2e2..000000000000
--- a/nixos/modules/service-managers/trivial.nix
+++ /dev/null
@@ -1,35 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-  cfg = config.trivial-services;
-
-  serviceModule.options = {
-    script = mkOption {
-      type = types.lines;
-      description = "Shell commands executed as the service's main process.";
-    };
-
-    environment = mkOption {
-      default = {};
-      type = types.attrs; # FIXME
-      example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
-      description = "Environment variables passed to the service's processes.";
-    };
-  };
-
-  launcher = name: value: pkgs.writeScript name ''
-    #!${pkgs.stdenv.shell} -eu
-
-    ${pkgs.writeScript "${name}-entry" value.script}
-  '';
-in {
-  options.trivial-services = mkOption {
-    default = {};
-    type = with types; attrsOf (types.submodule serviceModule);
-    description = "Definition of trivial services";
-  };
-
-  config.system.build.toplevel-trivial = lib.mapAttrs launcher cfg;
-}
diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix
index 267bc16862c9..b6d61f6c68bc 100644
--- a/nixos/modules/services/continuous-integration/buildkite-agent.nix
+++ b/nixos/modules/services/continuous-integration/buildkite-agent.nix
@@ -9,9 +9,8 @@ let
       token="${cfg.token}"
       name="${cfg.name}"
       meta-data="${cfg.meta-data}"
-      hooks-path="${pkgs.buildkite-agent}/share/hooks"
-      build-path="/var/lib/buildkite-agent/builds"
-      bootstrap-script="${pkgs.buildkite-agent}/share/bootstrap.sh"
+      hooks-path="${cfg.package}/share/hooks"
+      build-path="${cfg.dataDir}"
     '';
 in
 
@@ -20,6 +19,26 @@ in
     services.buildkite-agent = {
       enable = mkEnableOption "buildkite-agent";
 
+      package = mkOption {
+        default = pkgs.buildkite-agent;
+        defaultText = "pkgs.buildkite-agent";
+        description = "Which buildkite-agent derivation to use";
+        type = types.package;
+      };
+
+      dataDir = mkOption {
+        default = "/var/lib/buildkite-agent";
+        description = "The workdir for the agent";
+        type = types.str;
+      };
+
+      runtimePackages = mkOption {
+        default = [ pkgs.nix ];
+        defaultText = "[ pkgs.nix ]";
+        description = "Add programs to the buildkite-agent environment";
+        type = types.listOf types.package;
+      };
+
       token = mkOption {
         type = types.str;
         description = ''
@@ -62,27 +81,31 @@ in
   config = mkIf config.services.buildkite-agent.enable {
     users.extraUsers.buildkite-agent =
       { name = "buildkite-agent";
-        home = "/var/lib/buildkite-agent";
+        home = cfg.dataDir;
         createHome = true;
         description = "Buildkite agent user";
       };
 
-    environment.systemPackages = [ pkgs.buildkite-agent ];
+    environment.systemPackages = [ cfg.package ];
 
     systemd.services.buildkite-agent =
       { description = "Buildkite Agent";
         wantedBy = [ "multi-user.target" ];
         after = [ "network.target" ];
-        environment.HOME = "/var/lib/buildkite-agent";
+        path = cfg.runtimePackages;
+        environment = config.networking.proxy.envVars // {
+          HOME = cfg.dataDir;
+          NIX_REMOTE = "daemon";
+        };
         preStart = ''
-            ${pkgs.coreutils}/bin/mkdir -m 0700 -p /var/lib/buildkite-agent/.ssh
+          ${pkgs.coreutils}/bin/mkdir -m 0700 -p ${cfg.dataDir}/.ssh
 
-            echo "${cfg.openssh.privateKey}" > /var/lib/buildkite-agent/.ssh/id_rsa
-            ${pkgs.coreutils}/bin/chmod 600 /var/lib/buildkite-agent/.ssh/id_rsa
+          echo "${cfg.openssh.privateKey}" > ${cfg.dataDir}/.ssh/id_rsa
+          ${pkgs.coreutils}/bin/chmod 600 ${cfg.dataDir}/.ssh/id_rsa
 
-            echo "${cfg.openssh.publicKey}" > /var/lib/buildkite-agent/.ssh/id_rsa.pub
-            ${pkgs.coreutils}/bin/chmod 600 /var/lib/buildkite-agent/.ssh/id_rsa.pub
-          '';
+          echo "${cfg.openssh.publicKey}" > ${cfg.dataDir}/.ssh/id_rsa.pub
+          ${pkgs.coreutils}/bin/chmod 600 ${cfg.dataDir}/.ssh/id_rsa.pub
+        '';
 
         serviceConfig =
           { ExecStart = "${pkgs.buildkite-agent}/bin/buildkite-agent start --config ${configFile}";
diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix
index c14aa4167231..0dd59e4fb444 100644
--- a/nixos/modules/services/continuous-integration/jenkins/default.nix
+++ b/nixos/modules/services/continuous-integration/jenkins/default.nix
@@ -78,6 +78,13 @@ in {
         '';
       };
 
+      package = mkOption {
+        default = pkgs.jenkins;
+        defaultText = "pkgs.jenkins";
+        type = types.package;
+        description = "Jenkins package to use.";
+      };
+
       packages = mkOption {
         default = [ pkgs.stdenv pkgs.git pkgs.jdk config.programs.ssh.package pkgs.nix ];
         defaultText = "[ pkgs.stdenv pkgs.git pkgs.jdk config.programs.ssh.package pkgs.nix ]";
@@ -194,7 +201,7 @@ in {
         '';
 
       script = ''
-        ${pkgs.jdk}/bin/java ${concatStringsSep " " cfg.extraJavaOptions} -jar ${pkgs.jenkins}/webapps/jenkins.war --httpListenAddress=${cfg.listenAddress} \
+        ${pkgs.jdk}/bin/java ${concatStringsSep " " cfg.extraJavaOptions} -jar ${cfg.package}/webapps/jenkins.war --httpListenAddress=${cfg.listenAddress} \
                                                   --httpPort=${toString cfg.port} \
                                                   --prefix=${cfg.prefix} \
                                                   ${concatStringsSep " " cfg.extraOptions}
diff --git a/nixos/modules/services/desktops/geoclue2.nix b/nixos/modules/services/desktops/geoclue2.nix
index 0e041fdbfbcf..c5a000d5c6a7 100644
--- a/nixos/modules/services/desktops/geoclue2.nix
+++ b/nixos/modules/services/desktops/geoclue2.nix
@@ -17,7 +17,7 @@ with lib;
         default = false;
         description = ''
           Whether to enable GeoClue 2 daemon, a DBus service
-          that provides location informationfor accessing.
+          that provides location information for accessing.
         '';
       };
 
diff --git a/nixos/modules/services/mail/opendkim.nix b/nixos/modules/services/mail/opendkim.nix
index f065208ddfc1..59a8373843a1 100644
--- a/nixos/modules/services/mail/opendkim.nix
+++ b/nixos/modules/services/mail/opendkim.nix
@@ -8,10 +8,12 @@ let
 
   defaultSock = "local:/run/opendkim/opendkim.sock";
 
+  keyFile = "${cfg.keyPath}/${cfg.selector}.private";
+
   args = [ "-f" "-l"
            "-p" cfg.socket
            "-d" cfg.domains
-           "-k" cfg.keyFile
+           "-k" keyFile
            "-s" cfg.selector
          ] ++ optionals (cfg.configFile != null) [ "-x" cfg.configFile ];
 
@@ -57,9 +59,13 @@ in {
         '';
       };
 
-      keyFile = mkOption {
+      keyPath = mkOption {
         type = types.path;
-        description = "Secret key file used for signing messages.";
+        description = ''
+          The path that opendkim should put its generated private keys into.
+          The DNS settings will be found in this directory with the name selector.txt.
+        '';
+        default = "/var/lib/opendkim/keys";
       };
 
       selector = mkOption {
@@ -100,11 +106,25 @@ in {
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
 
+      preStart = ''
+        mkdir -p "${cfg.keyPath}"
+        cd "${cfg.keyPath}"
+        if ! test -f ${cfg.selector}.private; then
+          ${pkgs.opendkim}/bin/opendkim-genkey -s ${cfg.selector} -d all-domains-generic-key
+          echo "Generated OpenDKIM key! Please update your DNS settings:\n"
+          echo "-------------------------------------------------------------"
+          cat ${cfg.selector}.txt
+          echo "-------------------------------------------------------------"
+        fi
+        chown ${cfg.user}:${cfg.group} ${cfg.selector}.private
+      '';
+
       serviceConfig = {
         ExecStart = "${pkgs.opendkim}/bin/opendkim ${escapeShellArgs args}";
         User = cfg.user;
         Group = cfg.group;
         RuntimeDirectory = optional (cfg.socket == defaultSock) "opendkim";
+        PermissionsStartOnly = true;
       };
     };
 
diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix
index ad4e58149847..2185484827de 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -28,7 +28,7 @@ let
 
   mainCf = let
     escape = replaceStrings ["$"] ["$$"];
-    mkList = items: "\n  " + concatMapStringsSep "\n  " escape items;
+    mkList = items: "\n  " + concatStringsSep "\n  " items;
     mkVal = value:
       if isList value then mkList value
         else " " + (if value == true then "yes"
diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix
new file mode 100644
index 000000000000..f0b44b7bedeb
--- /dev/null
+++ b/nixos/modules/services/misc/gitea.nix
@@ -0,0 +1,270 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.gitea;
+  configFile = pkgs.writeText "app.ini" ''
+    APP_NAME = ${cfg.appName}
+    RUN_USER = ${cfg.user}
+    RUN_MODE = prod
+
+    [database]
+    DB_TYPE = ${cfg.database.type}
+    HOST = ${cfg.database.host}:${toString cfg.database.port}
+    NAME = ${cfg.database.name}
+    USER = ${cfg.database.user}
+    PASSWD = #dbpass#
+    PATH = ${cfg.database.path}
+
+    [repository]
+    ROOT = ${cfg.repositoryRoot}
+
+    [server]
+    DOMAIN = ${cfg.domain}
+    HTTP_ADDR = ${cfg.httpAddress}
+    HTTP_PORT = ${toString cfg.httpPort}
+    ROOT_URL = ${cfg.rootUrl}
+    STATIC_ROOT_PATH = ${cfg.staticRootPath}
+
+    [session]
+    COOKIE_NAME = session
+    COOKIE_SECURE = ${boolToString cfg.cookieSecure}
+
+    [security]
+    SECRET_KEY = #secretkey#
+    INSTALL_LOCK = true
+
+    ${cfg.extraConfig}
+  '';
+in
+
+{
+  options = {
+    services.gitea = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Enable Gitea Service.";
+      };
+
+      useWizard = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Do not generate a configuration and use gitea' installation wizard instead. The first registered user will be administrator.";
+      };
+
+      stateDir = mkOption {
+        default = "/var/lib/gitea";
+        type = types.str;
+        description = "gitea data directory.";
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "gitea";
+        description = "User account under which gitea runs.";
+      };
+
+      database = {
+        type = mkOption {
+          type = types.enum [ "sqlite3" "mysql" "postgres" ];
+          example = "mysql";
+          default = "sqlite3";
+          description = "Database engine to use.";
+        };
+
+        host = mkOption {
+          type = types.str;
+          default = "127.0.0.1";
+          description = "Database host address.";
+        };
+
+        port = mkOption {
+          type = types.int;
+          default = 3306;
+          description = "Database host port.";
+        };
+
+        name = mkOption {
+          type = types.str;
+          default = "gitea";
+          description = "Database name.";
+        };
+
+        user = mkOption {
+          type = types.str;
+          default = "gitea";
+          description = "Database user.";
+        };
+
+        password = mkOption {
+          type = types.str;
+          default = "";
+          description = ''
+            The password corresponding to <option>database.user</option>.
+            Warning: this is stored in cleartext in the Nix store!
+            Use <option>database.passwordFile</option> instead.
+          '';
+        };
+
+        passwordFile = mkOption {
+          type = types.nullOr types.path;
+          default = null;
+          example = "/run/keys/gitea-dbpassword";
+          description = ''
+            A file containing the password corresponding to
+            <option>database.user</option>.
+          '';
+        };
+
+        path = mkOption {
+          type = types.str;
+          default = "${cfg.stateDir}/data/gitea.db";
+          description = "Path to the sqlite3 database file.";
+        };
+      };
+
+      appName = mkOption {
+        type = types.str;
+        default = "gitea: Gitea Service";
+        description = "Application name.";
+      };
+
+      repositoryRoot = mkOption {
+        type = types.str;
+        default = "${cfg.stateDir}/repositories";
+        description = "Path to the git repositories.";
+      };
+
+      domain = mkOption {
+        type = types.str;
+        default = "localhost";
+        description = "Domain name of your server.";
+      };
+
+      rootUrl = mkOption {
+        type = types.str;
+        default = "http://localhost:3000/";
+        description = "Full public URL of gitea server.";
+      };
+
+      httpAddress = mkOption {
+        type = types.str;
+        default = "0.0.0.0";
+        description = "HTTP listen address.";
+      };
+
+      httpPort = mkOption {
+        type = types.int;
+        default = 3000;
+        description = "HTTP listen port.";
+      };
+
+      cookieSecure = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Marks session cookies as "secure" as a hint for browsers to only send
+          them via HTTPS. This option is recommend, if gitea is being served over HTTPS.
+        '';
+      };
+
+      staticRootPath = mkOption {
+        type = types.str;
+        default = "${pkgs.gitea.data}";
+        example = "/var/lib/gitea/data";
+        description = "Upper level of template and static files path.";
+      };
+
+      extraConfig = mkOption {
+        type = types.str;
+        default = "";
+        description = "Configuration lines appended to the generated gitea configuration file.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd.services.gitea = {
+      description = "gitea";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      path = [ pkgs.gitea.bin ];
+
+      preStart = let
+        runConfig = "${cfg.stateDir}/custom/conf/app.ini";
+        secretKey = "${cfg.stateDir}/custom/conf/secret_key";
+      in ''
+        mkdir -p ${cfg.stateDir}
+
+        # copy custom configuration and generate a random secret key if needed
+        ${optionalString (cfg.useWizard == false) ''
+          mkdir -p ${cfg.stateDir}/custom/conf
+          cp -f ${configFile} ${runConfig}
+
+          if [ ! -e ${secretKey} ]; then
+              head -c 16 /dev/urandom | base64 > ${secretKey}
+          fi
+
+          KEY=$(head -n1 ${secretKey})
+          DBPASS=$(head -n1 ${cfg.database.passwordFile})
+          sed -e "s,#secretkey#,$KEY,g" \
+              -e "s,#dbpass#,$DBPASS,g" \
+              -i ${runConfig}
+          chmod 640 ${runConfig} ${secretKey}
+        ''}
+
+        mkdir -p ${cfg.repositoryRoot}
+        # update all hooks' binary paths
+        HOOKS=$(find ${cfg.repositoryRoot} -mindepth 4 -maxdepth 4 -type f -wholename "*git/hooks/*")
+        if [ "$HOOKS" ]
+        then
+          sed -ri 's,/nix/store/[a-z0-9.-]+/bin/gitea,${pkgs.gitea.bin}/bin/gitea,g' $HOOKS
+          sed -ri 's,/nix/store/[a-z0-9.-]+/bin/env,${pkgs.coreutils}/bin/env,g' $HOOKS
+          sed -ri 's,/nix/store/[a-z0-9.-]+/bin/bash,${pkgs.bash}/bin/bash,g' $HOOKS
+          sed -ri 's,/nix/store/[a-z0-9.-]+/bin/perl,${pkgs.perl}/bin/perl,g' $HOOKS
+        fi
+        if [ ! -d ${cfg.stateDir}/conf/locale ]
+        then
+          mkdir -p ${cfg.stateDir}/conf
+          cp -r ${pkgs.gitea.out}/locale ${cfg.stateDir}/conf/locale
+        fi
+      '';
+
+      serviceConfig = {
+        Type = "simple";
+        User = cfg.user;
+        WorkingDirectory = cfg.stateDir;
+        ExecStart = "${pkgs.gitea.bin}/bin/gitea web";
+        Restart = "always";
+      };
+
+      environment = {
+        USER = cfg.user;
+        HOME = cfg.stateDir;
+        GITEA_WORK_DIR = cfg.stateDir;
+      };
+    };
+
+    users = mkIf (cfg.user == "gitea") {
+      extraUsers.gitea = {
+        description = "Gitea Service";
+        home = cfg.stateDir;
+        createHome = true;
+      };
+    };
+
+    warnings = optional (cfg.database.password != "")
+      ''config.services.gitea.database.password will be stored as plaintext
+        in the Nix store. Use database.passwordFile instead.'';
+
+    # Create database passwordFile default when password is configured.
+    services.gitea.database.passwordFile =
+      (mkDefault (toString (pkgs.writeTextFile {
+        name = "gitea-database-password";
+        text = cfg.database.password;
+      })));
+  };
+}
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 0fa9e417785f..740cbc141b53 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -581,6 +581,7 @@ in {
         mkdir -p ${cfg.statePath}/{log,uploads}
         ln -sf ${cfg.statePath}/log /run/gitlab/log
         ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads
+        ln -sf ${cfg.statePath}/tmp /run/gitlab/tmp
         chown -R ${cfg.user}:${cfg.group} /run/gitlab
 
         # Prepare home directory
@@ -631,6 +632,11 @@ in {
           touch "${cfg.statePath}/db-seeded"
         fi
 
+        # The gitlab:shell:create_hooks task seems broken for fixing links
+        # so we instead delete all the hooks and create them anew
+        rm ${cfg.statePath}/repositories/**/*.git/hooks
+        ${gitlab-rake}/bin/gitlab-rake gitlab:shell:create_hooks RAILS_ENV=production
+
         # Change permissions in the last step because some of the
         # intermediary scripts like to create directories as root.
         chown -R ${cfg.user}:${cfg.group} ${cfg.statePath}
@@ -639,10 +645,10 @@ in {
         chmod -R ug+rwX,o-rwx ${cfg.statePath}/repositories
         chmod -R ug-s ${cfg.statePath}/repositories
         find ${cfg.statePath}/repositories -type d -print0 | xargs -0 chmod g+s
-        chmod 700 ${cfg.statePath}/uploads
-        chown -R git ${cfg.statePath}/uploads
+        chmod 770 ${cfg.statePath}/uploads
+        chown -R ${cfg.user} ${cfg.statePath}/uploads
         find ${cfg.statePath}/uploads -type f -exec chmod 0644 {} \;
-        find ${cfg.statePath}/uploads -type d -not -path ${cfg.statePath}/uploads -exec chmod 0700 {} \;
+        find ${cfg.statePath}/uploads -type d -not -path ${cfg.statePath}/uploads -exec chmod 0770 {} \;
       '';
 
       serviceConfig = {
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index efa3b5b6bd76..beca820d2d60 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -189,6 +189,7 @@ in
               sshKey = "/root/.ssh/id_buildfarm";
               system = "x86_64-linux";
               maxJobs = 2;
+              speedFactor = 2;
               supportedFeatures = [ "kvm" ];
               mandatoryFeatures = [ "perf" ];
             }
diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix
index e37b486375bd..46221ace3084 100644
--- a/nixos/modules/services/misc/plex.nix
+++ b/nixos/modules/services/misc/plex.nix
@@ -137,7 +137,7 @@ in
         User = cfg.user;
         Group = cfg.group;
         PermissionsStartOnly = "true";
-        ExecStart = "/bin/sh -c ${cfg.package}/usr/lib/plexmediaserver/Plex\\ Media\\ Server";
+        ExecStart = "\"${cfg.package}/usr/lib/plexmediaserver/Plex Media Server\"";
         KillSignal = "SIGQUIT";
         Restart = "on-failure";
       };
diff --git a/nixos/modules/services/misc/pykms.nix b/nixos/modules/services/misc/pykms.nix
new file mode 100644
index 000000000000..897e856e2a2d
--- /dev/null
+++ b/nixos/modules/services/misc/pykms.nix
@@ -0,0 +1,90 @@
+{ config, lib, pkgs, ... }:
+
+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 {
+
+  options = {
+    services.pykms = rec {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the PyKMS service.";
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "0.0.0.0";
+        description = "The IP address on which to listen.";
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 1688;
+        description = "The port on which to listen.";
+      };
+
+      verbose = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Show verbose output.";
+      };
+
+      openFirewallPort = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether the listening port should be opened automatically.";
+      };
+    };
+  };
+
+  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 = {
+      extraUsers.pykms = {
+        name = "pykms";
+        group = "pykms";
+        home  = home;
+        createHome = true;
+        uid = config.ids.uids.pykms;
+        description = "PyKMS daemon user";
+      };
+
+      extraGroups.pykms = {
+        gid = config.ids.gids.pykms;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/tzupdate.nix b/nixos/modules/services/misc/tzupdate.nix
new file mode 100644
index 000000000000..570982ced29a
--- /dev/null
+++ b/nixos/modules/services/misc/tzupdate.nix
@@ -0,0 +1,45 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.tzupdate;
+in {
+  options.services.tzupdate = {
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable the tzupdate timezone updating service. This provides
+        a one-shot service which can be activated with systemctl to 
+        update the timezone.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    # We need to have imperative time zone management for this to work.
+    # This will give users an error if they have set an explicit time
+    # zone, which is better than silently overriding it.
+    time.timeZone = null; 
+
+    # We provide a one-shot service which can be manually run. We could
+    # provide a service that runs on startup, but it's tricky to get
+    # a service to run after you have *internet* access.
+    systemd.services.tzupdate = {
+      description = "tzupdate timezone update service";
+      wants = [ "network-online.target" ];
+      after = [ "network-online.target" ];
+
+      serviceConfig = {
+        Type = "oneshot";
+        # We could link directly into pkgs.tzdata, but at least timedatectl seems
+        # to expect the symlink to point directly to a file in etc.
+        # Setting the "debian timezone file" to point at /dev/null stops it doing anything.
+        ExecStart = "${pkgs.tzupdate}/bin/tzupdate -z /etc/zoneinfo -d /dev/null";
+      };
+    };
+  };
+
+  meta.maintainers = [ maintainers.michaelpj ];
+}
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index 332a04634d06..01b4aca91731 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -7,6 +7,19 @@ let
   writeTextOrNull = f: t: mapNullable (pkgs.writeTextDir f) t;
 
   dataDir = cfg.dataDir;
+  staticDir = cfg.dataDir + "/static";
+
+  graphiteLocalSettingsDir = pkgs.runCommand "graphite_local_settings"
+    {inherit graphiteLocalSettings;} ''
+    mkdir -p $out
+    ln -s $graphiteLocalSettings $out/graphite_local_settings.py
+  '';
+
+  graphiteLocalSettings = pkgs.writeText "graphite_local_settings.py" (
+    "STATIC_ROOT = '${staticDir}'\n" +
+    optionalString (! isNull config.time.timeZone) "TIME_ZONE = '${config.time.timeZone}'\n"
+    + cfg.web.extraConfig
+  );
 
   graphiteApiConfig = pkgs.writeText "graphite-api.yaml" ''
     time_zone: ${config.time.timeZone}
@@ -94,6 +107,15 @@ in {
         default = 8080;
         type = types.int;
       };
+
+      extraConfig = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Graphite webapp settings. See:
+          <link xlink:href="http://graphite.readthedocs.io/en/latest/config-local-settings.html"/>
+        '';
+      };
     };
 
     api = {
@@ -460,9 +482,13 @@ in {
                 ];
               };
               penvPack = "${penv}/${pkgs.python.sitePackages}";
-              # opt/graphite/webapp contains graphite/settings.py
-              # explicitly adding pycairo in path because it cannot be imported via buildEnv
-            in "${penvPack}/opt/graphite/webapp:${penvPack}:${pkgs.pythonPackages.pycairo}/${pkgs.python.sitePackages}";
+            in concatStringsSep ":" [
+                 "${graphiteLocalSettingsDir}"
+                 "${penvPack}/opt/graphite/webapp"
+                 "${penvPack}"
+                 # explicitly adding pycairo in path because it cannot be imported via buildEnv
+                 "${pkgs.pythonPackages.pycairo}/${pkgs.python.sitePackages}"
+               ];
           DJANGO_SETTINGS_MODULE = "graphite.settings";
           GRAPHITE_CONF_DIR = configDir;
           GRAPHITE_STORAGE_DIR = dataDir;
@@ -470,9 +496,9 @@ in {
         };
         serviceConfig = {
           ExecStart = ''
-            ${pkgs.python27Packages.waitress}/bin/waitress-serve \
-            --host=${cfg.web.listenAddress} --port=${toString cfg.web.port} \
-            --call django.core.handlers.wsgi:WSGIHandler'';
+            ${pkgs.python27Packages.waitress-django}/bin/waitress-serve-django \
+              --host=${cfg.web.listenAddress} --port=${toString cfg.web.port}
+          '';
           User = "graphite";
           Group = "graphite";
           PermissionsStartOnly = true;
@@ -482,16 +508,20 @@ in {
             mkdir -p ${dataDir}/{whisper/,log/webapp/}
             chmod 0700 ${dataDir}/{whisper/,log/webapp/}
 
-            # populate database
-            ${pkgs.python27Packages.graphite_web}/bin/manage-graphite.py syncdb --noinput
+            ${pkgs.pythonPackages.django_1_8}/bin/django-admin.py migrate --noinput
 
-            # create index
-            ${pkgs.python27Packages.graphite_web}/bin/build-index.sh
-
-            chown -R graphite:graphite ${cfg.dataDir}
+            chown -R graphite:graphite ${dataDir}
 
             touch ${dataDir}/db-created
           fi
+
+          # Only collect static files when graphite_web changes.
+          if ! [ "${dataDir}/current_graphite_web" -ef "${pkgs.python27Packages.graphite_web}" ]; then
+            mkdir -p ${staticDir}
+            ${pkgs.pythonPackages.django_1_8}/bin/django-admin.py collectstatic  --noinput --clear
+            chown -R graphite:graphite ${staticDir}
+            ln -sfT "${pkgs.python27Packages.graphite_web}" "${dataDir}/current_graphite_web"
+          fi
         '';
       };
 
diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix
index 723b04dc0fe9..cc6d51f0ef1b 100644
--- a/nixos/modules/services/monitoring/munin.nix
+++ b/nixos/modules/services/monitoring/munin.nix
@@ -193,6 +193,9 @@ in
       };
     };
 
+    # munin_stats plugin breaks as of 2.0.33 when this doesn't exist
+    systemd.tmpfiles.rules = [ "d /var/run/munin 0755 munin munin -" ];
+
   }) (mkIf cronCfg.enable {
 
     systemd.timers.munin-cron = {
@@ -212,9 +215,11 @@ in
       };
     };
 
-    system.activationScripts.munin-cron = stringAfter [ "users" "groups" ] ''
-      mkdir -p /var/{run,log,www,lib}/munin
-      chown -R munin:munin /var/{run,log,www,lib}/munin
-    '';
+    systemd.tmpfiles.rules = [
+      "d /var/run/munin 0755 munin munin -"
+      "d /var/log/munin 0755 munin munin -"
+      "d /var/www/munin 0755 munin munin -"
+      "d /var/lib/munin 0755 munin munin -"
+    ];
   })];
 }
diff --git a/nixos/modules/services/monitoring/prometheus/minio-exporter.nix b/nixos/modules/services/monitoring/prometheus/minio-exporter.nix
new file mode 100644
index 000000000000..4314671523cf
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/minio-exporter.nix
@@ -0,0 +1,117 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.minioExporter;
+in {
+  options = {
+    services.prometheus.minioExporter = {
+      enable = mkEnableOption "prometheus minio exporter";
+
+      port = mkOption {
+        type = types.int;
+        default = 9290;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "0.0.0.0";
+        description = ''
+          Address to listen on for web interface and telemetry.
+        '';
+      };
+
+      minioAddress = mkOption {
+        type = types.str;
+        example = "https://10.0.0.1:9000";
+        default = if config.services.minio.enable then "http://localhost:9000" else null;
+        description = ''
+          The URL of the minio server.
+          Use HTTPS if Minio accepts secure connections only.
+          By default this connects to the local minio server if enabled.
+        '';
+      };
+
+      minioAccessKey = mkOption ({
+        type = types.str;
+        example = "BKIKJAA5BMMU2RHO6IBB";
+        description = ''
+          The value of the Minio access key.
+          It is required in order to connect to the server.
+          By default this uses the one from the local minio server if enabled
+          and <literal>config.services.minio.accessKey</literal>.
+        '';
+      } // optionalAttrs (config.services.minio.enable && config.services.minio.accessKey != "") {
+        default = config.services.minio.accessKey;
+      });
+
+      minioAccessSecret = mkOption ({
+        type = types.str;
+        description = ''
+          The calue of the Minio access secret.
+          It is required in order to connect to the server.
+          By default this uses the one from the local minio server if enabled
+          and <literal>config.services.minio.secretKey</literal>.
+        '';
+      } // optionalAttrs (config.services.minio.enable && config.services.minio.secretKey != "") {
+        default = config.services.minio.secretKey;
+      });
+
+      minioBucketStats = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Collect statistics about the buckets and files in buckets.
+          It requires more computation, use it carefully in case of large buckets..
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the minio exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-minio-exporter = {
+      description = "Prometheus exporter for Minio server metrics";
+      unitConfig.Documentation = "https://github.com/joe-pll/minio-exporter";
+      wantedBy = [ "multi-user.target" ];
+      after = optional config.services.minio.enable "minio.service";
+      serviceConfig = {
+        DynamicUser = true;
+        Restart = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecStart = ''
+          ${pkgs.prometheus-minio-exporter}/bin/minio-exporter \
+            -web.listen-address ${optionalString (cfg.listenAddress != null) cfg.listenAddress}:${toString cfg.port} \
+            -minio.server ${cfg.minioAddress} \
+            -minio.access-key ${cfg.minioAccessKey} \
+            -minio.access-secret ${cfg.minioAccessSecret} \
+            ${optionalString cfg.minioBucketStats "-minio.bucket-stats"} \
+            ${concatStringsSep " \\\n  " cfg.extraFlags}
+        '';
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/node-exporter.nix b/nixos/modules/services/monitoring/prometheus/node-exporter.nix
index b5b852438d77..cacfb67ef06b 100644
--- a/nixos/modules/services/monitoring/prometheus/node-exporter.nix
+++ b/nixos/modules/services/monitoring/prometheus/node-exporter.nix
@@ -33,7 +33,7 @@ in {
         default = [];
         example = ''[ "systemd" ]'';
         description = ''
-          Collectors to enable. Only collectors explicitly listed here will be enabled.
+          Collectors to enable. The collectors listed here are enabled in addition to the default ones.
         '';
       };
 
@@ -64,13 +64,12 @@ in {
       wantedBy = [ "multi-user.target" ];
       script = ''
         exec ${pkgs.prometheus-node-exporter}/bin/node_exporter \
-          ${optionalString (cfg.enabledCollectors != [])
-            ''-collectors.enabled ${concatStringsSep "," cfg.enabledCollectors}''} \
-          -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+          ${concatMapStrings (x: "--collector." + x + " ") cfg.enabledCollectors} \
+          --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
           ${concatStringsSep " \\\n  " cfg.extraFlags}
       '';
       serviceConfig = {
-        User = "nobody";
+        DynamicUser = true;
         Restart  = "always";
         PrivateTmp = true;
         WorkingDirectory = /tmp;
diff --git a/nixos/modules/services/network-filesystems/kbfs.nix b/nixos/modules/services/network-filesystems/kbfs.nix
index cf1d7617cca6..7b2eea3b5850 100644
--- a/nixos/modules/services/network-filesystems/kbfs.nix
+++ b/nixos/modules/services/network-filesystems/kbfs.nix
@@ -55,8 +55,11 @@ in {
         Restart = "on-failure";
         PrivateTmp = true;
       };
+      wantedBy = [ "default.target" ];
     };
 
     services.keybase.enable = true;
+
+    environment.systemPackages = [ pkgs.kbfs ];
   };
 }
diff --git a/nixos/modules/services/network-filesystems/openafs-client/default.nix b/nixos/modules/services/network-filesystems/openafs-client/default.nix
index 94f93162cfee..0946e379e796 100644
--- a/nixos/modules/services/network-filesystems/openafs-client/default.nix
+++ b/nixos/modules/services/network-filesystems/openafs-client/default.nix
@@ -93,7 +93,6 @@ in
       preStop = ''
         ${pkgs.utillinux}/bin/umount /afs
         ${openafsPkgs}/sbin/afsd -shutdown
-        ${pkgs.kmod}/sbin/rmmod libafs
       '';
     };
   };
diff --git a/nixos/modules/services/networking/connman.nix b/nixos/modules/services/networking/connman.nix
index d0683b877801..546d27069232 100644
--- a/nixos/modules/services/networking/connman.nix
+++ b/nixos/modules/services/networking/connman.nix
@@ -115,10 +115,5 @@ in {
       wireless.enable = true;
       networkmanager.enable = false;
     };
-
-    powerManagement.resumeCommands = ''
-      systemctl restart connman
-    '';
-
   };
 }
diff --git a/nixos/modules/services/networking/dnscache.nix b/nixos/modules/services/networking/dnscache.nix
index f782be97f6fa..379203cd1ab6 100644
--- a/nixos/modules/services/networking/dnscache.nix
+++ b/nixos/modules/services/networking/dnscache.nix
@@ -18,10 +18,13 @@ let
       '') ips}
     '') cfg.domainServers)}
 
-    # djbdns contains an outdated list of root servers;
-    # if one was not provided in config, provide a current list
-    if [ ! -e servers/@ ]; then
-      awk '/^.?.ROOT-SERVERS.NET/ { print $4 }' ${pkgs.dns-root-data}/root.hints > $out/servers/@
+    # if a list of root servers was not provided in config, copy it
+    # over. (this is also done by dnscache-conf, but we 'rm -rf
+    # /var/lib/dnscache/root' below & replace it wholesale with this,
+    # so we have to ensure servers/@ exists ourselves.)
+    if [ ! -e $out/servers/@ ]; then
+      # symlink does not work here, due chroot
+      cp ${pkgs.djbdns}/etc/dnsroots.global $out/servers/@;
     fi
   '';
 
diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix
index 68a814b23053..9bd88ca1707b 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -95,18 +95,18 @@ let
     ip46tables -N nixos-fw-log-refuse
 
     ${optionalString cfg.logRefusedConnections ''
-      ip46tables -A nixos-fw-log-refuse -p tcp --syn -j LOG --log-level info --log-prefix "rejected connection: "
+      ip46tables -A nixos-fw-log-refuse -p tcp --syn -j LOG --log-level info --log-prefix "refused connection: "
     ''}
     ${optionalString (cfg.logRefusedPackets && !cfg.logRefusedUnicastsOnly) ''
       ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type broadcast \
-        -j LOG --log-level info --log-prefix "rejected broadcast: "
+        -j LOG --log-level info --log-prefix "refused broadcast: "
       ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type multicast \
-        -j LOG --log-level info --log-prefix "rejected multicast: "
+        -j LOG --log-level info --log-prefix "refused multicast: "
     ''}
     ip46tables -A nixos-fw-log-refuse -m pkttype ! --pkt-type unicast -j nixos-fw-refuse
     ${optionalString cfg.logRefusedPackets ''
       ip46tables -A nixos-fw-log-refuse \
-        -j LOG --log-level info --log-prefix "rejected packet: "
+        -j LOG --log-level info --log-prefix "refused packet: "
     ''}
     ip46tables -A nixos-fw-log-refuse -j nixos-fw-refuse
 
diff --git a/nixos/modules/services/networking/keybase.nix b/nixos/modules/services/networking/keybase.nix
index ca5c279ac6f0..7c7982ee8eac 100644
--- a/nixos/modules/services/networking/keybase.nix
+++ b/nixos/modules/services/networking/keybase.nix
@@ -28,11 +28,12 @@ in {
       description = "Keybase service";
       serviceConfig = {
         ExecStart = ''
-          ${pkgs.keybase}/bin/keybase service
+          ${pkgs.keybase}/bin/keybase -d service --auto-forked
         '';
         Restart = "on-failure";
         PrivateTmp = true;
       };
+      wantedBy = [ "default.target" ];
     };
 
     environment.systemPackages = [ pkgs.keybase ];
diff --git a/nixos/modules/services/networking/libreswan.nix b/nixos/modules/services/networking/libreswan.nix
index e7a6c565f4ff..280158b89f61 100644
--- a/nixos/modules/services/networking/libreswan.nix
+++ b/nixos/modules/services/networking/libreswan.nix
@@ -17,7 +17,7 @@ let
       else substring (head nonchars).ind (add 1 (sub (last nonchars).ind (head nonchars).ind)) str;
   indent = str: concatStrings (concatMap (s: ["  " (trim [" " "\t"] s) "\n"]) (splitString "\n" str));
   configText = indent (toString cfg.configSetup);
-  connectionText = concatStrings (mapAttrsToList (n: v: 
+  connectionText = concatStrings (mapAttrsToList (n: v:
     ''
       conn ${n}
       ${indent v}
@@ -27,7 +27,7 @@ let
     ''
       config setup
       ${configText}
-      
+
       ${connectionText}
     '';
 
@@ -93,6 +93,9 @@ in
         "${pkgs.libreswan}"
         "${pkgs.iproute}"
         "${pkgs.procps}"
+        "${pkgs.nssTools}"
+        "${pkgs.iptables}"
+        "${pkgs.nettools}"
       ];
 
       wants = [ "network-online.target" ];
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index f3a04d97c98e..bcce4accdd6e 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -105,7 +105,7 @@ in
       description = "Unbound recursive Domain Name Server";
       after = [ "network.target" ];
       before = [ "nss-lookup.target" ];
-      wants = [" nss-lookup.target" ];
+      wants = [ "nss-lookup.target" ];
       wantedBy = [ "multi-user.target" ];
 
       preStart = ''
diff --git a/nixos/modules/services/networking/znc.nix b/nixos/modules/services/networking/znc.nix
index 3d9cec46a582..72313ab2ee14 100644
--- a/nixos/modules/services/networking/znc.nix
+++ b/nixos/modules/services/networking/znc.nix
@@ -329,7 +329,7 @@ in
       };
 
       mutable = mkOption {
-        default = false;
+        default = true;
         type = types.bool;
         description = ''
           Indicates whether to allow the contents of the `dataDir` directory to be changed
diff --git a/nixos/modules/services/scheduling/atd.nix b/nixos/modules/services/scheduling/atd.nix
index 0216c9771c96..77a3f6b51e80 100644
--- a/nixos/modules/services/scheduling/atd.nix
+++ b/nixos/modules/services/scheduling/atd.nix
@@ -42,6 +42,8 @@ in
 
   config = mkIf cfg.enable {
 
+    # Not wrapping "batch" because it's a shell script (kernel drops perms
+    # anyway) and it's patched to invoke the "at" setuid wrapper.
     security.wrappers = builtins.listToAttrs (
       map (program: { name = "${program}"; value = {
       source = "${at}/bin/${program}";
@@ -49,7 +51,7 @@ in
       group = "atd";
       setuid = true;
       setgid = true;
-    };}) [ "at" "atq" "atrm" "batch" ]);
+    };}) [ "at" "atq" "atrm" ]);
 
     environment.systemPackages = [ at ];
 
diff --git a/nixos/modules/services/scheduling/fcron.nix b/nixos/modules/services/scheduling/fcron.nix
index af4f9f41fd04..ac589be57736 100644
--- a/nixos/modules/services/scheduling/fcron.nix
+++ b/nixos/modules/services/scheduling/fcron.nix
@@ -137,10 +137,7 @@ in
       after = [ "local-fs.target" ];
       wantedBy = [ "multi-user.target" ];
 
-      # FIXME use specific path
-      environment = {
-        PATH = "/run/current-system/sw/bin";
-      };
+      path = [ pkgs.fcron ];
 
       preStart = ''
         install \
@@ -149,7 +146,7 @@ in
           --group fcron \
           --directory /var/spool/fcron
         # load system crontab file
-        /run/wrappers/bin/fcrontab -u systab ${pkgs.writeText "systab" cfg.systab}
+        /run/wrappers/bin/fcrontab -u systab - < ${pkgs.writeText "systab" cfg.systab}
       '';
 
       serviceConfig = {
diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix
index 2ea22a945940..c51dd5d94655 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -174,11 +174,13 @@ in {
         LimitNOFILE = "1024000";
       };
       preStart = ''
-        # Only set vm.max_map_count if lower than ES required minimum
-        # This avoids conflict if configured via boot.kernel.sysctl
-        if [ `${pkgs.procps}/bin/sysctl -n vm.max_map_count` -lt 262144 ]; then
-          ${pkgs.procps}/bin/sysctl -w vm.max_map_count=262144
-        fi
+        ${optionalString (!config.boot.isContainer) ''
+          # Only set vm.max_map_count if lower than ES required minimum
+          # This avoids conflict if configured via boot.kernel.sysctl
+          if [ `${pkgs.procps}/bin/sysctl -n vm.max_map_count` -lt 262144 ]; then
+            ${pkgs.procps}/bin/sysctl -w vm.max_map_count=262144
+          fi
+        ''}
 
         mkdir -m 0700 -p ${cfg.dataDir}
 
diff --git a/nixos/modules/services/security/hologram-server.nix b/nixos/modules/services/security/hologram-server.nix
index 8315c9ea5d61..e267fed27955 100644
--- a/nixos/modules/services/security/hologram-server.nix
+++ b/nixos/modules/services/security/hologram-server.nix
@@ -23,8 +23,6 @@ let
     stats  = cfg.statsAddress;
     listen = cfg.listenAddress;
   });
-
-  script = "${pkgs.hologram.bin}/bin/hologram-server --debug --conf ${cfgFile}";
 in {
   options = {
     services.hologram-server = {
@@ -96,15 +94,9 @@ in {
       after       = [ "network.target" ];
       wantedBy    = [ "multi-user.target" ];
 
-      inherit script;
-    };
-
-    docker-containers.hologram-server = {
-      inherit script;
-    };
-
-    trivial-services.hologram-server = {
-      inherit script;
+      serviceConfig = {
+        ExecStart = "${pkgs.hologram.bin}/bin/hologram-server --debug --conf ${cfgFile}";
+      };
     };
   };
 }
diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix
index 3e5087766b1c..ef48d52e7a94 100644
--- a/nixos/modules/services/security/oauth2_proxy.nix
+++ b/nixos/modules/services/security/oauth2_proxy.nix
@@ -385,7 +385,7 @@ in
 
     httpAddress = mkOption {
       type = types.str;
-      default = "127.0.0.1:4180";
+      default = "http://127.0.0.1:4180";
       description = ''
         HTTPS listening address.  This module does not expose the port by
         default. If you want this URL to be accessible to other machines, please
diff --git a/nixos/modules/services/security/sshguard.nix b/nixos/modules/services/security/sshguard.nix
index 5a183443f71d..7f09e8893c4d 100644
--- a/nixos/modules/services/security/sshguard.nix
+++ b/nixos/modules/services/security/sshguard.nix
@@ -89,7 +89,7 @@ in {
 
     environment.systemPackages = [ pkgs.sshguard pkgs.iptables pkgs.ipset ];
 
-    environment.etc."sshguard.conf".text = let 
+    environment.etc."sshguard.conf".text = let
         list_services = ( name:  "-t ${name} ");
       in ''
         BACKEND="${pkgs.sshguard}/libexec/sshg-fw-ipset"
diff --git a/nixos/modules/services/web-apps/atlassian/crowd.nix b/nixos/modules/services/web-apps/atlassian/crowd.nix
index b54c91d7de92..2a5f08046382 100644
--- a/nixos/modules/services/web-apps/atlassian/crowd.nix
+++ b/nixos/modules/services/web-apps/atlassian/crowd.nix
@@ -142,7 +142,7 @@ in
           ${pkg}/apache-tomcat/conf/server.xml.dist > ${cfg.home}/server.xml
       '';
 
-      script = "${pkg}/start_crowd.sh";
+      script = "${pkg}/start_crowd.sh -fg";
 
       serviceConfig = {
         User = cfg.user;
diff --git a/nixos/modules/services/web-apps/mattermost.nix b/nixos/modules/services/web-apps/mattermost.nix
index bc88a808abc9..0b637e3991b4 100644
--- a/nixos/modules/services/web-apps/mattermost.nix
+++ b/nixos/modules/services/web-apps/mattermost.nix
@@ -184,10 +184,12 @@ in
           fi
         '' + lib.optionalString cfg.localDatabaseCreate ''
           if ! test -e "${cfg.statePath}/.db-created"; then
-            ${config.services.postgresql.package}/bin/psql postgres -c \
-              "CREATE ROLE ${cfg.localDatabaseUser} WITH LOGIN NOCREATEDB NOCREATEROLE ENCRYPTED PASSWORD '${cfg.localDatabasePassword}'"
-            ${config.services.postgresql.package}/bin/createdb \
-              --owner ${cfg.localDatabaseUser} ${cfg.localDatabaseName}
+            ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} \
+              ${config.services.postgresql.package}/bin/psql postgres -c \
+                "CREATE ROLE ${cfg.localDatabaseUser} WITH LOGIN NOCREATEDB NOCREATEROLE ENCRYPTED PASSWORD '${cfg.localDatabasePassword}'"
+            ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} \
+              ${config.services.postgresql.package}/bin/createdb \
+                --owner ${cfg.localDatabaseUser} ${cfg.localDatabaseName}
             touch ${cfg.statePath}/.db-created
           fi
         '' + ''
diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix
index 45a65965112a..700b4469c565 100644
--- a/nixos/modules/services/web-servers/lighttpd/default.nix
+++ b/nixos/modules/services/web-servers/lighttpd/default.nix
@@ -15,7 +15,8 @@ let
   # Some modules are always imported and should not appear in the config:
   # disallowedModules = [ "mod_indexfile" "mod_dirlisting" "mod_staticfile" ];
   #
-  # Get full module list: "ls -1 $lighttpd/lib/*.so"
+  # For full module list, see the output of running ./configure in the lighttpd
+  # source.
   allKnownModules = [
     "mod_rewrite"
     "mod_redirect"
@@ -38,12 +39,15 @@ let
     "mod_accesslog"
     # Remaining list of modules, order assumed to be unimportant.
     "mod_authn_file"
+    "mod_authn_gssapi"
+    "mod_authn_ldap"
     "mod_authn_mysql"
     "mod_cml"
     "mod_deflate"
     "mod_evasive"
     "mod_extforward"
     "mod_flv_streaming"
+    "mod_geoip"
     "mod_magnet"
     "mod_mysql_vhost"
     "mod_scgi"
diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix
index 8a04e07eeeac..801601aafd9d 100644
--- a/nixos/modules/services/web-servers/nginx/vhost-options.nix
+++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix
@@ -142,10 +142,10 @@ with lib;
     globalRedirect = mkOption {
       type = types.nullOr types.str;
       default = null;
-      example = http://newserver.example.org/;
+      example = "newserver.example.org";
       description = ''
         If set, all requests for this host are redirected permanently to
-        the given URL.
+        the given hostname.
       '';
     };
 
diff --git a/nixos/modules/services/x11/compton.nix b/nixos/modules/services/x11/compton.nix
index 56bc66b71796..8701354b5285 100644
--- a/nixos/modules/services/x11/compton.nix
+++ b/nixos/modules/services/x11/compton.nix
@@ -7,6 +7,14 @@ let
 
   cfg = config.services.compton;
 
+  floatBetween = a: b: with lib; with types;
+    addCheck str (x: versionAtLeast x a && versionOlder x b);
+
+  pairOf = x: with types; addCheck (listOf x) (y: lib.length y == 2);
+
+  opacityRules = optionalString (length cfg.opacityRules != 0)
+    (concatMapStringsSep ",\n" (rule: ''"${rule}"'') cfg.opacityRules);
+
   configFile = pkgs.writeText "compton.conf"
     (optionalString cfg.fade ''
       # fading
@@ -30,7 +38,11 @@ let
       active-opacity   = ${cfg.activeOpacity};
       inactive-opacity = ${cfg.inactiveOpacity};
       menu-opacity     = ${cfg.menuOpacity};
-      
+
+      opacity-rule = [
+        ${opacityRules}
+      ];
+
       # other options
       backend = ${toJSON cfg.backend};
       vsync = ${toJSON cfg.vSync};
@@ -57,7 +69,7 @@ in {
     };
 
     fadeDelta = mkOption {
-      type = types.int;
+      type = types.addCheck types.int (x: x > 0);
       default = 10;
       example = 5;
       description = ''
@@ -66,11 +78,12 @@ in {
     };
 
     fadeSteps = mkOption {
-      type = types.listOf types.str;
+      type = pairOf (floatBetween "0.01" "1.01");
       default = [ "0.028" "0.03" ];
       example = [ "0.04" "0.04" ];
       description = ''
         Opacity change between fade steps (in and out).
+        (numbers in range 0.01 - 1.0)
       '';
     };
 
@@ -97,7 +110,7 @@ in {
     };
 
     shadowOffsets = mkOption {
-      type = types.listOf types.int;
+      type = pairOf types.int;
       default = [ (-15) (-15) ];
       example = [ (-10) (-15) ];
       description = ''
@@ -106,11 +119,11 @@ in {
     };
 
     shadowOpacity = mkOption {
-      type = types.str;
+      type = floatBetween "0.0" "1.01";
       default = "0.75";
       example = "0.8";
       description = ''
-        Window shadows opacity (number in range 0 - 1).
+        Window shadows opacity (number in range 0.0 - 1.0).
       '';
     };
 
@@ -129,52 +142,67 @@ in {
     };
 
     activeOpacity = mkOption {
-      type = types.str;
+      type = floatBetween "0.0" "1.01";
       default = "1.0";
       example = "0.8";
       description = ''
-        Opacity of active windows.
+        Opacity of active windows (number in range 0.0 - 1.0).
       '';
     };
 
     inactiveOpacity = mkOption {
-      type = types.str;
+      type = floatBetween "0.1" "1.01";
       default = "1.0";
       example = "0.8";
       description = ''
-        Opacity of inactive windows.
+        Opacity of inactive windows (number in range 0.1 - 1.0).
       '';
     };
 
     menuOpacity = mkOption {
-      type = types.str;
+      type = floatBetween "0.0" "1.01";
       default = "1.0";
       example = "0.8";
       description = ''
-        Opacity of dropdown and popup menu.
+        Opacity of dropdown and popup menu (number in range 0.0 - 1.0).
+      '';
+    };
+
+    opacityRules = mkOption {
+      type = types.listOf types.str;
+      default = [];
+      example = [
+        "95:class_g = 'URxvt' && !_NET_WM_STATE@:32a"
+        "0:_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'"
+      ];
+      description = ''
+        Rules that control the opacity of windows, in format PERCENT:PATTERN.
       '';
     };
 
     backend = mkOption {
-      type = types.str;
-      default = "glx";
+      type = types.enum [ "glx" "xrender" ];
+      default = "xrender";
       description = ''
         Backend to use: <literal>glx</literal> or <literal>xrender</literal>.
       '';
     };
 
     vSync = mkOption {
-     type = types.str;
-     default = "none";
-     example = "opengl-swc";
-     description = ''
-       Enable vertical synchronization using the specified method.
-       See <literal>compton(1)</literal> man page available methods.
-     '';
+      type = types.enum [
+        "none" "drm" "opengl"
+        "opengl-oml" "opengl-swc" "opengl-mswc"
+      ];
+      default = "none";
+      example = "opengl-swc";
+      description = ''
+        Enable vertical synchronization using the specified method.
+        See <literal>compton(1)</literal> man page an explanation.
+      '';
     };
 
     refreshRate = mkOption {
-      type = types.int;
+      type = types.addCheck types.int (x: x >= 0);
       default = 0;
       example = 60;
       description = ''
diff --git a/nixos/modules/services/x11/desktop-managers/mate.nix b/nixos/modules/services/x11/desktop-managers/mate.nix
index 7a95ac6549d8..ab8a0a48b483 100644
--- a/nixos/modules/services/x11/desktop-managers/mate.nix
+++ b/nixos/modules/services/x11/desktop-managers/mate.nix
@@ -72,6 +72,7 @@ in
     ];
 
     services.gnome3.gnome-keyring.enable = true;
+    services.upower.enable = config.powerManagement.enable;
 
     environment.pathsToLink = [ "/share" ];
   };
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index f099117f4777..685a93d952b1 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -47,7 +47,7 @@ in
             ${getBin config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1"
           ''}
 
-          exec "${plasma5.startkde}"
+          exec "${getBin plasma5.plasma-workspace}/bin/startkde"
         '';
       };
 
@@ -142,7 +142,8 @@ in
 
           kde-gtk-config breeze-gtk
 
-          phonon-backend-gstreamer
+          libsForQt56.phonon-backend-gstreamer
+          libsForQt5.phonon-backend-gstreamer
         ]
 
         ++ lib.optionals cfg.enableQt4Support [ breeze-qt4 pkgs.phonon-backend-gstreamer ]
@@ -174,7 +175,7 @@ in
         serif = [ "Noto Serif" ];
       };
 
-      programs.ssh.askPassword = "${plasma5.ksshaskpass.out}/bin/ksshaskpass";
+      programs.ssh.askPassword = mkDefault "${plasma5.ksshaskpass.out}/bin/ksshaskpass";
 
       # Enable helpful DBus services.
       services.udisks2.enable = true;
@@ -189,7 +190,7 @@ in
       ];
 
       services.xserver.displayManager.sddm = {
-        theme = "breeze";
+        theme = mkDefault "breeze";
       };
 
       security.pam.services.kde = { allowNullPassword = true; };
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 58773685ec1f..3fa482fb6722 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -92,9 +92,12 @@ let
         ${config.hardware.pulseaudio.package.out}/bin/pactl load-module module-x11-publish "display=$DISPLAY"
       ''}
 
-      # Tell systemd about our $DISPLAY. This is needed by the
-      # ssh-agent unit.
-      ${config.systemd.package}/bin/systemctl --user import-environment DISPLAY
+      # Tell systemd about our $DISPLAY and $XAUTHORITY.
+      # This is needed by the ssh-agent unit.
+      #
+      # Also tell systemd about the dbus session bus address.
+      # This is required by user units using the session bus.
+      ${config.systemd.package}/bin/systemctl --user import-environment DISPLAY XAUTHORITY DBUS_SESSION_BUS_ADDRESS
 
       # Load X defaults.
       ${xorg.xrdb}/bin/xrdb -merge ${xresourcesXft}
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index e6cc02e4d491..facaea131ae5 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -19,6 +19,17 @@ let
 
   Xsetup = pkgs.writeScript "Xsetup" ''
     #!/bin/sh
+
+    # Prior to Qt 5.9.2, there is a QML cache invalidation bug which sometimes
+    # strikes new Plasma 5 releases. If the QML cache is not invalidated, SDDM
+    # will segfault without explanation. We really tore our hair out for awhile
+    # before finding the bug:
+    # https://bugreports.qt.io/browse/QTBUG-62302
+    # We work around the problem by deleting the QML cache before startup. It
+    # will be regenerated, causing a small but perceptible delay when SDDM
+    # starts.
+    rm -fr /var/lib/sddm/.cache/sddm-greeter/qmlcache
+
     ${cfg.setupScript}
   '';
 
diff --git a/nixos/modules/services/x11/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix
index d75c785270b3..44555cb6e2a9 100644
--- a/nixos/modules/services/x11/hardware/libinput.nix
+++ b/nixos/modules/services/x11/hardware/libinput.nix
@@ -75,12 +75,13 @@ in {
         default = null;
         description =
           ''
-            Enables a click method. Permitted values are none, buttonareas, clickfinger.
+            Enables a click method. Permitted values are <literal>none</literal>,
+            <literal>buttonareas</literal>, <literal>clickfinger</literal>.
             Not all devices support all methods, if an option is unsupported,
-            the default click method for this device is used. 
+            the default click method for this device is used.
           '';
       };
-      
+
       leftHanded = mkOption {
         type = types.bool;
         default = false;
@@ -96,7 +97,7 @@ in {
             simultaneously produces a middle mouse button click.
           '';
       };
-      
+
       naturalScrolling = mkOption {
         type = types.bool;
         default = false;
@@ -120,7 +121,8 @@ in {
         example = "edge";
         description =
           ''
-            Specify the scrolling method.
+            Specify the scrolling method: <literal>twofinger</literal>, <literal>edge</literal>,
+            or <literal>none</literal>
           '';
       };
 
@@ -141,7 +143,8 @@ in {
         example = "disabled";
         description =
           ''
-            Sets the send events mode to disabled, enabled, or "disable when an external mouse is connected".
+            Sets the send events mode to <literal>disabled</literal>, <literal>enabled</literal>,
+            or <literal>disabled-on-external-mouse</literal>
           '';
       };
 
diff --git a/nixos/modules/services/x11/redshift.nix b/nixos/modules/services/x11/redshift.nix
index 992709ed0000..30d853841ea4 100644
--- a/nixos/modules/services/x11/redshift.nix
+++ b/nixos/modules/services/x11/redshift.nix
@@ -19,18 +19,31 @@ in {
     };
 
     latitude = mkOption {
-      type = types.str;
+      type = types.nullOr types.str;
+      default = null;
       description = ''
         Your current latitude, between
-        <literal>-90.0</literal> and <literal>90.0</literal>.
+        <literal>-90.0</literal> and <literal>90.0</literal>. Must be provided
+        along with longitude.
       '';
     };
 
     longitude = mkOption {
-      type = types.str;
+      type = types.nullOr types.str;
+      default = null;
       description = ''
         Your current longitude, between
-        between <literal>-180.0</literal> and <literal>180.0</literal>.
+        between <literal>-180.0</literal> and <literal>180.0</literal>. Must be
+        provided along with latitude.
+      '';
+    };
+
+    provider = mkOption {
+      type = types.enum [ "manual" "geoclue2" ];
+      default = "manual";
+      description = ''
+        The location provider to use for determining your location. If set to
+        <literal>manual</literal> you must also provide latitude/longitude.
       '';
     };
 
@@ -93,14 +106,33 @@ in {
   };
 
   config = mkIf cfg.enable {
-    systemd.user.services.redshift = {
+    assertions = [ 
+      {
+        assertion = 
+          if cfg.provider == "manual"
+          then (cfg.latitude != null && cfg.longitude != null) 
+          else (cfg.latitude == null && cfg.longitude == null);
+        message = "Latitude and longitude must be provided together, and with provider set to null.";
+      }
+    ];
+
+    services.geoclue2.enable = mkIf (cfg.provider == "geoclue2") true;
+
+    systemd.user.services.redshift = 
+    let
+      providerString = 
+        if cfg.provider == "manual"
+        then "${cfg.latitude}:${cfg.longitude}"
+        else cfg.provider;
+    in
+    {
       description = "Redshift colour temperature adjuster";
       wantedBy = [ "graphical-session.target" ];
       partOf = [ "graphical-session.target" ];
       serviceConfig = {
         ExecStart = ''
           ${cfg.package}/bin/redshift \
-            -l ${cfg.latitude}:${cfg.longitude} \
+            -l ${providerString} \
             -t ${toString cfg.temperature.day}:${toString cfg.temperature.night} \
             -b ${toString cfg.brightness.day}:${toString cfg.brightness.night} \
             ${lib.strings.concatStringsSep " " cfg.extraOptions}
diff --git a/nixos/modules/services/x11/xautolock.nix b/nixos/modules/services/x11/xautolock.nix
index 60ce9e6ed5c0..28fc92024bcb 100644
--- a/nixos/modules/services/x11/xautolock.nix
+++ b/nixos/modules/services/x11/xautolock.nix
@@ -31,7 +31,17 @@ in
           type = types.string;
 
           description = ''
-            The script to use when locking the computer.
+            The script to use when automatically locking the computer.
+          '';
+        };
+
+        nowlocker = mkOption {
+          default = null;
+          example = "i3lock -i /path/to/img";
+          type = types.nullOr types.string;
+
+          description = ''
+            The script to use when manually locking the computer with <command>xautolock -locknow</command>.
           '';
         };
 
@@ -45,28 +55,82 @@ in
         };
 
         notifier = mkOption {
-          default = "notify-send 'Locking in 10 seconds'";
-          type = types.string;
+          default = null;
+          example = literalExample ''
+            "${pkgs.libnotify}/bin/notify-send \"Locking in 10 seconds\""
+          '';
+          type = types.nullOr types.string;
 
           description = ''
             Notification script to be used to warn about the pending autolock.
           '';
         };
+
+        killer = mkOption {
+          default = null; # default according to `man xautolock` is none
+          example = "systemctl suspend";
+          type = types.nullOr types.string;
+
+          description = ''
+            The script to use when nothing has happend for as long as <option>killtime</option>
+          '';
+        };
+
+        killtime = mkOption {
+          default = 20; # default according to `man xautolock`
+          type = types.int;
+
+          description = ''
+            Minutes xautolock waits until it executes the script specified in <option>killer</option>
+            (Has to be at least 10 minutes)
+          '';
+        };
+
+        extraOptions = mkOption {
+          type = types.listOf types.str;
+          default = [ ];
+          example = [ "-detectsleep" ];
+          description = ''
+            Additional command-line arguments to pass to
+            <command>xautolock</command>.
+          '';
+        };
       };
     };
 
     config = mkIf cfg.enable {
       environment.systemPackages = with pkgs; [ xautolock ];
-
-      services.xserver.displayManager.sessionCommands = with builtins; with pkgs; ''
-        ${xautolock}/bin/xautolock \
-          ${concatStringsSep " \\\n" ([
-            "-time ${toString(cfg.time)}"
-            "-locker ${cfg.locker}"
-          ] ++ optional cfg.enableNotifier (concatStringsSep " " [ 
-            "-notify ${toString(cfg.notify)}"
-            "-notifier \"${cfg.notifier}\""
-          ]))} &
-      '';
+      systemd.user.services.xautolock = {
+        description = "xautolock service";
+        wantedBy = [ "graphical-session.target" ];
+        partOf = [ "graphical-session.target" ];
+        serviceConfig = with lib; {
+          ExecStart = strings.concatStringsSep " " ([
+            "${pkgs.xautolock}/bin/xautolock"
+            "-noclose"
+            "-time ${toString cfg.time}"
+            "-locker '${cfg.locker}'"
+          ] ++ optionals cfg.enableNotifier [
+            "-notify ${toString cfg.notify}"
+            "-notifier '${cfg.notifier}'"
+          ] ++ optionals (cfg.nowlocker != null) [
+            "-nowlocker '${cfg.nowlocker}'"
+          ] ++ optionals (cfg.killer != null) [
+            "-killer '${cfg.killer}'"
+            "-killtime ${toString cfg.killtime}"
+          ] ++ cfg.extraOptions);
+          Restart = "always";
+        };
+      };
+      assertions = [
+        {
+          assertion = cfg.enableNotifier -> cfg.notifier != null;
+          message = "When enabling the notifier for xautolock, you also need to specify the notify script";
+        }
+        {
+          assertion = cfg.killer != null -> cfg.killtime >= 10;
+          message = "killtime has to be at least 10 minutes according to `man xautolock`";
+        }
+      ];
     };
   }
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix
index cf70a891c0ca..4db9631743e3 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -193,11 +193,6 @@ in
         "sd_mod"
         "sr_mod"
 
-        # Standard IDE stuff.
-        "ide_cd"
-        "ide_disk"
-        "ide_generic"
-
         # SD cards and internal eMMC drives.
         "mmc_block"
 
@@ -211,21 +206,11 @@ in
         "xhci_hcd"
         "xhci_pci"
         "usbhid"
-        "hid_generic" "hid_lenovo"
-        "hid_apple" "hid_logitech_dj" "hid_lenovo_tpkbd" "hid_roccat"
+        "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat"
 
         # Misc. keyboard stuff.
         "pcips2" "atkbd" "i8042"
 
-        # Temporary fix for https://github.com/NixOS/nixpkgs/issues/18451
-        # Remove as soon as upstream gets fixed - marking it:
-        # TODO
-        # FIXME
-        "i8042"
-
-        # To wait for SCSI devices to appear.
-        "scsi_wait_scan"
-
         # Needed by the stage 2 init script.
         "rtc_cmos"
       ];
diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl
index 82b5bcda9217..cc03e54ead63 100644
--- a/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ b/nixos/modules/system/boot/loader/grub/install-grub.pl
@@ -197,7 +197,7 @@ sub GrubFs {
                 if ($status != 0) {
                     die "Failed to retrieve subvolume info for @{[$fs->mount]}\n";
                 }
-                my @ids = join("", @id_info) =~ m/Subvolume ID:[ \t\n]*([^ \t\n]*)/;
+                my @ids = join("\n", @id_info) =~ m/^(?!\/\n).*Subvolume ID:[ \t\n]*([0-9]+)/s;
                 if ($#ids > 0) {
                     die "Btrfs subvol name for @{[$fs->device]} listed multiple times in mount\n"
                 } elsif ($#ids == 0) {
diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix
index a3fb733c289d..2147d43c4f19 100644
--- a/nixos/modules/system/boot/resolved.nix
+++ b/nixos/modules/system/boot/resolved.nix
@@ -31,8 +31,15 @@ in
       example = [ "example.com" ];
       type = types.listOf types.str;
       description = ''
-        A list of domains. These domains are used as search suffixes when resolving single-label host names (domain names which contain no dot), in order to qualify them into fully-qualified domain names (FQDNs).
-        For compatibility reasons, if this setting is not specified, the search domains listed in /etc/resolv.conf are used instead, if that file exists and any domains are configured in it.
+        A list of domains. These domains are used as search suffixes
+        when resolving single-label host names (domain names which
+        contain no dot), in order to qualify them into fully-qualified
+        domain names (FQDNs).
+        </para><para>
+        For compatibility reasons, if this setting is not specified,
+        the search domains listed in
+        <filename>/etc/resolv.conf</filename> are used instead, if
+        that file exists and any domains are configured in it.
       '';
     };
 
@@ -41,10 +48,30 @@ in
       example = "false";
       type = types.enum [ "true" "resolve" "false" ];
       description = ''
-        Controls Link-Local Multicast Name Resolution support (RFC 4794) on the local host.
-        If true, enables full LLMNR responder and resolver support.
-        If false, disables both.
-        If set to "resolve", only resolution support is enabled, but responding is disabled.
+        Controls Link-Local Multicast Name Resolution support
+        (RFC 4795) on the local host.
+        </para><para>
+        If set to
+        <variablelist>
+        <varlistentry>
+          <term><literal>"true"</literal></term>
+          <listitem><para>
+            Enables full LLMNR responder and resolver support.
+          </para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><literal>"false"</literal></term>
+          <listitem><para>
+            Disables both.
+          </para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><literal>"resolve"</literal></term>
+          <listitem><para>
+            Only resolution support is enabled, but responding is disabled.
+          </para></listitem>
+        </varlistentry>
+        </variablelist>
       '';
     };
 
@@ -53,9 +80,36 @@ in
       example = "true";
       type = types.enum [ "true" "allow-downgrade" "false" ];
       description = ''
-        If true all DNS lookups are DNSSEC-validated locally (excluding LLMNR and Multicast DNS). Note that this mode requires a DNS server that supports DNSSEC. If the DNS server does not properly support DNSSEC all validations will fail.
-        If set to "allow-downgrade" DNSSEC validation is attempted, but if the server does not support DNSSEC properly, DNSSEC mode is automatically disabled. Note that this mode makes DNSSEC validation vulnerable to "downgrade" attacks, where an attacker might be able to trigger a downgrade to non-DNSSEC mode by synthesizing a DNS response that suggests DNSSEC was not supported.
-        If set to false, DNS lookups are not DNSSEC validated.
+        If set to
+        <variablelist>
+        <varlistentry>
+          <term><literal>"true"</literal></term>
+          <listitem><para>
+            all DNS lookups are DNSSEC-validated locally (excluding
+            LLMNR and Multicast DNS). Note that this mode requires a
+            DNS server that supports DNSSEC. If the DNS server does
+            not properly support DNSSEC all validations will fail.
+          </para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><literal>"allow-downgrade"</literal></term>
+          <listitem><para>
+            DNSSEC validation is attempted, but if the server does not
+            support DNSSEC properly, DNSSEC mode is automatically
+            disabled. Note that this mode makes DNSSEC validation
+            vulnerable to "downgrade" attacks, where an attacker might
+            be able to trigger a downgrade to non-DNSSEC mode by
+            synthesizing a DNS response that suggests DNSSEC was not
+            supported.
+          </para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><literal>"false"</literal></term>
+          <listitem><para>
+            DNS lookups are not DNSSEC validated.
+          </para></listitem>
+        </varlistentry>
+        </variablelist>
       '';
     };
 
diff --git a/nixos/modules/tasks/encrypted-devices.nix b/nixos/modules/tasks/encrypted-devices.nix
index 6bbf335e7db7..da0c9408d891 100644
--- a/nixos/modules/tasks/encrypted-devices.nix
+++ b/nixos/modules/tasks/encrypted-devices.nix
@@ -36,7 +36,7 @@ let
 
       keyFile = mkOption {
         default = null;
-        example = "/root/.swapkey";
+        example = "/mnt-root/root/.swapkey";
         type = types.nullOr types.str;
         description = "File system location of keyfile. This unlocks the drive after the root has been mounted to <literal>/mnt-root</literal>.";
       };
@@ -67,7 +67,6 @@ in
       luks = {
         devices =
           map (dev: { name = dev.encrypted.label; device = dev.encrypted.blkDev; } ) keylessEncDevs;
-        cryptoModules = [ "aes" "sha256" "sha1" "xts" ];
         forceLuksSupportInInitrd = true;
       };
       postMountCommands =
diff --git a/nixos/modules/tasks/filesystems/ecryptfs.nix b/nixos/modules/tasks/filesystems/ecryptfs.nix
new file mode 100644
index 000000000000..12a407cabbfb
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/ecryptfs.nix
@@ -0,0 +1,14 @@
+{ config, lib, pkgs, ... }:
+# TODO: make ecryptfs work in initramfs?
+
+with lib;
+
+{
+  config = mkIf (any (fs: fs == "ecryptfs") config.boot.supportedFilesystems) {
+    system.fsPackages = [ pkgs.ecryptfs ];
+    security.wrappers = {
+      "mount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/mount.ecryptfs_private";
+      "umount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/umount.ecryptfs_private";
+    };
+  };
+}
diff --git a/nixos/modules/tasks/filesystems/ext.nix b/nixos/modules/tasks/filesystems/ext.nix
index cc9d0ef37d59..3a8999c242bd 100644
--- a/nixos/modules/tasks/filesystems/ext.nix
+++ b/nixos/modules/tasks/filesystems/ext.nix
@@ -5,7 +5,8 @@
 
     system.fsPackages = [ pkgs.e2fsprogs ];
 
-    boot.initrd.availableKernelModules = [ "ext2" "ext3" "ext4" ];
+    # As of kernel 4.3, there is no separate ext3 driver (they're also handled by ext4.ko)
+    boot.initrd.availableKernelModules = [ "ext2" "ext4" ];
 
     boot.initrd.extraUtilsCommands =
       ''
diff --git a/nixos/modules/tasks/powertop.nix b/nixos/modules/tasks/powertop.nix
index 0ec4974789b4..609831506e16 100644
--- a/nixos/modules/tasks/powertop.nix
+++ b/nixos/modules/tasks/powertop.nix
@@ -16,6 +16,7 @@ in {
       powertop = {
         wantedBy = [ "multi-user.target" ];
         description = "Powertop tunings";
+        path = [ pkgs.kmod ];
         serviceConfig = {
           Type = "oneshot";
           RemainAfterExit = "yes";
diff --git a/nixos/modules/virtualisation/brightbox-image.nix b/nixos/modules/virtualisation/brightbox-image.nix
index 7f45f0f34f71..08bbcfd9d7c2 100644
--- a/nixos/modules/virtualisation/brightbox-image.nix
+++ b/nixos/modules/virtualisation/brightbox-image.nix
@@ -33,9 +33,9 @@ in
         }
         ''
           # Create partition table
-          ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos
-          ${pkgs.parted}/sbin/parted /dev/vda mkpart primary ext4 1 ${diskSize}
-          ${pkgs.parted}/sbin/parted /dev/vda print
+          ${pkgs.parted}/sbin/parted --script /dev/vda mklabel msdos
+          ${pkgs.parted}/sbin/parted --script /dev/vda mkpart primary ext4 1 ${diskSize}
+          ${pkgs.parted}/sbin/parted --script /dev/vda print
           . /sys/class/block/vda1/uevent
           mknod /dev/vda1 b $MAJOR $MINOR