about 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/hardware/opengl.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-aarch64.nix10
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix7
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix1
-rw-r--r--nixos/modules/installer/scan/detected.nix5
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl15
-rw-r--r--nixos/modules/misc/crashdump.nix39
-rw-r--r--nixos/modules/misc/ids.nix11
-rw-r--r--nixos/modules/misc/locate.nix16
-rw-r--r--nixos/modules/module-list.nix19
-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/ssh.nix4
-rw-r--r--nixos/modules/programs/sway.nix69
-rw-r--r--nixos/modules/programs/zsh/zsh-syntax-highlighting.nix116
-rw-r--r--nixos/modules/rename.nix9
-rw-r--r--nixos/modules/security/acme.nix18
-rw-r--r--nixos/modules/security/acme.xml3
-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/databases/mysql.nix2
-rw-r--r--nixos/modules/services/databases/pgmanage.nix (renamed from nixos/modules/services/databases/postage.nix)125
-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.nix18
-rw-r--r--nixos/modules/services/misc/gitea.nix270
-rw-r--r--nixos/modules/services/misc/gitlab.nix16
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix1
-rw-r--r--nixos/modules/services/misc/nixos-manual.nix5
-rw-r--r--nixos/modules/services/misc/plex.nix2
-rw-r--r--nixos/modules/services/misc/plexpy.nix81
-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/dd-agent/dd-agent.nix2
-rw-r--r--nixos/modules/services/monitoring/graphite.nix76
-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.nix22
-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/babeld.nix98
-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/dnschain.nix2
-rw-r--r--nixos/modules/services/networking/dnsmasq.nix14
-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/networkmanager.nix27
-rw-r--r--nixos/modules/services/networking/strongswan.nix25
-rw-r--r--nixos/modules/services/networking/unbound.nix6
-rw-r--r--nixos/modules/services/networking/wireguard.nix1
-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.nix12
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix1
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/wordpress.nix1
-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.nix74
-rw-r--r--nixos/modules/services/x11/desktop-managers/lxqt.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/mate.nix1
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix14
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix9
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix1
-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/plymouth.nix20
-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.nix15
-rw-r--r--nixos/modules/tasks/filesystems/ecryptfs.nix14
-rw-r--r--nixos/modules/tasks/filesystems/ext.nix3
-rw-r--r--nixos/modules/tasks/network-interfaces-scripted.nix3
-rw-r--r--nixos/modules/tasks/powertop.nix1
-rw-r--r--nixos/modules/virtualisation/brightbox-image.nix6
-rw-r--r--nixos/modules/virtualisation/containers.nix4
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix12
106 files changed, 1650 insertions, 614 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/hardware/opengl.nix b/nixos/modules/hardware/opengl.nix
index 486fe7c1cd8f..c2c36f02a143 100644
--- a/nixos/modules/hardware/opengl.nix
+++ b/nixos/modules/hardware/opengl.nix
@@ -93,7 +93,7 @@ in
     hardware.opengl.extraPackages = mkOption {
       type = types.listOf types.package;
       default = [];
-      example = literalExample "with pkgs; [ vaapiIntel libvdpau-va-gl vaapiVdpau ]";
+      example = literalExample "with pkgs; [ vaapiIntel libvdpau-va-gl vaapiVdpau intel-ocl ]";
       description = ''
         Additional packages to add to OpenGL drivers. This can be used
         to add OpenCL drivers, VA-API/VDPAU drivers etc.
diff --git a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
index 8d80ceff84e0..c94dc7d40194 100644
--- a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
@@ -10,6 +10,7 @@ let
 in
 {
   imports = [
+    ../../profiles/base.nix
     ../../profiles/installation-device.nix
     ./sd-image.nix
   ];
@@ -27,9 +28,12 @@ in
   boot.loader.generic-extlinux-compatible.enable = true;
 
   boot.kernelPackages = pkgs.linuxPackages_latest;
-  # Increase the amount of CMA to ensure the virtual console on the RPi3 works.
-  boot.kernelParams = ["cma=32M" "console=ttyS0,115200n8" "console=tty0"];
-  boot.consoleLogLevel = 7;
+
+  # The serial ports listed here are:
+  # - ttyS0: for Tegra (Jetson TX1)
+  # - ttyAMA0: for QEMU's -machine virt
+  # Also increase the amount of CMA to ensure the virtual console on the RPi3 works.
+  boot.kernelParams = ["cma=32M" "console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"];
 
   # FIXME: this probably should be in installation-device.nix
   users.extraUsers.root.initialHashedPassword = "";
diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
index 1c664e025036..880a6bf2e1e8 100644
--- a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
@@ -10,6 +10,7 @@ let
 in
 {
   imports = [
+    ../../profiles/base.nix
     ../../profiles/installation-device.nix
     ./sd-image.nix
   ];
@@ -27,6 +28,12 @@ in
   boot.loader.generic-extlinux-compatible.enable = true;
 
   boot.kernelPackages = pkgs.linuxPackages_latest;
+  # The serial ports listed here are:
+  # - ttyS0: for Tegra (Jetson TK1)
+  # - ttymxc0: for i.MX6 (Wandboard)
+  # - ttyAMA0: for Allwinner (pcDuino3 Nano) and QEMU's -machine virt
+  # - ttyO0: for OMAP (BeagleBone Black)
+  # - ttySAC2: for Exynos (ODROID-XU3)
   boot.kernelParams = ["console=ttyS0,115200n8" "console=ttymxc0,115200n8" "console=ttyAMA0,115200n8" "console=ttyO0,115200n8" "console=ttySAC2,115200n8" "console=tty0"];
 
   # FIXME: this probably should be in installation-device.nix
diff --git a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
index 3f2970757bd2..eb676eae05e8 100644
--- a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
@@ -10,6 +10,7 @@ let
 in
 {
   imports = [
+    ../../profiles/base.nix
     ../../profiles/installation-device.nix
     ./sd-image.nix
   ];
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..7c737e84de0a 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -8,6 +8,7 @@ use File::Basename;
 use File::Slurp;
 use File::stat;
 
+umask(0022);
 
 sub uniq {
     my %seen;
@@ -103,7 +104,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 +399,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/crashdump.nix b/nixos/modules/misc/crashdump.nix
index 5ef4b7781bd0..6e0b49fa9af0 100644
--- a/nixos/modules/misc/crashdump.nix
+++ b/nixos/modules/misc/crashdump.nix
@@ -18,26 +18,23 @@ in
           default = false;
           description = ''
             If enabled, NixOS will set up a kernel that will
-            boot on crash, and leave the user to a stage1 debug1devices
-            interactive shell to be able to save the crashed kernel dump.
+            boot on crash, and leave the user in systemd rescue
+            to be able to save the crashed kernel dump at
+            /proc/vmcore.
             It also activates the NMI watchdog.
           '';
         };
-        kernelPackages = mkOption {
-          type = types.package;
-          default = pkgs.linuxPackages;
-          # We don't want to evaluate all of linuxPackages for the manual
-          # - some of it might not even evaluate correctly.
-          defaultText = "pkgs.linuxPackages";
-          example = literalExample "pkgs.linuxPackages_2_6_25";
+        reservedMemory = mkOption {
+          default = "128M";
           description = ''
-            This will override the boot.kernelPackages, and will add some
-            kernel configuration parameters for the crash dump to work.
+            The amount of memory reserved for the crashdump kernel.
+            If you choose a too high value, dmesg will mention
+            "crashkernel reservation failed".
           '';
         };
         kernelParams = mkOption {
           type = types.listOf types.str;
-          default = [ "debug1devices" ];
+          default = [ "1" "boot.shell_on_fail" ];
           description = ''
             Parameters that will be passed to the kernel kexec-ed on crash.
           '';
@@ -51,29 +48,29 @@ in
   config = mkIf crashdump.enable {
     boot = {
       postBootCommands = ''
+        echo "loading crashdump kernel...";
         ${pkgs.kexectools}/sbin/kexec -p /run/current-system/kernel \
         --initrd=/run/current-system/initrd \
-        --append="init=$(readlink -f /run/current-system/init) system=$(readlink -f /run/current-system) irqpoll maxcpus=1 reset_devices ${kernelParams}" --reset-vga --console-vga
+        --reset-vga --console-vga \
+        --command-line="systemConfig=$(readlink -f /run/current-system) init=$(readlink -f /run/current-system/init) irqpoll maxcpus=1 reset_devices ${kernelParams}"
       '';
       kernelParams = [
-       "crashkernel=64M"
+       "crashkernel=${crashdump.reservedMemory}"
        "nmi_watchdog=panic"
        "softlockup_panic=1"
        "idle=poll"
       ];
-      kernelPackages = mkOverride 50 (crashdump.kernelPackages // {
-        kernel = crashdump.kernelPackages.kernel.override 
-          (attrs: {
-            extraConfig = (optionalString (attrs ? extraConfig) attrs.extraConfig) +
-              ''
+      kernelPatches = [ {
+        name = "crashdump-config";
+        patch = null;
+        extraConfig = ''
                 CRASH_DUMP y
                 DEBUG_INFO y
                 PROC_VMCORE y
                 LOCKUP_DETECTOR y
                 HARDLOCKUP_DETECTOR y
               '';
-          });
-      });
+        } ];
     };
   };
 }
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 508a76d3cab5..7d0cbf6aad02 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -207,11 +207,12 @@
       ripple-data-api = 186;
       mediatomb = 187;
       rdnssd = 188;
-      # ihaskell = 189; # unused
+      ihaskell = 189;
       i2p = 190;
       lambdabot = 191;
       asterisk = 192;
       plex = 193;
+      plexpy = 195;
       grafana = 196;
       skydns = 197;
       # ripple-rest = 198; # unused, removed 2017-08-12
@@ -296,6 +297,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!
 
@@ -480,7 +484,7 @@
       #ripple-data-api = 186; #unused
       mediatomb = 187;
       #rdnssd = 188; # unused
-      # ihaskell = 189; # unused
+      ihaskell = 189;
       i2p = 190;
       lambdabot = 191;
       asterisk = 192;
@@ -561,6 +565,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..99d3c0112f2a 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
@@ -191,7 +185,7 @@
   ./services/databases/neo4j.nix
   ./services/databases/openldap.nix
   ./services/databases/opentsdb.nix
-  ./services/databases/postage.nix
+  ./services/databases/pgmanage.nix
   ./services/databases/postgresql.nix
   ./services/databases/redis.nix
   ./services/databases/riak.nix
@@ -303,13 +297,14 @@
   ./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
   ./services/misc/gogs.nix
   ./services/misc/gollum.nix
   ./services/misc/gpsd.nix
-  #./services/misc/ihaskell.nix
+  ./services/misc/ihaskell.nix
   ./services/misc/irkerd.nix
   ./services/misc/jackett.nix
   ./services/misc/logkeys.nix
@@ -333,6 +328,8 @@
   ./services/misc/parsoid.nix
   ./services/misc/phd.nix
   ./services/misc/plex.nix
+  ./services/misc/plexpy.nix
+  ./services/misc/pykms.nix
   ./services/misc/radarr.nix
   ./services/misc/redmine.nix
   ./services/misc/rippled.nix
@@ -349,6 +346,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 +373,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
@@ -414,6 +413,7 @@
   ./services/networking/asterisk.nix
   ./services/networking/atftpd.nix
   ./services/networking/avahi-daemon.nix
+  ./services/networking/babeld.nix
   ./services/networking/bind.nix
   ./services/networking/autossh.nix
   ./services/networking/bird.nix
@@ -698,6 +698,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/ssh.nix b/nixos/modules/programs/ssh.nix
index e0fbba897fa4..0935bf0cae71 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -148,11 +148,11 @@ in
           [
             {
               hostNames = [ "myhost" "myhost.mydomain.com" "10.10.1.4" ];
-              publicKeyFile = "./pubkeys/myhost_ssh_host_dsa_key.pub";
+              publicKeyFile = ./pubkeys/myhost_ssh_host_dsa_key.pub;
             }
             {
               hostNames = [ "myhost2" ];
-              publicKeyFile = "./pubkeys/myhost2_ssh_host_dsa_key.pub";
+              publicKeyFile = ./pubkeys/myhost2_ssh_host_dsa_key.pub;
             }
           ]
         '';
diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix
new file mode 100644
index 000000000000..9070722c770b
--- /dev/null
+++ b/nixos/modules/programs/sway.nix
@@ -0,0 +1,69 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.sway;
+  sway = pkgs.sway;
+
+  swayWrapped = pkgs.writeScriptBin "sway" ''
+    #! ${pkgs.stdenv.shell}
+    ${cfg.extraSessionCommands}
+    PATH="${sway}/bin:$PATH"
+    exec ${pkgs.dbus.dbus-launch} --exit-with-session sway-setcap
+  '';
+  swayJoined = pkgs.symlinkJoin {
+    name = "sway-wrapped";
+    paths = [ swayWrapped sway ];
+  };
+in
+{
+  options.programs.sway = {
+    enable = mkEnableOption "sway";
+
+    extraSessionCommands = mkOption {
+      default     = "";
+      type        = types.lines;
+      example = ''
+        export XKB_DEFAULT_LAYOUT=us,de
+        export XKB_DEFAULT_VARIANT=,nodeadkeys
+        export XKB_DEFAULT_OPTIONS=grp:alt_shift_toggle,
+      '';
+      description = ''
+        Shell commands executed just before sway is started.
+      '';
+    };
+
+    extraPackages = mkOption {
+      type = with types; listOf package;
+      default = with pkgs; [
+        i3status xwayland rxvt_unicode dmenu
+      ];
+      example = literalExample ''
+        with pkgs; [
+          i3status xwayland rxvt_unicode dmenu
+        ]
+      '';
+      description = ''
+        Extra packages to be installed system wide.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ swayJoined ] ++ cfg.extraPackages;
+    security.wrappers.sway = {
+      program = "sway-setcap";
+      source = "${sway}/bin/sway";
+      capabilities = "cap_sys_ptrace,cap_sys_tty_config=eip";
+      owner = "root";
+      group = "sway";
+      permissions = "u+rx,g+rx";
+    };
+
+    users.extraGroups.sway = {};
+
+    hardware.opengl.enable = mkDefault true;
+    fonts.enableDefaultFonts = mkDefault true;
+  };
+}
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/acme.nix b/nixos/modules/security/acme.nix
index a40c5ef9ebe1..fb011019f7f5 100644
--- a/nixos/modules/security/acme.nix
+++ b/nixos/modules/security/acme.nix
@@ -139,6 +139,20 @@ in
         '';
       };
 
+      production = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          If set to true, use Let's Encrypt's production environment
+          instead of the staging environment. The main benefit of the
+          staging environment is to get much higher rate limits.
+
+          See
+          <literal>https://letsencrypt.org/docs/staging-environment</literal>
+          for more detail.
+        '';
+      };
+
       certs = mkOption {
         default = { };
         type = with types; attrsOf (submodule certOpts);
@@ -177,7 +191,9 @@ in
                 cmdline = [ "-v" "-d" domain "--default_root" data.webroot "--valid_min" cfg.validMin ]
                           ++ optionals (data.email != null) [ "--email" data.email ]
                           ++ concatMap (p: [ "-f" p ]) data.plugins
-                          ++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains);
+                          ++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains)
+                          ++ (if cfg.production then []
+                              else ["--server" "https://acme-staging.api.letsencrypt.org/directory"]);
                 acmeService = {
                   description = "Renew ACME Certificate for ${cert}";
                   after = [ "network.target" "network-online.target" ];
diff --git a/nixos/modules/security/acme.xml b/nixos/modules/security/acme.xml
index 823806f4641b..6130ed82ed38 100644
--- a/nixos/modules/security/acme.xml
+++ b/nixos/modules/security/acme.xml
@@ -89,8 +89,5 @@ services.nginx = {
   };
 }
 </programlisting>
-
-<para>At the moment you still have to restart Nginx after the ACME
-certs arrive.</para>
 </section>
 </chapter>
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..9c06e1d43bbe 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.bash pkgs.nix ];
+        defaultText = "[ pkgs.bash 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/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix
index 845e6d4c22ef..c6c463bce7d5 100644
--- a/nixos/modules/services/databases/mysql.nix
+++ b/nixos/modules/services/databases/mysql.nix
@@ -67,7 +67,7 @@ in
         type = types.nullOr types.str;
         default = null;
         example = literalExample "0.0.0.0";
-        description = "Address to bind to. The default it to bind to all addresses";
+        description = "Address to bind to. The default is to bind to all addresses";
       };
 
       port = mkOption {
diff --git a/nixos/modules/services/databases/postage.nix b/nixos/modules/services/databases/pgmanage.nix
index d49c9a83a46f..86733a3e5a07 100644
--- a/nixos/modules/services/databases/postage.nix
+++ b/nixos/modules/services/databases/pgmanage.nix
@@ -3,16 +3,16 @@
 with lib;
 
 let
-  cfg = config.services.postage;
+  cfg = config.services.pgmanage;
 
   confFile = pkgs.writeTextFile {
-    name = "postage.conf";
+    name = "pgmanage.conf";
     text =  ''
-      connection_file = ${postageConnectionsFile}
+      connection_file = ${pgmanageConnectionsFile}
 
       allow_custom_connections = ${builtins.toJSON cfg.allowCustomConnections}
 
-      postage_port = ${toString cfg.port}
+      pgmanage_port = ${toString cfg.port}
 
       super_only = ${builtins.toJSON cfg.superOnly}
 
@@ -20,7 +20,7 @@ let
 
       login_timeout = ${toString cfg.loginTimeout}
 
-      web_root = ${cfg.package}/etc/postage/web_root
+      web_root = ${cfg.package}/etc/pgmanage/web_root
 
       data_root = ${cfg.dataRoot}
 
@@ -33,24 +33,23 @@ let
     '';
   };
 
-  postageConnectionsFile = pkgs.writeTextFile {
-    name = "postage-connections.conf";
+  pgmanageConnectionsFile = pkgs.writeTextFile {
+    name = "pgmanage-connections.conf";
     text = concatStringsSep "\n"
       (mapAttrsToList (name : conn : "${name}: ${conn}") cfg.connections);
   };
 
-  postage = "postage";
-in {
+  pgmanage = "pgmanage";
 
-  options.services.postage = {
+  pgmanageOptions = {
     enable = mkEnableOption "PostgreSQL Administration for the web";
 
     package = mkOption {
       type = types.package;
-      default = pkgs.postage;
-      defaultText = "pkgs.postage";
+      default = pkgs.pgmanage;
+      defaultText = "pkgs.pgmanage";
       description = ''
-        The postage package to use.
+        The pgmanage package to use.
       '';
     };
 
@@ -62,14 +61,14 @@ in {
         "mini-server" = "hostaddr=127.0.0.1 port=5432 dbname=postgres sslmode=require";
       };
       description = ''
-        Postage requires at least one PostgreSQL server be defined.
+        pgmanage requires at least one PostgreSQL server be defined.
         </para><para>
         Detailed information about PostgreSQL connection strings is available at:
         <link xlink:href="http://www.postgresql.org/docs/current/static/libpq-connect.html"/>
         </para><para>
         Note that you should not specify your user name or password. That
         information will be entered on the login screen. If you specify a
-        username or password, it will be removed by Postage before attempting to
+        username or password, it will be removed by pgmanage before attempting to
         connect to a database.
       '';
     };
@@ -78,7 +77,7 @@ in {
       type = types.bool;
       default = false;
       description = ''
-        This tells Postage whether or not to allow anyone to use a custom
+        This tells pgmanage whether or not to allow anyone to use a custom
         connection from the login screen.
       '';
     };
@@ -87,7 +86,7 @@ in {
       type = types.int;
       default = 8080;
       description = ''
-        This tells Postage what port to listen on for browser requests.
+        This tells pgmanage what port to listen on for browser requests.
       '';
     };
 
@@ -95,7 +94,7 @@ in {
       type = types.bool;
       default = true;
       description = ''
-        This tells Postage whether or not to set the listening socket to local
+        This tells pgmanage whether or not to set the listening socket to local
         addresses only.
       '';
     };
@@ -104,10 +103,10 @@ in {
       type = types.bool;
       default = true;
       description = ''
-        This tells Postage whether or not to only allow super users to
+        This tells pgmanage whether or not to only allow super users to
         login. The recommended value is true and will restrict users who are not
         super users from logging in to any PostgreSQL instance through
-        Postage. Note that a connection will be made to PostgreSQL in order to
+        pgmanage. Note that a connection will be made to PostgreSQL in order to
         test if the user is a superuser.
       '';
     };
@@ -116,8 +115,8 @@ in {
       type = types.nullOr types.str;
       default = null;
       description = ''
-        This tells Postage to only allow users in a certain PostgreSQL group to
-        login to Postage. Note that a connection will be made to PostgreSQL in
+        This tells pgmanage to only allow users in a certain PostgreSQL group to
+        login to pgmanage. Note that a connection will be made to PostgreSQL in
         order to test if the user is a member of the login group.
       '';
     };
@@ -133,10 +132,10 @@ in {
 
     dataRoot = mkOption {
       type = types.str;
-      default = "/var/lib/postage";
+      default = "/var/lib/pgmanage";
       description = ''
-        This tells Postage where to put the SQL file history. All tabs are saved
-        to this location so that if you get disconnected from Postage you
+        This tells pgmanage where to put the SQL file history. All tabs are saved
+        to this location so that if you get disconnected from pgmanage you
         don't lose your work.
       '';
     };
@@ -156,15 +155,15 @@ in {
       });
       default = null;
       description = ''
-        These options tell Postage where the TLS Certificate and Key files
+        These options tell pgmanage where the TLS Certificate and Key files
         reside. If you use these options then you'll only be able to access
-        Postage through a secure TLS connection. These options are only
-        necessary if you wish to connect directly to Postage using a secure TLS
-        connection. As an alternative, you can set up Postage in a reverse proxy
+        pgmanage through a secure TLS connection. These options are only
+        necessary if you wish to connect directly to pgmanage using a secure TLS
+        connection. As an alternative, you can set up pgmanage in a reverse proxy
         configuration. This allows your web server to terminate the secure
-        connection and pass on the request to Postage. You can find help to set
+        connection and pass on the request to pgmanage. You can find help to set
         up this configuration in:
-        <link xlink:href="https://github.com/workflowproducts/postage/blob/master/INSTALL_NGINX.md"/>
+        <link xlink:href="https://github.com/pgManage/pgManage/blob/master/INSTALL_NGINX.md"/>
       '';
     };
 
@@ -177,29 +176,47 @@ in {
     };
   };
 
-  config = mkIf cfg.enable {
-    systemd.services.postage = {
-      description = "postage - PostgreSQL Administration for the web";
-      wants    = [ "postgresql.service" ];
-      after    = [ "postgresql.service" ];
-      wantedBy = [ "multi-user.target" ];
-      serviceConfig = {
-        User         = postage;
-        Group        = postage;
-        ExecStart    = "${pkgs.postage}/sbin/postage -c ${confFile}" +
-                       optionalString cfg.localOnly " --local-only=true";
-      };
-    };
-    users = {
-      users."${postage}" = {
-        name  = postage;
-        group = postage;
-        home  = cfg.dataRoot;
-        createHome = true;
+
+in {
+
+  options.services.pgmanage = pgmanageOptions;
+
+  # This is deprecated and should be removed for NixOS-18.03.
+  options.services.postage = pgmanageOptions;
+
+  config = mkMerge [
+    { assertions = [
+        { assertion = !config.services.postage.enable;
+          message =
+            "services.postage is deprecated in favour of pgmanage. " +
+            "They have the same options so just substitute postage for pgmanage." ;
+        }
+      ];
+    }
+    (mkIf cfg.enable {
+      systemd.services.pgmanage = {
+        description = "pgmanage - PostgreSQL Administration for the web";
+        wants    = [ "postgresql.service" ];
+        after    = [ "postgresql.service" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          User         = pgmanage;
+          Group        = pgmanage;
+          ExecStart    = "${pkgs.pgmanage}/sbin/pgmanage -c ${confFile}" +
+                         optionalString cfg.localOnly " --local-only=true";
+        };
       };
-      groups."${postage}" = {
-        name = postage;
+      users = {
+        users."${pgmanage}" = {
+          name  = pgmanage;
+          group = pgmanage;
+          home  = cfg.dataRoot;
+          createHome = true;
+        };
+        groups."${pgmanage}" = {
+          name = pgmanage;
+        };
       };
-    };
-  };
+    })
+  ];
 }
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..867c0ea6761c 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"
@@ -60,9 +60,11 @@ let
     manpage_directory    = "${pkgs.postfix}/share/man";
     html_directory       = "${pkgs.postfix}/share/postfix/doc/html";
     shlib_directory      = false;
-    relayhost            = if cfg.lookupMX || cfg.relayHost == ""
-                             then cfg.relayHost
-                             else "[${cfg.relayHost}]";
+    relayhost            = if cfg.relayHost == "" then "" else
+                             if cfg.lookupMX
+                             then "${cfg.relayHost}:${toString cfg.relayPort}"
+                             else "[${cfg.relayHost}]:${toString cfg.relayPort}";
+
     mail_spool_directory = "/var/spool/mail/";
     setgid_group         = setgidGroup;
   }
@@ -458,6 +460,14 @@ in
         ";
       };
 
+      relayPort = mkOption {
+        type = types.int;
+        default = 25;
+        description = "
+          SMTP port for relay mail relay.
+        ";
+      };
+
       lookupMX = mkOption {
         type = types.bool;
         default = false;
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..7b2b40e59232 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -572,7 +572,7 @@ in {
         rm -rf ${cfg.statePath}/config ${cfg.statePath}/shell/hooks
         mkdir -p ${cfg.statePath}/config
 
-        tr -dc A-Za-z0-9 < /dev/urandom | head -c 32 > ${cfg.statePath}/config/gitlab_shell_secret
+        ${pkgs.openssl}/bin/openssl rand -hex 32 > ${cfg.statePath}/config/gitlab_shell_secret
 
         # The uploads directory is hardcoded somewhere deep in rails. It is
         # symlinked in the gitlab package to /run/gitlab/uploads to make it
@@ -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
@@ -618,7 +619,7 @@ in {
         fi
 
         # enable required pg_trgm extension for gitlab
-        ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql gitlab -c "CREATE EXTENSION IF NOT EXISTS pg_trgm"
+        ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql ${cfg.databaseName} -c "CREATE EXTENSION IF NOT EXISTS pg_trgm"
         # Always do the db migrations just to be sure the database is up-to-date
         ${gitlab-rake}/bin/gitlab-rake db:migrate RAILS_ENV=production
 
@@ -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 -f ${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/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix
index 515864ec2e2d..41cadb4a6de0 100644
--- a/nixos/modules/services/misc/nixos-manual.nix
+++ b/nixos/modules/services/misc/nixos-manual.nix
@@ -135,8 +135,9 @@ in
         };
       };
 
-    services.mingetty.helpLine = mkIf cfg.showManual
-      "\nPress <Alt-F${toString cfg.ttyNumber}> for the NixOS manual.";
+      services.mingetty.helpLine = "\nRun `nixos-help` "
+        + lib.optionalString cfg.showManual "or press <Alt-F${toString cfg.ttyNumber}> "
+        + "for the NixOS manual.";
 
   };
 
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/plexpy.nix b/nixos/modules/services/misc/plexpy.nix
new file mode 100644
index 000000000000..df9f12581247
--- /dev/null
+++ b/nixos/modules/services/misc/plexpy.nix
@@ -0,0 +1,81 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.plexpy;
+in
+{
+  options = {
+    services.plexpy = {
+      enable = mkEnableOption "PlexPy Plex Monitor";
+
+      dataDir = mkOption {
+        type = types.str;
+        default = "/var/lib/plexpy";
+        description = "The directory where PlexPy stores its data files.";
+      };
+
+      configFile = mkOption {
+        type = types.str;
+        default = "/var/lib/plexpy/config.ini";
+        description = "The location of PlexPy's config file.";
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 8181;
+        description = "TCP port where PlexPy listens.";
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "plexpy";
+        description = "User account under which PlexPy runs.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "nogroup";
+        description = "Group under which PlexPy runs.";
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.plexpy;
+        defaultText = "pkgs.plexpy";
+        description = ''
+          The PlexPy package to use.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.plexpy = {
+      description = "PlexPy Plex Monitor";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      preStart = ''
+        test -d "${cfg.dataDir}" || {
+          echo "Creating initial PlexPy data directory in \"${cfg.dataDir}\"."
+          mkdir -p "${cfg.dataDir}"
+          chown ${cfg.user}:${cfg.group} "${cfg.dataDir}"
+        }
+     '';
+      serviceConfig = {
+        Type = "simple";
+        User = cfg.user;
+        Group = cfg.group;
+        PermissionsStartOnly = "true";
+        GuessMainPID = "false";
+        ExecStart = "${cfg.package}/bin/plexpy --datadir ${cfg.dataDir} --config ${cfg.configFile} --port ${toString cfg.port} --pidfile ${cfg.dataDir}/plexpy.pid --nolaunch";
+        Restart = "on-failure";
+      };
+    };
+
+    users.extraUsers = mkIf (cfg.user == "plexpy") {
+      plexpy = { group = cfg.group; uid = config.ids.uids.plexpy; };
+    };
+  };
+}
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/dd-agent/dd-agent.nix b/nixos/modules/services/monitoring/dd-agent/dd-agent.nix
index 8d3d4f2065ec..beaa2c01b298 100644
--- a/nixos/modules/services/monitoring/dd-agent/dd-agent.nix
+++ b/nixos/modules/services/monitoring/dd-agent/dd-agent.nix
@@ -23,7 +23,7 @@ let
     # proxy_password: password
 
     # tags: mytag0, mytag1
-    ${optionalString (cfg.tags != null ) "tags: ${concatStringsSep "," cfg.tags }"}
+    ${optionalString (cfg.tags != null ) "tags: ${concatStringsSep ", " cfg.tags }"}
 
     # collect_ec2_tags: no
     # recent_point_threshold: 30
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index 332a04634d06..4b1ad34b3a4e 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -7,10 +7,23 @@ 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}
     search_index: ${dataDir}/index
+    ${optionalString (!isNull config.time.timeZone) ''time_zone: ${config.time.timeZone}''}
     ${optionalString (cfg.api.finders != []) ''finders:''}
     ${concatMapStringsSep "\n" (f: "  - " + f.moduleName) cfg.api.finders}
     ${optionalString (cfg.api.functions != []) ''functions:''}
@@ -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 = {
@@ -445,7 +467,15 @@ in {
       ];
     })
 
-    (mkIf cfg.web.enable {
+    (mkIf cfg.web.enable (let
+      python27' = pkgs.python27.override {
+        packageOverrides = self: super: {
+          django = self.django_1_8;
+          django_tagging = self.django_tagging_0_4_3;
+        };
+      };
+      pythonPackages = python27'.pkgs;
+    in {
       systemd.services.graphiteWeb = {
         description = "Graphite Web Interface";
         wantedBy = [ "multi-user.target" ];
@@ -455,14 +485,18 @@ in {
           PYTHONPATH = let
               penv = pkgs.python.buildEnv.override {
                 extraLibs = [
-                  pkgs.python27Packages.graphite_web
-                  pkgs.python27Packages.pysqlite
+                  pythonPackages.graphite_web
+                  pythonPackages.pysqlite
                 ];
               };
               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 +504,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,21 +516,25 @@ 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 "${pythonPackages.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 "${pythonPackages.graphite_web}" "${dataDir}/current_graphite_web"
+          fi
         '';
       };
 
-      environment.systemPackages = [ pkgs.python27Packages.graphite_web ];
-    })
+      environment.systemPackages = [ pythonPackages.graphite_web ];
+    }))
 
     (mkIf cfg.api.enable {
       systemd.services.graphiteApi = {
@@ -506,7 +544,7 @@ in {
         environment = {
           PYTHONPATH = let
               aenv = pkgs.python.buildEnv.override {
-                extraLibs = [ cfg.api.package pkgs.cairo ] ++ cfg.api.finders;
+                extraLibs = [ cfg.api.package pkgs.cairo pkgs.pythonPackages.cffi ] ++ cfg.api.finders;
               };
             in "${aenv}/${pkgs.python.sitePackages}";
           GRAPHITE_API_CONFIG = graphiteApiConfig;
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..bad4389ce799 100644
--- a/nixos/modules/services/monitoring/prometheus/node-exporter.nix
+++ b/nixos/modules/services/monitoring/prometheus/node-exporter.nix
@@ -4,9 +4,6 @@ with lib;
 
 let
   cfg = config.services.prometheus.nodeExporter;
-  cmdlineArgs = cfg.extraFlags ++ [
-    "-web.listen-address=${cfg.listenAddress}"
-  ];
 in {
   options = {
     services.prometheus.nodeExporter = {
@@ -33,7 +30,16 @@ 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.
+        '';
+      };
+
+      disabledCollectors = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = ''[ "timex" ]'';
+        description = ''
+          Collectors to disable which are enabled by default.
         '';
       };
 
@@ -64,14 +70,14 @@ 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} \
+          ${concatMapStringsSep " " (x: "--collector." + x) cfg.enabledCollectors} \
+          ${concatMapStringsSep " " (x: "--no-collector." + x) cfg.disabledCollectors} \
+          --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
           ${concatStringsSep " \\\n  " cfg.extraFlags}
       '';
       serviceConfig = {
         User = "nobody";
-        Restart  = "always";
+        Restart = "always";
         PrivateTmp = true;
         WorkingDirectory = /tmp;
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
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/babeld.nix b/nixos/modules/services/networking/babeld.nix
new file mode 100644
index 000000000000..dd76bac9df76
--- /dev/null
+++ b/nixos/modules/services/networking/babeld.nix
@@ -0,0 +1,98 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.babeld;
+
+  paramsString = params:
+    concatMapStringsSep "" (name: "${name} ${boolToString (getAttr name params)}")
+                   (attrNames params);
+
+  interfaceConfig = name:
+    let
+      interface = getAttr name cfg.interfaces;
+    in
+    "interface ${name} ${paramsString interface}\n";
+
+  configFile = with cfg; pkgs.writeText "babeld.conf" (
+    (optionalString (cfg.interfaceDefaults != null) ''
+      default ${paramsString cfg.interfaceDefaults}
+    '')
+    + (concatMapStrings interfaceConfig (attrNames cfg.interfaces))
+    + extraConfig);
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.babeld = {
+
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to run the babeld network routing daemon.
+        '';
+      };
+
+      interfaceDefaults = mkOption {
+        default = null;
+        description = ''
+          A set describing default parameters for babeld interfaces.
+          See <citerefentry><refentrytitle>babeld</refentrytitle><manvolnum>8</manvolnum></citerefentry> for options.
+        '';
+        type = types.nullOr (types.attrsOf types.unspecified);
+        example =
+          {
+            wired = true;
+            "split-horizon" = true;
+          };
+      };
+
+      interfaces = mkOption {
+        default = {};
+        description = ''
+          A set describing babeld interfaces.
+          See <citerefentry><refentrytitle>babeld</refentrytitle><manvolnum>8</manvolnum></citerefentry> for options.
+        '';
+        type = types.attrsOf (types.attrsOf types.unspecified);
+        example =
+          { enp0s2 =
+            { wired = true;
+              "hello-interval" = 5;
+              "split-horizon" = "auto";
+            };
+          };
+      };
+
+      extraConfig = mkOption {
+        default = "";
+        description = ''
+          Options that will be copied to babeld.conf.
+          See <citerefentry><refentrytitle>babeld</refentrytitle><manvolnum>8</manvolnum></citerefentry> for details.
+        '';
+      };
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.babeld.enable {
+
+    systemd.services.babeld = {
+      description = "Babel routing daemon";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig.ExecStart = "${pkgs.babeld}/bin/babeld -c ${configFile}";
+    };
+
+  };
+
+}
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/dnschain.nix b/nixos/modules/services/networking/dnschain.nix
index ab7bbb15ad4f..ee1cd3600039 100644
--- a/nixos/modules/services/networking/dnschain.nix
+++ b/nixos/modules/services/networking/dnschain.nix
@@ -158,7 +158,7 @@ in
       serviceConfig = {
         User = "dnschain";
         Restart = "on-failure";
-        ExecStart = "${pkgs.dnschain}/bin/dnschain";
+        ExecStart = "${pkgs.nodePackages.dnschain}/bin/dnschain";
       };
 
       preStart = ''
diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix
index fcf5aa5f175b..91a3e54474ac 100644
--- a/nixos/modules/services/networking/dnsmasq.nix
+++ b/nixos/modules/services/networking/dnsmasq.nix
@@ -55,6 +55,14 @@ in
         '';
       };
 
+      alwaysKeepRunning = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If enabled, systemd will always respawn dnsmasq even if shut down manually. The default, disabled, will only restart it on error.
+        '';
+      };
+
       extraConfig = mkOption {
         type = types.lines;
         default = "";
@@ -101,10 +109,12 @@ in
           BusName = "uk.org.thekelleys.dnsmasq";
           ExecStart = "${dnsmasq}/bin/dnsmasq -k --enable-dbus --user=dnsmasq -C ${dnsmasqConf}";
           ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+          PrivateTmp = true;
+          ProtectSystem = true;
+          ProtectHome = true;
+          Restart = if cfg.alwaysKeepRunning then "always" else "on-failure";
         };
         restartTriggers = [ config.environment.etc.hosts.source ];
     };
-
   };
-
 }
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..a149f16a84cb 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 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/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index e03309c87299..6bdae32f72bb 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -32,6 +32,11 @@ let
     ipv6.ip6-privacy=2
     ethernet.cloned-mac-address=${cfg.ethernet.macAddress}
     wifi.cloned-mac-address=${cfg.wifi.macAddress}
+    ${optionalString (cfg.wifi.powersave != null)
+      ''wifi.powersave=${if cfg.wifi.powersave then "3" else "2"}''}
+
+    [device]
+    wifi.scan-rand-mac-address=${if cfg.wifi.scanRandMacAddress then "yes" else "no"}
   '';
 
   /*
@@ -179,7 +184,27 @@ in {
       };
 
       ethernet.macAddress = macAddressOpt;
-      wifi.macAddress = macAddressOpt;
+
+      wifi = {
+        macAddress = macAddressOpt;
+
+        powersave = mkOption {
+          type = types.nullOr types.bool;
+          default = null;
+          description = ''
+            Whether to enable Wi-Fi power saving.
+          '';
+        };
+
+        scanRandMacAddress = mkOption {
+          type = types.bool;
+          default = true;
+          description = ''
+            Whether to enable MAC address randomization of a Wi-Fi device
+            during scanning.
+          '';
+        };
+      };
 
       useDnsmasq = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/networking/strongswan.nix b/nixos/modules/services/networking/strongswan.nix
index b0eb0460b9ba..3a3f64221c42 100644
--- a/nixos/modules/services/networking/strongswan.nix
+++ b/nixos/modules/services/networking/strongswan.nix
@@ -32,8 +32,10 @@ let
       ${caConf}
     '';
 
-  strongswanConf = {setup, connections, ca, secrets}: toFile "strongswan.conf" ''
+  strongswanConf = {setup, connections, ca, secrets, managePlugins, enabledPlugins}: toFile "strongswan.conf" ''
     charon {
+      ${if managePlugins then "load_modular = no" else ""}
+      ${if managePlugins then ("load = " + (concatStringsSep " " enabledPlugins)) else ""}
       plugins {
         stroke {
           secrets_file = ${ipsecSecrets secrets}
@@ -112,6 +114,25 @@ in
         file.
       '';
     };
+
+    managePlugins = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        If set to true, this option will disable automatic plugin loading and
+        then tell strongSwan to enable the plugins specified in the
+        <option>enabledPlugins</option> option.
+      '';
+    };
+
+    enabledPlugins = mkOption {
+      type = types.listOf types.str;
+      default = [];
+      description = ''
+        A list of additional plugins to enable if
+        <option>managePlugins</option> is true.
+      '';
+    };
   };
 
   config = with cfg; mkIf enable {
@@ -122,7 +143,7 @@ in
       wants = [ "keys.target" ];
       after = [ "network-online.target" "keys.target" ];
       environment = {
-        STRONGSWAN_CONF = strongswanConf { inherit setup connections ca secrets; };
+        STRONGSWAN_CONF = strongswanConf { inherit setup connections ca secrets managePlugins enabledPlugins; };
       };
       serviceConfig = {
         ExecStart  = "${pkgs.strongswan}/sbin/ipsec start --nofork";
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index f3a04d97c98e..545ee327d596 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -8,9 +8,9 @@ let
 
   stateDir = "/var/lib/unbound";
 
-  access = concatMapStrings (x: "  access-control: ${x} allow\n") cfg.allowedAccess;
+  access = concatMapStringsSep "\n  " (x: "access-control: ${x} allow") cfg.allowedAccess;
 
-  interfaces = concatMapStrings (x: "  interface: ${x}\n") cfg.interfaces;
+  interfaces = concatMapStringsSep "\n  " (x: "interface: ${x}") cfg.interfaces;
 
   isLocalAddress = x: substring 0 3 x == "::1" || substring 0 9 x == "127.0.0.1";
 
@@ -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/wireguard.nix b/nixos/modules/services/networking/wireguard.nix
index eb08e7f90c0d..24accd41511c 100644
--- a/nixos/modules/services/networking/wireguard.nix
+++ b/nixos/modules/services/networking/wireguard.nix
@@ -195,6 +195,7 @@ let
         description = "WireGuard Tunnel - ${name}";
         after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
+        environment.DEVICE = name;
 
         serviceConfig = {
           Type = "oneshot";
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..be74a2b1955b 100644
--- a/nixos/modules/services/web-apps/mattermost.nix
+++ b/nixos/modules/services/web-apps/mattermost.nix
@@ -173,7 +173,7 @@ in
 
         preStart = ''
           mkdir -p ${cfg.statePath}/{data,config,logs}
-          ln -sf ${pkgs.mattermost}/{bin,fonts,i18n,templates,webapp} ${cfg.statePath}
+          ln -sf ${pkgs.mattermost}/{bin,fonts,i18n,templates,client} ${cfg.statePath}
         '' + lib.optionalString (!cfg.mutableConfig) ''
           ln -sf ${mattermostConfJSON} ${cfg.statePath}/config/config.json
         '' + lib.optionalString cfg.mutableConfig ''
@@ -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/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 1c3c7835d961..f9f2511f45dc 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -676,6 +676,7 @@ in
       ''
         ; Needed for PHP's mail() function.
         sendmail_path = sendmail -t -i
+      '' + optionalString (!isNull config.time.timeZone) ''
 
         ; Apparently PHP doesn't use $TZ.
         date.timezone = "${config.time.timeZone}"
diff --git a/nixos/modules/services/web-servers/apache-httpd/wordpress.nix b/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
index c6f4bcd0f666..1c654667dfc7 100644
--- a/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
@@ -13,6 +13,7 @@ let
     define('DB_HOST',     '${config.dbHost}');
     define('DB_CHARSET',  'utf8');
     $table_prefix  = '${config.tablePrefix}';
+    define('AUTOMATIC_UPDATER_DISABLED', true);
     ${config.extraConfig}
     if ( !defined('ABSPATH') )
     	define('ABSPATH', dirname(__FILE__) . '/');
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..11cbcac6fa85 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 = ''
@@ -193,7 +221,7 @@ in {
     };
 
     extraOptions = mkOption {
-      type = types.str;
+      type = types.lines;
       default = "";
       example = ''
         unredir-if-possible = true;
diff --git a/nixos/modules/services/x11/desktop-managers/lxqt.nix b/nixos/modules/services/x11/desktop-managers/lxqt.nix
index 89ad2882363d..fb907618d35b 100644
--- a/nixos/modules/services/x11/desktop-managers/lxqt.nix
+++ b/nixos/modules/services/x11/desktop-managers/lxqt.nix
@@ -41,7 +41,7 @@ in
       name = "lxqt";
       bgSupport = true;
       start = ''
-        exec ${pkgs.lxqt.lxqt-common}/bin/startlxqt
+        exec ${pkgs.lxqt.lxqt-session}/bin/startlxqt
       '';
     };
 
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..7f54bb182fe9 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,12 @@ in
       ];
 
       services.xserver.displayManager.sddm = {
-        theme = "breeze";
+        theme = mkDefault "breeze";
+      };
+
+      boot.plymouth = {
+        theme = mkDefault "breeze";
+        themePackages = mkDefault [ pkgs.breeze-plymouth ];
       };
 
       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/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index 83c5c95dae7e..e83f26516f5f 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -125,6 +125,7 @@ in
       "getty@tty1.service"
     ];
 
+    systemd.services."getty@tty1".enable = false;
     systemd.services.display-manager.conflicts = [ "getty@tty1.service" ];
     systemd.services.display-manager.serviceConfig = {
       # Restart = "always"; - already defined in xserver.nix
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/plymouth.nix b/nixos/modules/system/boot/plymouth.nix
index d45b1686c1ea..4b0c498424b5 100644
--- a/nixos/modules/system/boot/plymouth.nix
+++ b/nixos/modules/system/boot/plymouth.nix
@@ -72,7 +72,7 @@ in
     environment.systemPackages = [ plymouth ];
 
     environment.etc."plymouth/plymouthd.conf".source = configFile;
-    environment.etc."plymouth/plymouthd.defaults".source = "${plymouth}/share/plymouth/plymouth.defaults";
+    environment.etc."plymouth/plymouthd.defaults".source = "${plymouth}/share/plymouth/plymouthd.defaults";
     environment.etc."plymouth/logo.png".source = cfg.logo;
     environment.etc."plymouth/themes".source = "${themesEnv}/share/plymouth/themes";
     # XXX: Needed because we supply a different set of plugins in initrd.
@@ -97,12 +97,26 @@ in
       moduleName="$(sed -n 's,ModuleName *= *,,p' ${themesEnv}/share/plymouth/themes/${cfg.theme}/${cfg.theme}.plymouth)"
 
       mkdir -p $out/lib/plymouth/renderers
-      cp ${plymouth}/lib/plymouth/{text,details,$moduleName}.so $out/lib/plymouth
+      # module might come from a theme
+      cp ${themesEnv}/lib/plymouth/{text,details,$moduleName}.so $out/lib/plymouth
       cp ${plymouth}/lib/plymouth/renderers/{drm,frame-buffer}.so $out/lib/plymouth/renderers
 
       mkdir -p $out/share/plymouth/themes
       cp ${plymouth}/share/plymouth/plymouthd.defaults $out/share/plymouth
-      cp -r ${themesEnv}/share/plymouth/themes/{text,details,${cfg.theme}} $out/share/plymouth/themes
+
+      # copy themes into working directory for patching
+      mkdir themes
+      # use -L to copy the directories proper, not the symlinks to them
+      cp -r -L ${themesEnv}/share/plymouth/themes/{text,details,${cfg.theme}} themes
+
+      # patch out any attempted references to the theme or plymouth's themes directory
+      chmod -R +w themes
+      find themes -type f | while read file
+      do
+        sed -i "s,/nix/.*/share/plymouth/themes,$out/share/plymouth/themes,g" $file
+      done
+
+      cp -r themes/* $out/share/plymouth/themes
       cp ${cfg.logo} $out/share/plymouth/logo.png
     '';
 
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.nix b/nixos/modules/tasks/filesystems.nix
index 6ceb36714b28..b3690fad1a6a 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -115,11 +115,18 @@ let
 
     };
 
-    config = {
+    config = let
+      defaultFormatOptions =
+        # -F needed to allow bare block device without partitions
+        if (builtins.substring 0 3 config.fsType) == "ext" then "-F"
+        # -q needed for non-interactive operations
+        else if config.fsType == "jfs" then "-q"
+        # (same here)
+        else if config.fsType == "reiserfs" then "-q"
+        else null;
+    in {
       options = mkIf config.autoResize [ "x-nixos.autoresize" ];
-
-      # -F needed to allow bare block device without partitions
-      formatOptions = mkIf ((builtins.substring 0 3 config.fsType) == "ext") (mkDefault "-F");
+      formatOptions = mkIf (defaultFormatOptions != null) (mkDefault defaultFormatOptions);
     };
 
   };
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/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix
index e92c9bc27def..1f424f84c6e0 100644
--- a/nixos/modules/tasks/network-interfaces-scripted.nix
+++ b/nixos/modules/tasks/network-interfaces-scripted.nix
@@ -93,6 +93,7 @@ let
             after = [ "network-pre.target" "systemd-udevd.service" "systemd-sysctl.service" ];
             before = [ "network.target" "shutdown.target" ];
             wants = [ "network.target" ];
+            partOf = map (i: "network-addresses-${i.name}.service") interfaces;
             conflicts = [ "shutdown.target" ];
             wantedBy = [ "multi-user.target" ] ++ optional hasDefaultGatewaySet "network-online.target";
 
@@ -171,8 +172,6 @@ let
               "network-link-${i.name}.service"
               "network.target"
             ];
-            # propagate stop and reload from network-setup
-            partOf = [ "network-setup.service" ];
             # order before network-setup because the routes that are configured
             # there may need ip addresses configured
             before = [ "network-setup.service" ];
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
 
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index 82dfc1c9f1ce..e68bfd860601 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -537,7 +537,7 @@ in
               type = types.bool;
               default = false;
               description = ''
-                Wether the container is automatically started at boot-time.
+                Whether the container is automatically started at boot-time.
               '';
             };
 
@@ -596,6 +596,8 @@ in
                   { config, pkgs, ... }:
                   { services.postgresql.enable = true;
                     services.postgresql.package = pkgs.postgresql96;
+                    
+                    system.stateVersion = "17.03";
                   };
               };
           }
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index a17e2c9ca471..3c89ca68113b 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -92,7 +92,7 @@ let
             -drive index=0,id=drive1,file=$NIX_DISK_IMAGE,if=${cfg.qemu.diskInterface},cache=writeback,werror=report \
             -kernel ${config.system.build.toplevel}/kernel \
             -initrd ${config.system.build.toplevel}/initrd \
-            -append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.toplevel}/init regInfo=${regInfo} ${kernelConsole} $QEMU_KERNEL_PARAMS" \
+            -append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.toplevel}/init regInfo=${regInfo}/registration ${kernelConsole} $QEMU_KERNEL_PARAMS" \
           ''} \
           $extraDisks \
           ${qemuGraphics} \
@@ -102,15 +102,7 @@ let
     '';
 
 
-  regInfo = pkgs.runCommand "reginfo"
-    { exportReferencesGraph =
-        map (x: [("closure-" + baseNameOf x) x]) config.virtualisation.pathsInNixDB;
-      buildInputs = [ pkgs.perl ];
-      preferLocalBuild = true;
-    }
-    ''
-      printRegistration=1 perl ${pkgs.pathsFromGraph} closure-* > $out
-    '';
+  regInfo = pkgs.closureInfo { rootPaths = config.virtualisation.pathsInNixDB; };
 
 
   # Generate a hard disk image containing a /boot partition and GRUB