about summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
authorVladimír Čunát <vcunat@gmail.com>2016-03-14 11:27:15 +0100
committerVladimír Čunát <vcunat@gmail.com>2016-03-14 11:27:15 +0100
commitd6b46ecb30f1a18a4b08ed29f03d2b5a6941aec4 (patch)
treea6b6cc322e9a615bf0e8b49de927d4edfc214554 /nixos/modules
parentab8a691d059b364c435a1871ae2ef70a578685d8 (diff)
parent55b6c1792619085dd8aacf46b94e2f33303dd58e (diff)
downloadnixlib-d6b46ecb30f1a18a4b08ed29f03d2b5a6941aec4.tar
nixlib-d6b46ecb30f1a18a4b08ed29f03d2b5a6941aec4.tar.gz
nixlib-d6b46ecb30f1a18a4b08ed29f03d2b5a6941aec4.tar.bz2
nixlib-d6b46ecb30f1a18a4b08ed29f03d2b5a6941aec4.tar.lz
nixlib-d6b46ecb30f1a18a4b08ed29f03d2b5a6941aec4.tar.xz
nixlib-d6b46ecb30f1a18a4b08ed29f03d2b5a6941aec4.tar.zst
nixlib-d6b46ecb30f1a18a4b08ed29f03d2b5a6941aec4.zip
Merge branch 'closure-size' into p/default-outputs
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/config/fonts/fontconfig.nix17
-rw-r--r--nixos/modules/config/gtk-exe-env.nix41
-rw-r--r--nixos/modules/config/networking.nix16
-rw-r--r--nixos/modules/config/qt-plugin-env.nix37
-rw-r--r--nixos/modules/config/vpnc.nix20
-rw-r--r--nixos/modules/config/zram.nix6
-rw-r--r--nixos/modules/hardware/all-firmware.nix2
-rw-r--r--nixos/modules/hardware/network/intel-2200bg.nix2
-rw-r--r--nixos/modules/hardware/opengl.nix39
-rw-r--r--nixos/modules/hardware/video/webcam/facetimehd.nix45
-rw-r--r--nixos/modules/i18n/inputMethod/default.nix29
-rw-r--r--nixos/modules/i18n/inputMethod/fcitx.nix44
-rw-r--r--nixos/modules/i18n/inputMethod/ibus.nix55
-rw-r--r--nixos/modules/i18n/inputMethod/nabi.nix16
-rw-r--r--nixos/modules/i18n/inputMethod/uim.nix37
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix78
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical-kde-new-kernel.nix (renamed from nixos/modules/installer/cd-dvd/installation-cd-graphical-new-kernel.nix)2
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix (renamed from nixos/modules/installer/cd-dvd/installation-cd-graphical.nix)0
-rw-r--r--nixos/modules/installer/cd-dvd/iso-image.nix8
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image.nix10
-rw-r--r--nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix3
-rw-r--r--nixos/modules/installer/cd-dvd/system-tarball.nix2
-rw-r--r--nixos/modules/installer/tools/auto-upgrade.nix2
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl21
-rw-r--r--nixos/modules/installer/tools/nixos-install.sh5
-rw-r--r--nixos/modules/installer/tools/nixos-rebuild.sh188
-rw-r--r--nixos/modules/misc/ids.nix9
-rw-r--r--nixos/modules/misc/locate.nix129
-rw-r--r--nixos/modules/misc/nixos.nix82
-rw-r--r--nixos/modules/misc/nixos.xml84
-rw-r--r--nixos/modules/module-list.nix31
-rw-r--r--nixos/modules/profiles/base.nix1
-rw-r--r--nixos/modules/profiles/qemu-guest.nix2
-rw-r--r--nixos/modules/programs/bash/bash.nix2
-rw-r--r--nixos/modules/programs/freetds.nix16
-rw-r--r--nixos/modules/programs/ibus.nix51
-rw-r--r--nixos/modules/programs/ssh.nix11
-rw-r--r--nixos/modules/programs/uim.nix31
-rw-r--r--nixos/modules/programs/venus.nix4
-rw-r--r--nixos/modules/programs/xfs_quota.nix4
-rw-r--r--nixos/modules/rename.nix9
-rw-r--r--nixos/modules/security/acme.nix4
-rw-r--r--nixos/modules/security/apparmor-suid.nix4
-rw-r--r--nixos/modules/security/audit.nix4
-rw-r--r--nixos/modules/security/ca.nix35
-rw-r--r--nixos/modules/security/oath.nix50
-rw-r--r--nixos/modules/security/pam.nix17
-rw-r--r--nixos/modules/services/amqp/activemq/default.nix3
-rw-r--r--nixos/modules/services/computing/slurm/slurm.nix1
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/default.nix17
-rw-r--r--nixos/modules/services/databases/postgresql.nix38
-rw-r--r--nixos/modules/services/hardware/acpid.nix174
-rw-r--r--nixos/modules/services/hardware/bluetooth.nix60
-rw-r--r--nixos/modules/services/hardware/sane.nix17
-rw-r--r--nixos/modules/services/hardware/udev.nix93
-rw-r--r--nixos/modules/services/mail/dovecot.nix105
-rw-r--r--nixos/modules/services/mail/dspam.nix11
-rw-r--r--nixos/modules/services/mail/opendkim.nix9
-rw-r--r--nixos/modules/services/mail/opensmtpd.nix21
-rw-r--r--nixos/modules/services/mail/postfix.nix67
-rw-r--r--nixos/modules/services/mail/postsrsd.nix6
-rw-r--r--nixos/modules/services/misc/bepasty.nix8
-rw-r--r--nixos/modules/services/misc/cfdyndns.nix70
-rw-r--r--nixos/modules/services/misc/defaultUnicornConfig.rb1
-rw-r--r--nixos/modules/services/misc/gammu-smsd.nix253
-rw-r--r--nixos/modules/services/misc/gitit.nix1
-rw-r--r--nixos/modules/services/misc/gitlab.nix390
-rw-r--r--nixos/modules/services/misc/gitlab.xml103
-rw-r--r--nixos/modules/services/misc/ihaskell.nix2
-rw-r--r--nixos/modules/services/misc/matrix-synapse.nix1
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix4
-rw-r--r--nixos/modules/services/misc/nixos-manual.nix38
-rw-r--r--nixos/modules/services/misc/octoprint.nix120
-rw-r--r--nixos/modules/services/misc/plex.nix1
-rw-r--r--nixos/modules/services/misc/spice-vdagentd.nix30
-rw-r--r--nixos/modules/services/misc/subsonic.nix4
-rw-r--r--nixos/modules/services/misc/sundtek.nix2
-rw-r--r--nixos/modules/services/monitoring/bosun.nix18
-rw-r--r--nixos/modules/services/monitoring/collectd.nix11
-rw-r--r--nixos/modules/services/monitoring/dd-agent.nix1
-rw-r--r--nixos/modules/services/monitoring/grafana.nix4
-rw-r--r--nixos/modules/services/monitoring/graphite.nix2
-rw-r--r--nixos/modules/services/monitoring/hdaps.nix22
-rw-r--r--nixos/modules/services/network-filesystems/netatalk.nix150
-rw-r--r--nixos/modules/services/network-filesystems/samba.nix20
-rw-r--r--nixos/modules/services/networking/bird.nix4
-rw-r--r--nixos/modules/services/networking/connman.nix6
-rw-r--r--nixos/modules/services/networking/consul.nix1
-rw-r--r--nixos/modules/services/networking/ddclient.nix1
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.nix5
-rw-r--r--nixos/modules/services/networking/ejabberd.nix1
-rw-r--r--nixos/modules/services/networking/gale.nix12
-rw-r--r--nixos/modules/services/networking/gateone.nix4
-rw-r--r--nixos/modules/services/networking/i2pd.nix300
-rw-r--r--nixos/modules/services/networking/ifplugd.nix82
-rw-r--r--nixos/modules/services/networking/kippo.nix6
-rw-r--r--nixos/modules/services/networking/libreswan.nix126
-rw-r--r--nixos/modules/services/networking/networkmanager.nix8
-rw-r--r--nixos/modules/services/networking/nix-serve.nix2
-rw-r--r--nixos/modules/services/networking/nntp-proxy.nix235
-rw-r--r--nixos/modules/services/networking/nsd.nix874
-rw-r--r--nixos/modules/services/networking/pdnsd.nix93
-rw-r--r--nixos/modules/services/networking/softether.nix31
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix17
-rw-r--r--nixos/modules/services/networking/syncthing.nix21
-rw-r--r--nixos/modules/services/networking/tinc.nix12
-rw-r--r--nixos/modules/services/networking/tlsdated.nix1
-rw-r--r--nixos/modules/services/networking/unbound.nix46
-rw-r--r--nixos/modules/services/networking/unifi.nix2
-rw-r--r--nixos/modules/services/networking/wpa_supplicant.nix38
-rw-r--r--nixos/modules/services/networking/zerotierone.nix7
-rw-r--r--nixos/modules/services/printing/cupsd.nix196
-rw-r--r--nixos/modules/services/search/elasticsearch.nix17
-rw-r--r--nixos/modules/services/search/kibana.nix65
-rw-r--r--nixos/modules/services/security/clamav.nix11
-rw-r--r--nixos/modules/services/security/fail2ban.nix28
-rw-r--r--nixos/modules/services/security/haka.nix157
-rw-r--r--nixos/modules/services/system/dbus.nix2
-rw-r--r--nixos/modules/services/system/uptimed.nix71
-rw-r--r--nixos/modules/services/torrent/transmission.nix2
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix5
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/mediawiki.nix4
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/moodle.nix10
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/owncloud.nix3
-rw-r--r--nixos/modules/services/web-servers/phpfpm.nix30
-rw-r--r--nixos/modules/services/web-servers/uwsgi.nix125
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix8
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix59
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde4.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix22
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix41
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix6
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix11
-rw-r--r--nixos/modules/services/x11/hardware/libinput.nix230
-rw-r--r--nixos/modules/services/x11/hardware/synaptics.nix29
-rw-r--r--nixos/modules/services/x11/window-managers/bspwm.nix33
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix1
-rw-r--r--nixos/modules/services/x11/window-managers/exwm.nix55
-rw-r--r--nixos/modules/services/x11/window-managers/i3.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/metacity.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/openbox.nix2
-rw-r--r--nixos/modules/services/x11/xserver.nix26
-rw-r--r--nixos/modules/system/activation/activation-script.nix47
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl16
-rw-r--r--nixos/modules/system/activation/top-level.nix11
-rw-r--r--nixos/modules/system/boot/initrd-network.nix178
-rw-r--r--nixos/modules/system/boot/initrd-ssh.nix124
-rw-r--r--nixos/modules/system/boot/kernel.nix3
-rw-r--r--nixos/modules/system/boot/loader/init-script/init-script-builder.sh9
-rw-r--r--nixos/modules/system/boot/luksroot.nix4
-rw-r--r--nixos/modules/system/boot/networkd.nix31
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh29
-rw-r--r--nixos/modules/system/boot/stage-1.nix20
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh20
-rw-r--r--nixos/modules/system/boot/systemd.nix8
-rw-r--r--nixos/modules/tasks/filesystems.nix18
-rw-r--r--nixos/modules/tasks/kbd.nix51
-rw-r--r--nixos/modules/tasks/network-interfaces-scripted.nix7
-rw-r--r--nixos/modules/tasks/network-interfaces.nix2
-rw-r--r--nixos/modules/testing/test-instrumentation.nix13
-rw-r--r--nixos/modules/virtualisation/amazon-image.nix29
-rw-r--r--nixos/modules/virtualisation/amazon-init.nix23
-rw-r--r--nixos/modules/virtualisation/azure-agent.nix15
-rw-r--r--nixos/modules/virtualisation/azure-config-user.nix12
-rw-r--r--nixos/modules/virtualisation/azure-image.nix6
-rw-r--r--nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch14
-rw-r--r--nixos/modules/virtualisation/container-config.nix3
-rw-r--r--nixos/modules/virtualisation/ec2-data.nix56
-rwxr-xr-x[-rw-r--r--]nixos/modules/virtualisation/nixos-container.pl2
-rw-r--r--nixos/modules/virtualisation/nova.nix2
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix13
-rw-r--r--nixos/modules/virtualisation/rkt.nix2
173 files changed, 4857 insertions, 2290 deletions
diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix
index c027796d5476..1eaebe4b2bbd 100644
--- a/nixos/modules/config/fonts/fontconfig.nix
+++ b/nixos/modules/config/fonts/fontconfig.nix
@@ -129,6 +129,14 @@ with lib;
 
         };
 
+        cache32Bit = mkOption {
+          default = false;
+          type = types.bool;
+          description = ''
+            Generate system fonts cache for 32-bit applications.
+          '';
+        };
+
       };
 
     };
@@ -231,12 +239,19 @@ with lib;
         "${pkgs.fontconfig.out}/etc/fonts/fonts.conf";
 
       environment.etc."fonts/${pkgs.fontconfig.configVersion}/conf.d/00-nixos.conf".text =
-        ''
+        let
+          cache = fontconfig: pkgs.makeFontsCache { inherit fontconfig; fontDirectories = config.fonts.fonts; };
+        in ''
           <?xml version='1.0'?>
           <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
           <fontconfig>
             <!-- Font directories -->
             ${concatStringsSep "\n" (map (font: "<dir>${font}</dir>") config.fonts.fonts)}
+            <!-- Pre-generated font caches -->
+            <cachedir>${cache pkgs.fontconfig}</cachedir>
+            ${optionalString (pkgs.stdenv.isx86_64 && config.fonts.fontconfig.cache32Bit) ''
+              <cachedir>${cache pkgs.pkgsi686Linux.fontconfig}</cachedir>
+            ''}
           </fontconfig>
         '';
 
diff --git a/nixos/modules/config/gtk-exe-env.nix b/nixos/modules/config/gtk-exe-env.nix
deleted file mode 100644
index b565072e3a71..000000000000
--- a/nixos/modules/config/gtk-exe-env.nix
+++ /dev/null
@@ -1,41 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-{
-  imports = [
-  ];
-
-  options = {
-    gtkPlugins = lib.mkOption {
-      type = lib.types.listOf lib.types.path;
-      default = [];
-      description = ''
-        Plugin packages for GTK+ such as input methods.
-      '';
-    };
-  };
-
-  config = {
-    environment.variables = if builtins.length config.gtkPlugins > 0
-      then
-        let
-          paths = [ pkgs.gtk2 pkgs.gtk3 ] ++ config.gtkPlugins;
-          env = pkgs.buildEnv {
-            name = "gtk-exe-env";
-
-            inherit paths;
-
-            postBuild = lib.concatStringsSep "\n"
-              (map (d: d.gtkExeEnvPostBuild or "") paths);
-
-            ignoreCollisions = true;
-          };
-        in {
-          GTK_EXE_PREFIX = builtins.toString env;
-          GTK_PATH = [
-            "${env}/lib/gtk-2.0"
-            "${env}/lib/gtk-3.0"
-          ];
-        }
-      else {};
-  };
-}
diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix
index cbda34348930..0c4f4cbfa5c6 100644
--- a/nixos/modules/config/networking.nix
+++ b/nixos/modules/config/networking.nix
@@ -39,6 +39,17 @@ in
       '';
     };
 
+    networking.dnsExtensionMechanism = lib.mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable the <code>edns0</code> option in <filename>resolv.conf</filename>. With
+        that option set, <code>glibc</code> supports use of the extension mechanisms for
+        DNS (EDNS) specified in RFC 2671. The most popular user of that feature is DNSSEC,
+        which does not work without it.
+      '';
+    };
+
     networking.extraResolvconfConf = lib.mkOption {
       type = types.lines;
       default = "";
@@ -162,7 +173,10 @@ in
               libc_restart='${pkgs.systemd}/bin/systemctl try-restart --no-block nscd.service 2> /dev/null'
             '' + optionalString cfg.dnsSingleRequest ''
               # only send one DNS request at a time
-              resolv_conf_options='single-request'
+              resolv_conf_options+=' single-request'
+            '' + optionalString cfg.dnsExtensionMechanism ''
+              # enable extension mechanisms for DNS
+              resolv_conf_options+=' edns0'
             '' + optionalString hasLocalResolver ''
               # This hosts runs a full-blown DNS resolver.
               name_servers='127.0.0.1'
diff --git a/nixos/modules/config/qt-plugin-env.nix b/nixos/modules/config/qt-plugin-env.nix
deleted file mode 100644
index c59865604165..000000000000
--- a/nixos/modules/config/qt-plugin-env.nix
+++ /dev/null
@@ -1,37 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-{
-  imports = [
-  ];
-
-  options = {
-    qtPlugins = lib.mkOption {
-      type = lib.types.listOf lib.types.path;
-      default = [];
-      description = ''
-        Plugin packages for Qt such as input methods.
-      '';
-    };
-  };
-
-  config = {
-    environment.variables = if builtins.length config.qtPlugins > 0
-      then
-        let
-          paths = [ pkgs.qt48 ] ++ config.qtPlugins;
-          env = pkgs.buildEnv {
-            name = "qt-plugin-env";
-
-            inherit paths;
-
-            postBuild = lib.concatStringsSep "\n"
-              (map (d: d.qtPluginEnvPostBuild or "") paths);
-
-            ignoreCollisions = true;
-          };
-        in {
-          QT_PLUGIN_PATH = [ (builtins.toString env) ];
-        }
-      else {};
-  };
-}
diff --git a/nixos/modules/config/vpnc.nix b/nixos/modules/config/vpnc.nix
index 68d755232ebe..c7ac1b3530e1 100644
--- a/nixos/modules/config/vpnc.nix
+++ b/nixos/modules/config/vpnc.nix
@@ -17,16 +17,16 @@ in
       services = mkOption {
        type = types.attrsOf types.str;
        default = {};
-       example = {
-         test = 
-          ''
-           IPSec gateway 192.168.1.1 
-           IPSec ID someID
-           IPSec secret secretKey
-           Xauth username name
-           Xauth password pass
-          '';
-       };
+       example = literalExample ''
+         { test = '''
+             IPSec gateway 192.168.1.1
+             IPSec ID someID
+             IPSec secret secretKey
+             Xauth username name
+             Xauth password pass
+           ''';
+         }
+       '';
        description = 
          ''
            The names of cisco VPNs and their associated definitions
diff --git a/nixos/modules/config/zram.nix b/nixos/modules/config/zram.nix
index 22b74847f871..019932b04e8d 100644
--- a/nixos/modules/config/zram.nix
+++ b/nixos/modules/config/zram.nix
@@ -98,11 +98,9 @@ in
             script = ''
               set -u
               set -o pipefail
-
-              PATH=${pkgs.procps}/bin:${pkgs.gnugrep}/bin:${pkgs.gnused}/bin
-
+              
               # Calculate memory to use for zram
-              totalmem=$(free | grep -e "^Mem:" | sed -e 's/^Mem: *//' -e 's/  *.*//')
+              totalmem=$(${pkgs.gnugrep}/bin/grep 'MemTotal: ' /proc/meminfo | ${pkgs.gawk}/bin/awk '{print $2}')
               mem=$(((totalmem * ${toString cfg.memoryPercent} / 100 / ${toString cfg.numDevices}) * 1024))
 
               echo $mem > /sys/class/block/${dev}/disksize
diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix
index 1a04baef1930..d0d481f72a40 100644
--- a/nixos/modules/hardware/all-firmware.nix
+++ b/nixos/modules/hardware/all-firmware.nix
@@ -22,7 +22,7 @@ with lib;
   ###### implementation
 
   config = mkIf config.hardware.enableAllFirmware {
-    hardware.firmware = [ pkgs.firmwareLinuxNonfree ];
+    hardware.firmware = [ pkgs.firmwareLinuxNonfree pkgs.intel2200BGFirmware ];
   };
 
 }
diff --git a/nixos/modules/hardware/network/intel-2200bg.nix b/nixos/modules/hardware/network/intel-2200bg.nix
index 1b70057d135b..17b973474c93 100644
--- a/nixos/modules/hardware/network/intel-2200bg.nix
+++ b/nixos/modules/hardware/network/intel-2200bg.nix
@@ -23,7 +23,7 @@
 
   config = lib.mkIf config.networking.enableIntel2200BGFirmware {
 
-    hardware.enableAllFirmware = true;
+    hardware.firmware = [ pkgs.intel2200BGFirmware ];
 
   };
 
diff --git a/nixos/modules/hardware/opengl.nix b/nixos/modules/hardware/opengl.nix
index 7693bd5bb453..d3b146be6b33 100644
--- a/nixos/modules/hardware/opengl.nix
+++ b/nixos/modules/hardware/opengl.nix
@@ -10,7 +10,7 @@ let
 
   videoDrivers = config.services.xserver.videoDrivers;
 
-  makePackage = p: p.buildEnv {
+  makePackage = p: pkgs.buildEnv {
     name = "mesa-drivers+txc-${p.mesa_drivers.version}";
     paths =
       [ p.mesa_drivers
@@ -19,6 +19,16 @@ let
       ];
   };
 
+  package = pkgs.buildEnv {
+    name = "opengl-drivers";
+    paths = [ cfg.package ] ++ cfg.extraPackages;
+  };
+
+  package32 = pkgs.buildEnv {
+    name = "opengl-drivers-32bit";
+    paths = [ cfg.package32 ] ++ cfg.extraPackages32;
+  };
+
 in
 
 {
@@ -75,11 +85,32 @@ in
       internal = true;
       description = ''
         The package that provides the 32-bit OpenGL implementation on
-        64-bit systems.  Used when <option>driSupport32Bit</option> is
+        64-bit systems. Used when <option>driSupport32Bit</option> is
         set.
       '';
     };
 
+    hardware.opengl.extraPackages = mkOption {
+      type = types.listOf types.package;
+      default = [];
+      example = literalExample "with pkgs; [ vaapiIntel libvdpau-va-gl vaapiVdpau ]";
+      description = ''
+        Additional packages to add to OpenGL drivers. This can be used
+        to add additional VA-API/VDPAU drivers.
+      '';
+    };
+
+    hardware.opengl.extraPackages32 = mkOption {
+      type = types.listOf types.package;
+      default = [];
+      example = literalExample "with pkgs; [ vaapiIntel libvdpau-va-gl vaapiVdpau ]";
+      description = ''
+        Additional packages to add to 32-bit OpenGL drivers on
+        64-bit systems. Used when <option>driSupport32Bit</option> is
+        set. This can be used to add additional VA-API/VDPAU drivers.
+      '';
+    };
+
   };
 
   config = mkIf cfg.enable {
@@ -91,11 +122,11 @@ in
 
     system.activationScripts.setup-opengl =
       ''
-        ln -sfn ${cfg.package} /run/opengl-driver
+        ln -sfn ${package} /run/opengl-driver
         ${if pkgs.stdenv.isi686 then ''
           ln -sfn opengl-driver /run/opengl-driver-32
         '' else if cfg.driSupport32Bit then ''
-          ln -sfn ${cfg.package32} /run/opengl-driver-32
+          ln -sfn ${package32} /run/opengl-driver-32
         '' else ''
           rm -f /run/opengl-driver-32
         ''}
diff --git a/nixos/modules/hardware/video/webcam/facetimehd.nix b/nixos/modules/hardware/video/webcam/facetimehd.nix
new file mode 100644
index 000000000000..b35709763b90
--- /dev/null
+++ b/nixos/modules/hardware/video/webcam/facetimehd.nix
@@ -0,0 +1,45 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.hardware.facetimehd;
+
+  kernelPackages = config.boot.kernelPackages;
+
+in
+
+{
+
+  options.hardware.facetimehd.enable = mkEnableOption "facetimehd kernel module";
+
+  config = mkIf cfg.enable {
+
+    assertions = singleton {
+      assertion = versionAtLeast kernelPackages.kernel.version "3.19";
+      message = "facetimehd is not supported for kernels older than 3.19";
+    };
+
+    boot.kernelModules = [ "facetimehd" ];
+
+    boot.blacklistedKernelModules = [ "bdc_pci" ];
+
+    boot.extraModulePackages = [ kernelPackages.facetimehd ];
+
+    hardware.firmware = [ pkgs.facetimehd-firmware ];
+
+    # unload module during suspend/hibernate as it crashes the whole system
+    powerManagement.powerDownCommands = ''
+      ${pkgs.module_init_tools}/bin/rmmod -f facetimehd
+    '';
+
+    # and load it back on resume
+    powerManagement.resumeCommands = ''
+      export MODULE_DIR=/run/current-system/kernel-modules/lib/modules
+      ${pkgs.module_init_tools}/bin/modprobe -v facetimehd
+    '';
+
+  };
+
+}
diff --git a/nixos/modules/i18n/inputMethod/default.nix b/nixos/modules/i18n/inputMethod/default.nix
new file mode 100644
index 000000000000..7e6a25bfb084
--- /dev/null
+++ b/nixos/modules/i18n/inputMethod/default.nix
@@ -0,0 +1,29 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+{
+  options = {
+    i18n.inputMethod = {
+      enabled = mkOption {
+        type    = types.nullOr (types.enum [ "ibus" "fcitx" "nabi" "uim" ]);
+        default = null;
+        example = "fcitx";
+        description = ''
+          Select the enabled input method. Input methods is a software to input symbols that are not available on standard input devices.
+
+          Input methods are specially used to input Chinese, Japanese and Korean characters.
+
+          Currently the following input methods are available in NixOS:
+
+          <itemizedlist>
+          <listitem><para>ibus: The intelligent input bus, extra input engines can be added using <literal>i18n.inputMethod.ibus.engines</literal>.</para></listitem>
+          <listitem><para>fcitx: A customizable lightweight input method, extra input engines can be added using <literal>i18n.inputMethod.fcitx.engines</literal>.</para></listitem>
+          <listitem><para>nabi: A Korean input method based on XIM. Nabi doesn't support Qt 5.</para></listitem>
+          <listitem><para>uim: The universal input method, is a library with a XIM bridge. uim mainly support Chinese, Japanese and Korean.</para></listitem>
+          </itemizedlist>
+        '';
+      };
+    };
+  };
+}
diff --git a/nixos/modules/i18n/inputMethod/fcitx.nix b/nixos/modules/i18n/inputMethod/fcitx.nix
new file mode 100644
index 000000000000..8e31743504f1
--- /dev/null
+++ b/nixos/modules/i18n/inputMethod/fcitx.nix
@@ -0,0 +1,44 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.i18n.inputMethod.fcitx;
+  fcitxPackage = pkgs.fcitx-with-plugins.override { plugins = cfg.engines; };
+  fcitxEngine = types.package // {
+    name  = "fcitx-engine";
+    check = x: (lib.types.package.check x) && (attrByPath ["meta" "isFcitxEngine"] false x);
+  };
+in
+{
+  options = {
+
+    i18n.inputMethod.fcitx = {
+      engines = mkOption {
+        type    = with types; listOf fcitxEngine;
+        default = [];
+        example = literalExample "with pkgs.fcitx-engines; [ mozc hangul ]";
+        description =
+          let
+            engines =
+              lib.concatStringsSep ", "
+              (map (name: "<literal>${name}</literal>")
+               (lib.attrNames pkgs.fcitx-engines));
+          in
+            "Enabled Fcitx engines. Available engines are: ${engines}.";
+      };
+    };
+
+  };
+
+  config = mkIf (config.i18n.inputMethod.enabled == "fcitx") {
+    environment.systemPackages = [ fcitxPackage ];
+
+    environment.variables = {
+      GTK_IM_MODULE = "fcitx";
+      QT_IM_MODULE  = "fcitx";
+      XMODIFIERS    = "@im=fcitx";
+    };
+    services.xserver.displayManager.sessionCommands = "${fcitxPackage}/bin/fcitx";
+  };
+}
diff --git a/nixos/modules/i18n/inputMethod/ibus.nix b/nixos/modules/i18n/inputMethod/ibus.nix
new file mode 100644
index 000000000000..bb80f43634d3
--- /dev/null
+++ b/nixos/modules/i18n/inputMethod/ibus.nix
@@ -0,0 +1,55 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.i18n.inputMethod.ibus;
+  ibusPackage = pkgs.ibus-with-plugins.override { plugins = cfg.engines; };
+  ibusEngine = types.package // {
+    name  = "ibus-engine";
+    check = x: (lib.types.package.check x) && (attrByPath ["meta" "isIbusEngine"] false x);
+  };
+
+  ibusAutostart = pkgs.writeTextFile {
+    name = "autostart-ibus-daemon";
+    destination = "/etc/xdg/autostart/ibus-daemon.desktop";
+    text = ''
+      [Desktop Entry]
+      Name=IBus
+      Type=Application
+      Exec=${ibusPackage}/bin/ibus-daemon --daemonize --xim --cache=refresh
+    '';
+  };
+in
+{
+  options = {
+    i18n.inputMethod.ibus = {
+      engines = mkOption {
+        type    = with types; listOf ibusEngine;
+        default = [];
+        example = literalExample "with pkgs.ibus-engines; [ mozc hangul ]";
+        description =
+          let
+            engines =
+              lib.concatStringsSep ", "
+              (map (name: "<literal>${name}</literal>")
+               (lib.attrNames pkgs.ibus-engines));
+          in
+            "Enabled IBus engines. Available engines are: ${engines}.";
+      };
+    };
+  };
+
+  config = mkIf (config.i18n.inputMethod.enabled == "ibus") {
+    # Without dconf enabled it is impossible to use IBus
+    environment.systemPackages = with pkgs; [
+      ibusPackage ibus-qt gnome3.dconf ibusAutostart
+    ];
+
+    environment.variables = {
+      GTK_IM_MODULE = "ibus";
+      QT_IM_MODULE = "ibus";
+      XMODIFIERS = "@im=ibus";
+    };
+  };
+}
diff --git a/nixos/modules/i18n/inputMethod/nabi.nix b/nixos/modules/i18n/inputMethod/nabi.nix
new file mode 100644
index 000000000000..c6708365effa
--- /dev/null
+++ b/nixos/modules/i18n/inputMethod/nabi.nix
@@ -0,0 +1,16 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+{
+  config = mkIf (config.i18n.inputMethod.enabled == "nabi") {
+    environment.systemPackages = [ pkgs.nabi ];
+
+    environment.variables = {
+      GTK_IM_MODULE = "nabi";
+      QT_IM_MODULE  = "nabi";
+      XMODIFIERS    = "@im=nabi";
+    };
+
+    services.xserver.displayManager.sessionCommands = "${pkgs.nabi}/bin/nabi &";
+  };
+}
diff --git a/nixos/modules/i18n/inputMethod/uim.nix b/nixos/modules/i18n/inputMethod/uim.nix
new file mode 100644
index 000000000000..f8a3e560656d
--- /dev/null
+++ b/nixos/modules/i18n/inputMethod/uim.nix
@@ -0,0 +1,37 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let 
+  cfg = config.i18n.inputMethod.uim;
+in
+{
+  options = {
+
+    i18n.inputMethod.uim = {
+      toolbar = mkOption {
+        type    = types.enum [ "gtk" "gtk3" "gtk-systray" "gtk3-systray" "qt4" ];
+        default = "gtk";
+        example = "gtk-systray";
+        description = ''
+          selected UIM toolbar.
+        '';
+      };
+    };
+
+  };
+
+  config = mkIf (config.i18n.inputMethod.enabled == "uim") {
+    environment.systemPackages = [ pkgs.uim ];
+
+    environment.variables = {
+      GTK_IM_MODULE = "uim";
+      QT_IM_MODULE  = "uim";
+      XMODIFIERS    = "@im=uim";
+    };
+    services.xserver.displayManager.sessionCommands = ''
+      ${pkgs.uim}/bin/uim-xim &
+      ${pkgs.uim}/bin/uim-toolbar-${cfg.toolbar} &
+    '';
+  };
+}
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
new file mode 100644
index 000000000000..5725938465f5
--- /dev/null
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
@@ -0,0 +1,78 @@
+# This module defines a NixOS installation CD that contains X11 and
+# GNOME 3.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  imports = [ ./installation-cd-base.nix ];
+
+  services.xserver = {
+    enable = true;
+    # GDM doesn't start in virtual machines with ISO
+    displayManager.slim = {
+      enable = true;
+      defaultUser = "root";
+      autoLogin = true;
+    };
+    desktopManager.gnome3 = {
+      enable = true;
+      extraGSettingsOverrides = ''
+        [org.gnome.desktop.background]
+        show-desktop-icons=true
+
+        [org.gnome.nautilus.desktop]
+        trash-icon-visible=false
+        volumes-visible=false
+        home-icon-visible=false
+        network-icon-visible=false
+      '';
+
+      extraGSettingsOverridePackages = [ pkgs.gnome3.nautilus ];
+    };
+  };
+
+  environment.systemPackages =
+    [ # Include gparted for partitioning disks.
+      pkgs.gparted
+
+      # Include some editors.
+      pkgs.vim
+      pkgs.bvi # binary editor
+      pkgs.joe
+
+      pkgs.glxinfo
+    ];
+
+  # Don't start the X server by default.
+  services.xserver.autorun = mkForce false;
+
+  # Auto-login as root.
+  services.xserver.displayManager.gdm.autoLogin = {
+    enable = true;
+    user = "root";
+  };
+
+  system.activationScripts.installerDesktop = let
+    # Must be executable
+    desktopFile = pkgs.writeScript "nixos-manual.desktop" ''
+      [Desktop Entry]
+      Version=1.0
+      Type=Link
+      Name=NixOS Manual
+      URL=${config.system.build.manual.manual}/share/doc/nixos/index.html
+      Icon=system-help
+    '';
+
+  # use cp and chmod +x, we must be sure the apps are in the nix store though
+  in ''
+    mkdir -p /root/Desktop
+    ln -sfT ${desktopFile} /root/Desktop/nixos-manual.desktop
+    cp ${pkgs.gnome3.gnome_terminal}/share/applications/gnome-terminal.desktop /root/Desktop/gnome-terminal.desktop
+    chmod a+rx /root/Desktop/gnome-terminal.desktop
+    cp ${pkgs.gparted}/share/applications/gparted.desktop /root/Desktop/gparted.desktop
+    chmod a+rx /root/Desktop/gparted.desktop
+  '';
+
+}
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-new-kernel.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde-new-kernel.nix
index 506b9292b01e..a4bcd7079a4f 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-new-kernel.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde-new-kernel.nix
@@ -1,7 +1,7 @@
 { config, pkgs, ... }:
 
 {
-  imports = [ ./installation-cd-graphical.nix ];
+  imports = [ ./installation-cd-graphical-kde.nix ];
 
   boot.kernelPackages = pkgs.linuxPackages_latest;
 }
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
index d14768bc1079..d14768bc1079 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index 248b0f00283c..5702e2d9a1e5 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -249,7 +249,7 @@ in
 
     fileSystems."/" =
       { fsType = "tmpfs";
-        options = "mode=0755";
+        options = [ "mode=0755" ];
       };
 
     # Note that /dev/root is a symlink to the actual root device
@@ -266,20 +266,20 @@ in
     fileSystems."/nix/.ro-store" =
       { fsType = "squashfs";
         device = "/iso/nix-store.squashfs";
-        options = "loop";
+        options = [ "loop" ];
         neededForBoot = true;
       };
 
     fileSystems."/nix/.rw-store" =
       { fsType = "tmpfs";
-        options = "mode=0755";
+        options = [ "mode=0755" ];
         neededForBoot = true;
       };
 
     fileSystems."/nix/store" =
       { fsType = "unionfs-fuse";
         device = "unionfs";
-        options = "allow_other,cow,nonempty,chroot=/mnt-root,max_files=32768,hide_meta_files,dirs=/nix/.rw-store=rw:/nix/.ro-store=ro";
+        options = [ "allow_other" "cow" "nonempty" "chroot=/mnt-root" "max_files=32768" "hide_meta_files" "dirs=/nix/.rw-store=rw:/nix/.ro-store=ro" ];
       };
 
     boot.initrd.availableKernelModules = [ "squashfs" "iso9660" "usb-storage" ];
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 15e22fb50d48..957a8ff9ce6d 100644
--- a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
@@ -23,7 +23,7 @@ in
   boot.loader.generic-extlinux-compatible.enable = true;
 
   boot.kernelPackages = pkgs.linuxPackages_latest;
-  boot.kernelParams = ["console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"];
+  boot.kernelParams = ["console=ttyS0,115200n8" "console=ttymxc0,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.nix b/nixos/modules/installer/cd-dvd/sd-image.nix
index 12b4f3045614..9eba542d8c91 100644
--- a/nixos/modules/installer/cd-dvd/sd-image.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image.nix
@@ -30,7 +30,7 @@ in
 
     bootSize = mkOption {
       type = types.int;
-      default = 128;
+      default = 120;
       description = ''
         Size of the /boot partition, in megabytes.
       '';
@@ -66,10 +66,10 @@ in
       buildInputs = with pkgs; [ dosfstools e2fsprogs mtools libfaketime utillinux ];
 
       buildCommand = ''
-        # Create the image file sized to fit /boot and /, plus 4M of slack
+        # Create the image file sized to fit /boot and /, plus 20M of slack
         rootSizeBlocks=$(du -B 512 --apparent-size ${rootfsImage} | awk '{ print $1 }')
         bootSizeBlocks=$((${toString config.sdImage.bootSize} * 1024 * 1024 / 512))
-        imageSize=$((rootSizeBlocks * 512 + bootSizeBlocks * 512 + 4096 * 1024))
+        imageSize=$((rootSizeBlocks * 512 + bootSizeBlocks * 512 + 20 * 1024 * 1024))
         truncate -s $imageSize $out
 
         # type=b is 'W95 FAT32', type=83 is 'Linux'.
@@ -77,8 +77,8 @@ in
             label: dos
             label-id: 0x2178694e
 
-            start=1M, size=$bootSizeBlocks, type=b, bootable
-            type=83
+            start=8M, size=$bootSizeBlocks, type=b, bootable
+            start=${toString (8 + config.sdImage.bootSize)}M, type=83
         EOF
 
         # Copy the rootfs into the SD image
diff --git a/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix b/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
index de0cc604bf3b..7badfcb8df22 100644
--- a/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
+++ b/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
@@ -86,8 +86,7 @@ in
   system.boot.loader.kernelFile = "uImage";
 
   boot.initrd.availableKernelModules =
-    [ "mvsdio" "mmc_block" "reiserfs" "ext3" "ums-cypress" "rtc_mv"
-      "ext4" ];
+    [ "mvsdio" "reiserfs" "ext3" "ums-cypress" "rtc_mv" "ext4" ];
 
   boot.postBootCommands =
     ''
diff --git a/nixos/modules/installer/cd-dvd/system-tarball.nix b/nixos/modules/installer/cd-dvd/system-tarball.nix
index c24fe97fba46..90e9b98a4575 100644
--- a/nixos/modules/installer/cd-dvd/system-tarball.nix
+++ b/nixos/modules/installer/cd-dvd/system-tarball.nix
@@ -43,7 +43,7 @@ in
     # so that we don't need to know its device.
     fileSystems = [ ];
 
-    # boot.initrd.availableKernelModules = [ "mvsdio" "mmc_block" "reiserfs" "ext3" "ext4" ];
+    # boot.initrd.availableKernelModules = [ "mvsdio" "reiserfs" "ext3" "ext4" ];
 
     # boot.initrd.kernelModules = [ "rtc_mv" ];
 
diff --git a/nixos/modules/installer/tools/auto-upgrade.nix b/nixos/modules/installer/tools/auto-upgrade.nix
index ca51de0fb8c7..79ccb5c3d18a 100644
--- a/nixos/modules/installer/tools/auto-upgrade.nix
+++ b/nixos/modules/installer/tools/auto-upgrade.nix
@@ -74,7 +74,7 @@ let cfg = config.system.autoUpgrade; in
       serviceConfig.Type = "oneshot";
 
       environment = config.nix.envVars //
-        { inherit (config.environment.sessionVariables) NIX_PATH SSL_CERT_FILE;
+        { inherit (config.environment.sessionVariables) NIX_PATH;
           HOME = "/root";
         };
 
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index c590c4cde3f0..ec880e084726 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -148,7 +148,7 @@ sub pciCheck {
          $device eq "0x4331" || $device eq "0x43a0" || $device eq "0x43b1"
         ) )
      {
-        push @modulePackages, "\${config.boot.kernelPackages.broadcom_sta}";
+        push @modulePackages, "config.boot.kernelPackages.broadcom_sta";
         push @kernelModules, "wl";
      }
 
@@ -349,7 +349,7 @@ foreach my $fs (read_file("/proc/self/mountinfo")) {
   fileSystems.\"$mountPoint\" =
     { device = \"$base$path\";
       fsType = \"none\";
-      options = \"bind\";
+      options = \[ \"bind\" \];
     };
 
 EOF
@@ -409,7 +409,7 @@ EOF
 
     if (scalar @extraOptions > 0) {
       $fileSystems .= <<EOF;
-      options = \"${\join ",", uniq(@extraOptions)}\";
+      options = \[ ${\join " ", map { "\"" . $_ . "\"" } uniq(@extraOptions)} \];
 EOF
     }
 
@@ -422,13 +422,20 @@ EOF
 
 # Generate the hardware configuration file.
 
-sub toNixExpr {
+sub toNixStringList {
     my $res = "";
     foreach my $s (@_) {
         $res .= " \"$s\"";
     }
     return $res;
 }
+sub toNixList {
+    my $res = "";
+    foreach my $s (@_) {
+        $res .= " $s";
+    }
+    return $res;
+}
 
 sub multiLineList {
     my $indent = shift;
@@ -444,9 +451,9 @@ sub multiLineList {
     return $res;
 }
 
-my $initrdAvailableKernelModules = toNixExpr(uniq @initrdAvailableKernelModules);
-my $kernelModules = toNixExpr(uniq @kernelModules);
-my $modulePackages = toNixExpr(uniq @modulePackages);
+my $initrdAvailableKernelModules = toNixStringList(uniq @initrdAvailableKernelModules);
+my $kernelModules = toNixStringList(uniq @kernelModules);
+my $modulePackages = toNixList(uniq @modulePackages);
 
 my $fsAndSwap = "";
 if (!$noFilesystems) {
diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh
index 4e10615f902f..c23d7e5b509d 100644
--- a/nixos/modules/installer/tools/nixos-install.sh
+++ b/nixos/modules/installer/tools/nixos-install.sh
@@ -73,11 +73,6 @@ if ! test -e "$mountPoint"; then
     exit 1
 fi
 
-if ! grep -F -q " $mountPoint " /proc/mounts; then
-    echo "$mountPoint doesn't appear to be a mount point"
-    exit 1
-fi
-
 
 # Mount some stuff in the target root directory.
 mkdir -m 0755 -p $mountPoint/dev $mountPoint/proc $mountPoint/sys $mountPoint/etc $mountPoint/run $mountPoint/home
diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh
index 6792690b4c3b..e0e79f63fab7 100644
--- a/nixos/modules/installer/tools/nixos-rebuild.sh
+++ b/nixos/modules/installer/tools/nixos-rebuild.sh
@@ -19,6 +19,8 @@ rollback=
 upgrade=
 repair=
 profile=/nix/var/nix/profiles/system
+buildHost=
+targetHost=
 
 while [ "$#" -gt 0 ]; do
     i="$1"; shift 1
@@ -73,6 +75,14 @@ while [ "$#" -gt 0 ]; do
         fi
         shift 1
         ;;
+      --build-host|h)
+        buildHost="$1"
+        shift 1
+        ;;
+      --target-host|t)
+        targetHost="$1"
+        shift 1
+        ;;
       *)
         echo "$0: unknown option \`$i'"
         exit 1
@@ -80,6 +90,91 @@ while [ "$#" -gt 0 ]; do
     esac
 done
 
+
+if [ -z "$buildHost" -a -n "$targetHost" ]; then
+    buildHost="$targetHost"
+fi
+if [ "$targetHost" = localhost ]; then
+    targetHost=
+fi
+if [ "$buildHost" = localhost ]; then
+    buildHost=
+fi
+
+buildHostCmd() {
+    if [ -z "$buildHost" ]; then
+        "$@"
+    elif [ -n "$remoteNix" ]; then
+        ssh $SSHOPTS "$buildHost" PATH="$remoteNix:$PATH" "$@"
+    else
+        ssh $SSHOPTS "$buildHost" "$@"
+    fi
+}
+
+targetHostCmd() {
+    if [ -z "$targetHost" ]; then
+        "$@"
+    else
+        ssh $SSHOPTS "$targetHost" "$@"
+    fi
+}
+
+copyToTarget() {
+    if ! [ "$targetHost" = "$buildHost" ]; then
+        if [ -z "$targetHost" ]; then
+            NIX_SSHOPTS=$SSH_OPTS nix-copy-closure --from "$buildHost" "$1"
+        elif [ -z "$buildHost" ]; then
+            NIX_SSHOPTS=$SSH_OPTS nix-copy-closure --to "$targetHost" "$1"
+        else
+            buildHostCmd nix-copy-closure --to "$targetHost" "$1"
+        fi
+    fi
+}
+
+nixBuild() {
+    if [ -z "$buildHost" ]; then
+        nix-build "$@"
+    else
+        local instArgs=()
+        local buildArgs=()
+
+        while [ "$#" -gt 0 ]; do
+            local i="$1"; shift 1
+            case "$i" in
+              -o)
+                local out="$1"; shift 1
+                buildArgs+=("--add-root" "$out" "--indirect")
+                ;;
+              -A)
+                local j="$1"; shift 1
+                instArgs+=("$i" "$j")
+                ;;
+              -I) # We don't want this in buildArgs
+                shift 1
+                ;;
+              --no-out-link) # We don't want this in buildArgs
+                ;;
+              "<"*) # nix paths
+                instArgs+=("$i")
+                ;;
+              *)
+                buildArgs+=("$i")
+                ;;
+            esac
+        done
+
+        local drv="$(nix-instantiate "${instArgs[@]}" "${extraBuildFlags[@]}")"
+        if [ -a "$drv" ]; then
+            NIX_SSHOPTS=$SSH_OPTS nix-copy-closure --to "$buildHost" "$drv"
+            buildHostCmd nix-store -r "$drv" "${buildArgs[@]}"
+        else
+            echo "nix-instantiate failed"
+            exit 1
+        fi
+  fi
+}
+
+
 if [ -z "$action" ]; then showSyntax; fi
 
 # Only run shell scripts from the Nixpkgs tree if the action is
@@ -128,7 +223,16 @@ fi
 
 
 tmpDir=$(mktemp -t -d nixos-rebuild.XXXXXX)
-trap 'rm -rf "$tmpDir"' EXIT
+SSHOPTS="$NIX_SSHOPTS -o ControlMaster=auto -o ControlPath=$tmpDir/ssh-%n -o ControlPersist=60"
+
+cleanup() {
+    for ctrl in "$tmpDir"/ssh-*; do
+        ssh -o ControlPath="$ctrl" -O exit dummyhost 2>/dev/null || true
+    done
+    rm -rf "$tmpDir"
+}
+trap cleanup EXIT
+
 
 
 # If the Nix daemon is running, then use it.  This allows us to use
@@ -150,30 +254,56 @@ if [ -n "$rollback" -o "$action" = dry-build ]; then
     buildNix=
 fi
 
+prebuiltNix() {
+    machine="$1"
+    if [ "$machine" = x86_64 ]; then
+        return /nix/store/xryr9g56h8yjddp89d6dw12anyb4ch7c-nix-1.10
+    elif [[ "$machine" =~ i.86 ]]; then
+        return /nix/store/2w92k5wlpspf0q2k9mnf2z42prx3bwmv-nix-1.10
+    else
+        echo "$0: unsupported platform"
+        exit 1
+    fi
+}
+
+remotePATH=
+
 if [ -n "$buildNix" ]; then
     echo "building Nix..." >&2
-    if ! nix-build '<nixpkgs/nixos>' -A config.nix.package -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
-        if ! nix-build '<nixpkgs/nixos>' -A nixFallback -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
-            if ! nix-build '<nixpkgs>' -A nix -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
-                machine="$(uname -m)"
-                if [ "$machine" = x86_64 ]; then
-                    nixStorePath=/nix/store/xryr9g56h8yjddp89d6dw12anyb4ch7c-nix-1.10
-                elif [[ "$machine" =~ i.86 ]]; then
-                    nixStorePath=/nix/store/2w92k5wlpspf0q2k9mnf2z42prx3bwmv-nix-1.10
-                else
-                    echo "$0: unsupported platform"
-                    exit 1
-                fi
+    nixDrv=
+    if ! nixDrv="$(nix-instantiate '<nixpkgs/nixos>' --add-root $tmpDir/nix.drv --indirect -A config.nix.package "${extraBuildFlags[@]}")"; then
+        if ! nixDrv="$(nix-instantiate '<nixpkgs/nixos>' --add-root $tmpDir/nix.drv --indirect -A nixFallback "${extraBuildFlags[@]}")"; then
+            if ! nixDrv="$(nix-instantiate '<nixpkgs>' --add-root $tmpDir/nix.drv --indirect -A nix "${extraBuildFlags[@]}")"; then
+                nixStorePath="$(prebuiltNix "$(uname -m)")"
                 if ! nix-store -r $nixStorePath --add-root $tmpDir/nix --indirect \
                     --option extra-binary-caches https://cache.nixos.org/; then
                     echo "warning: don't know how to get latest Nix" >&2
                 fi
                 # Older version of nix-store -r don't support --add-root.
                 [ -e $tmpDir/nix ] || ln -sf $nixStorePath $tmpDir/nix
+                if [ -n "$buildHost" ]; then
+                    remoteNixStorePath="$(prebuiltNix "$(buildHostCmd uname -m)")"
+                    remoteNix="$remoteNixStorePath/bin"
+                    if ! buildHostCmd nix-store -r $remoteNixStorePath \
+                      --option extra-binary-caches https://cache.nixos.org/ >/dev/null; then
+                        remoteNix=
+                        echo "warning: don't know how to get latest Nix" >&2
+                    fi
+                fi
             fi
         fi
     fi
-    PATH=$tmpDir/nix/bin:$PATH
+    if [ -a "$nixDrv" ]; then
+        nix-store -r "$nixDrv"'!'"out" --add-root $tmpDir/nix --indirect >/dev/null
+        if [ -n "$buildHost" ]; then
+            nix-copy-closure --to "$buildHost" "$nixDrv"
+            # The nix build produces multiple outputs, we add them all to the remote path
+            for p in $(buildHostCmd nix-store -r "$(readlink "$nixDrv")" "${buildArgs[@]}"); do
+                remoteNix="$remoteNix${remoteNix:+:}$p/bin"
+            done
+        fi
+    fi
+    PATH="$tmpDir/nix/bin:$PATH"
 fi
 
 
@@ -200,31 +330,35 @@ fi
 if [ -z "$rollback" ]; then
     echo "building the system configuration..." >&2
     if [ "$action" = switch -o "$action" = boot ]; then
-        nix-env "${extraBuildFlags[@]}" -p "$profile" -f '<nixpkgs/nixos>' --set -A system
-        pathToConfig="$profile"
+        pathToConfig="$(nixBuild '<nixpkgs/nixos>' --no-out-link -A system "${extraBuildFlags[@]}")"
+        copyToTarget "$pathToConfig"
+        targetHostCmd nix-env -p "$profile" --set "$pathToConfig"
     elif [ "$action" = test -o "$action" = build -o "$action" = dry-build -o "$action" = dry-activate ]; then
-        nix-build '<nixpkgs/nixos>' -A system -k "${extraBuildFlags[@]}" > /dev/null
-        pathToConfig=./result
+        pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A system -k "${extraBuildFlags[@]}")"
     elif [ "$action" = build-vm ]; then
-        nix-build '<nixpkgs/nixos>' -A vm -k "${extraBuildFlags[@]}" > /dev/null
-        pathToConfig=./result
+        pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A vm -k "${extraBuildFlags[@]}")"
     elif [ "$action" = build-vm-with-bootloader ]; then
-        nix-build '<nixpkgs/nixos>' -A vmWithBootLoader -k "${extraBuildFlags[@]}" > /dev/null
-        pathToConfig=./result
+        pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A vmWithBootLoader -k "${extraBuildFlags[@]}")"
     else
         showSyntax
     fi
+    # Copy build to target host if we haven't already done it
+    if ! [ "$action" = switch -o "$action" = boot ]; then
+        copyToTarget "$pathToConfig"
+    fi
 else # [ -n "$rollback" ]
     if [ "$action" = switch -o "$action" = boot ]; then
-        nix-env --rollback -p "$profile"
+        targetHostCmd nix-env --rollback -p "$profile"
         pathToConfig="$profile"
     elif [ "$action" = test -o "$action" = build ]; then
         systemNumber=$(
-            nix-env -p "$profile" --list-generations |
+            targetHostCmd nix-env -p "$profile" --list-generations |
             sed -n '/current/ {g; p;}; s/ *\([0-9]*\).*/\1/; h'
         )
-        ln -sT "$profile"-${systemNumber}-link ./result
-        pathToConfig=./result
+        pathToConfig="$profile"-${systemNumber}-link
+        if [ -z "$targetHost" ]; then
+            ln -sT "$pathToConfig" ./result
+        fi
     else
         showSyntax
     fi
@@ -234,7 +368,7 @@ fi
 # If we're not just building, then make the new configuration the boot
 # default and/or activate it now.
 if [ "$action" = switch -o "$action" = boot -o "$action" = test -o "$action" = dry-activate ]; then
-    if ! $pathToConfig/bin/switch-to-configuration "$action"; then
+    if ! targetHostCmd $pathToConfig/bin/switch-to-configuration "$action"; then
         echo "warning: error(s) occurred while switching to the new configuration" >&2
         exit 1
     fi
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 064b4cbc4b33..0ab2b8a76fc5 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -248,6 +248,12 @@
       matrix-synapse = 224;
       rspamd = 225;
       rmilter = 226;
+      cfdyndns = 227;
+      gammu-smsd = 228;
+      pdnsd = 229;
+      octoprint = 230;
+      avahi-autoipd = 231;
+      nntp-proxy = 232;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -473,6 +479,9 @@
       matrix-synapse = 224;
       rspamd = 225;
       rmilter = 226;
+      cfdyndns = 227;
+      pdnsd = 229;
+      octoprint = 230;
 
       # 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 4f9c8d4e5ba1..5b560cedc623 100644
--- a/nixos/modules/misc/locate.nix
+++ b/nixos/modules/misc/locate.nix
@@ -1,76 +1,76 @@
-{ config, lib, pkgs, ... }:
+{ config, options, lib, pkgs, ... }:
 
 with lib;
 
 let
   cfg = config.services.locate;
 in {
+  options.services.locate = {
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        If enabled, NixOS will periodically update the database of
+        files used by the <command>locate</command> command.
+      '';
+    };
 
-  ###### interface
-
-  options = {
-
-    services.locate = {
-
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          If enabled, NixOS will periodically update the database of
-          files used by the <command>locate</command> command.
-        '';
-      };
-
-      period = mkOption {
-        type = types.str;
-        default = "15 02 * * *";
-        description = ''
-          This option defines (in the format used by cron) when the
-          locate database is updated.
-          The default is to update at 02:15 at night every day.
-        '';
-      };
-
-      extraFlags = mkOption {
-        type = types.listOf types.str;
-        default = [ ];
-        description = ''
-          Extra flags to pass to <command>updatedb</command>.
-        '';
-      };
+    interval = mkOption {
+      type = types.str;
+      default = "02:15";
+      example = "hourly";
+      description = ''
+        Update the locate database at this interval. Updates by
+        default at 2:15 AM every day.
+
+        The format is described in
+        <citerefentry><refentrytitle>systemd.time</refentrytitle>
+        <manvolnum>7</manvolnum></citerefentry>.
+      '';
+    };
 
-      output = mkOption {
-        type = types.path;
-        default = "/var/cache/locatedb";
-        description = ''
-          The database file to build.
-        '';
-      };
+    # This is no longer supported, but we keep it to give a better warning below
+    period = mkOption { visible = false; };
 
-      localuser = mkOption {
-        type = types.str;
-        default = "nobody";
-        description = ''
-          The user to search non-network directories as, using
-          <command>su</command>.
-        '';
-      };
+    extraFlags = mkOption {
+      type = types.listOf types.str;
+      default = [ ];
+      description = ''
+        Extra flags to pass to <command>updatedb</command>.
+      '';
+    };
 
-      includeStore = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Whether to include <filename>/nix/store</filename> in the locate database.
-        '';
-      };
+    output = mkOption {
+      type = types.path;
+      default = "/var/cache/locatedb";
+      description = ''
+        The database file to build.
+      '';
+    };
 
+    localuser = mkOption {
+      type = types.str;
+      default = "nobody";
+      description = ''
+        The user to search non-network directories as, using
+        <command>su</command>.
+      '';
     };
 
+    includeStore = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to include <filename>/nix/store</filename> in the locate database.
+      '';
+    };
   };
 
-  ###### implementation
-
   config = {
+    warnings =
+      let opt = options.services.locate.period; in
+      optional opt.isDefined "The ‘services.locate.period’ option in ${showFiles opt.files} has been removed; please replace it with ‘services.locate.interval’, using the systemd.time(7) calendar event format.";
+
     systemd.services.update-locatedb =
       { description = "Update Locate Database";
         path  = [ pkgs.su ];
@@ -84,11 +84,18 @@ in {
           '';
         serviceConfig.Nice = 19;
         serviceConfig.IOSchedulingClass = "idle";
+        serviceConfig.PrivateTmp = "yes";
+        serviceConfig.PrivateNetwork = "yes";
+        serviceConfig.NoNewPrivileges = "yes";
+        serviceConfig.ReadOnlyDirectories = "/";
+        serviceConfig.ReadWriteDirectories = cfg.output;
       };
 
-    services.cron.systemCronJobs = optional config.services.locate.enable
-      "${config.services.locate.period} root ${config.systemd.package}/bin/systemctl start update-locatedb.service";
-
+    systemd.timers.update-locatedb = mkIf cfg.enable
+      { description = "Update timer for locate database";
+        partOf      = [ "update-locatedb.service" ];
+        wantedBy    = [ "timers.target" ];
+        timerConfig.OnCalendar = cfg.interval;
+      };
   };
-
 }
diff --git a/nixos/modules/misc/nixos.nix b/nixos/modules/misc/nixos.nix
deleted file mode 100644
index 84365b640a48..000000000000
--- a/nixos/modules/misc/nixos.nix
+++ /dev/null
@@ -1,82 +0,0 @@
-{ config, options, lib, ... }:
-
-# This modules is used to inject a different NixOS version as well as its
-# argument such that one can pin a specific version with the versionning
-# system of the configuration.
-let
-  nixosReentry = import config.nixos.path {
-    inherit (config.nixos) configuration extraModules;
-    inherit (config.nixpkgs) system;
-    reEnter = true;
-  };
-in
-
-with lib;
-
-{
-  options = {
-    nixos.path = mkOption {
-      default = null;
-      example = literalExample "./nixpkgs-15.09/nixos";
-      type = types.nullOr types.path;
-      description = ''
-        This option give the ability to evaluate the current set of modules
-        with a different version of NixOS. This option can be used version
-        the version of NixOS with the configuration without relying on the
-        <literal>NIX_PATH</literal> environment variable.
-      '';
-    };
-
-    nixos.system = mkOption {
-      example = "i686-linux";
-      type = types.uniq types.str;
-      description = ''
-        Name of the system used to compile NixOS.
-      '';
-    };
-
-    nixos.extraModules = mkOption {
-      default = [];
-      example = literalExample "[ ./sshd-config.nix ]";
-      type = types.listOf (types.either (types.submodule ({...}:{options={};})) types.path);
-      description = ''
-        Define additional modules which would be loaded to evaluate the
-        configuration.
-      '';
-    };
-
-    nixos.configuration = mkOption {
-      type = types.unspecified;
-      internal = true;
-      description = ''
-        Option used by <filename>nixos/default.nix</filename> to re-inject
-        the same configuration module as the one used for the current
-        execution.
-      '';
-    };
-
-    nixos.reflect = mkOption {
-      default = { inherit config options; };
-      type = types.unspecified;
-      internal = true;
-      description = ''
-        Provides <literal>config</literal> and <literal>options</literal>
-        computed by the module system and given as argument to all
-        modules. These are used for introspection of options and
-        configuration by tools such as <literal>nixos-option</literal>.
-      '';
-    };
-  };
-
-  config = mkMerge [
-    (mkIf (config.nixos.path != null) (mkForce {
-      system.build.toplevel = nixosReentry.system;
-      system.build.vm = nixosReentry.vm;
-      nixos.reflect = { inherit (nixosReentry) config options; };
-    }))
-
-    { meta.maintainers = singleton lib.maintainers.pierron;
-      meta.doc = ./nixos.xml;
-    }
-  ];
-}
diff --git a/nixos/modules/misc/nixos.xml b/nixos/modules/misc/nixos.xml
deleted file mode 100644
index 064bdd80b3c9..000000000000
--- a/nixos/modules/misc/nixos.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<chapter xmlns="http://docbook.org/ns/docbook"
-         xmlns:xlink="http://www.w3.org/1999/xlink"
-         xmlns:xi="http://www.w3.org/2001/XInclude"
-         version="5.0"
-         xml:id="module-misc-nixos">
-
-<title>NixOS Reentry</title>
-
-<!-- FIXME: render nicely -->
-
-<!-- FIXME: source can be added automatically -->
-<para><emphasis>Source:</emphasis> <filename>modules/misc/nixos.nix</filename></para>
-
-<!-- FIXME: more stuff, like maintainer? -->
-
-<para>NixOS reentry can be used for both pinning the evaluation to a
-specific version of NixOS, and to dynamically add additional modules into
-the Module evaluation.</para>
-
-<section><title>NixOS Version Pinning</title>
-
-<para>To pin a specific version of NixOS, you need a version that you can
-either clone localy, or that you can fetch remotely.</para>
-
-<para>If you already have a cloned version of NixOS in the directory
-<filename>/etc/nixos/nixpkgs-16-03</filename>, then you can specify the
-<option>nixos.path</option> with either the path or the relative path of
-your NixOS clone. For example, you can add the following to your
-<filename>/etc/nixos/configuration.nix</filename> file:
-
-<programlisting>
-nixos.path = ./nixpkgs-16-03/nixos;
-</programlisting>
-</para>
-
-<para>Another option is to fetch a specific version of NixOS, with either
-the <literal>fetchTarball</literal> builtin, or the
-<literal>pkgs.fetchFromGitHub</literal> function and use the result as an
-input.
-
-<programlisting>
-nixos.path = "${builtins.fetchTarball https://github.com/NixOS/nixpkgs/archive/1f27976e03c15183191d1b4aa1a40d1f14666cd2.tar.gz}/nixos";
-</programlisting>
-</para>
-
-</section>
-
-
-<section><title>Adding Module Dynamically</title>
-
-<para>To add additional module, the recommended way is to use statically
-known modules in the list of imported arguments as described in <xref
-linkend="sec-modularity" />.  Unfortunately, this recommended method has
-limitation, such that the list of imported files cannot be selected based on
-the content of the configuration.
-
-Fortunately, NixOS reentry system can be used as an alternative to register
-new imported modules based on the content of the configuration. To do so,
-one should define both <option>nixos.path</option> and
-<option>nixos.extraModules</option> options.
-
-<programlisting>
-nixos.path = &lt;nixos&gt;;
-nixos.extraModules =
-  if config.networking.hostName == "server" then
-    [ ./server.nix ] else [ ./client.nix ];
-</programlisting>
-
-Also note, that the above can be reimplemented in a different way which is
-not as expensive, by using <literal>mkIf</literal> at the top each
-configuration if both modules are present on the file system (see <xref
-linkend="sec-option-definitions" />) and by always inmporting both
-modules.</para>
-
-</section>
-
-<section><title>Options</title>
-
-<para>FIXME: auto-generated list of module options.</para>
-
-</section>
-
-
-</chapter>
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 2ff61877c23d..0105cc3cdf2c 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -7,7 +7,6 @@
   ./config/fonts/fonts.nix
   ./config/fonts/ghostscript.nix
   ./config/gnu.nix
-  ./config/gtk-exe-env.nix
   ./config/i18n.nix
   ./config/krb5.nix
   ./config/ldap.nix
@@ -16,7 +15,6 @@
   ./config/nsswitch.nix
   ./config/power-management.nix
   ./config/pulseaudio.nix
-  ./config/qt-plugin-env.nix
   ./config/shells-environment.nix
   ./config/swap.nix
   ./config/sysctl.nix
@@ -42,6 +40,12 @@
   ./hardware/video/bumblebee.nix
   ./hardware/video/nvidia.nix
   ./hardware/video/ati.nix
+  ./hardware/video/webcam/facetimehd.nix
+  ./i18n/inputMethod/default.nix
+  ./i18n/inputMethod/fcitx.nix
+  ./i18n/inputMethod/ibus.nix
+  ./i18n/inputMethod/nabi.nix
+  ./i18n/inputMethod/uim.nix
   ./installer/tools/auto-upgrade.nix
   ./installer/tools/nixos-checkout.nix
   ./installer/tools/tools.nix
@@ -52,7 +56,6 @@
   ./misc/lib.nix
   ./misc/locate.nix
   ./misc/meta.nix
-  ./misc/nixos.nix
   ./misc/nixpkgs.nix
   ./misc/passthru.nix
   ./misc/version.nix
@@ -65,7 +68,6 @@
   ./programs/environment.nix
   ./programs/freetds.nix
   ./programs/fish.nix
-  ./programs/ibus.nix
   ./programs/kbdlight.nix
   ./programs/light.nix
   ./programs/man.nix
@@ -75,7 +77,6 @@
   ./programs/shell.nix
   ./programs/ssh.nix
   ./programs/ssmtp.nix
-  ./programs/uim.nix
   ./programs/venus.nix
   ./programs/wvdial.nix
   ./programs/xfs_quota.nix
@@ -88,6 +89,7 @@
   ./security/ca.nix
   ./security/duosec.nix
   ./security/grsecurity.nix
+  ./security/oath.nix
   ./security/pam.nix
   ./security/pam_usb.nix
   ./security/pam_mount.nix
@@ -200,6 +202,7 @@
   ./services/misc/bepasty.nix
   ./services/misc/canto-daemon.nix
   ./services/misc/calibre-server.nix
+  ./services/misc/cfdyndns.nix
   ./services/misc/cpuminer-cryptonight.nix
   ./services/misc/cgminer.nix
   ./services/misc/confd.nix
@@ -210,6 +213,7 @@
   ./services/misc/etcd.nix
   ./services/misc/felix.nix
   ./services/misc/folding-at-home.nix
+  ./services/misc/gammu-smsd.nix
   #./services/misc/gitit.nix
   ./services/misc/gitlab.nix
   ./services/misc/gitolite.nix
@@ -226,6 +230,7 @@
   ./services/misc/nix-gc.nix
   ./services/misc/nixos-manual.nix
   ./services/misc/nix-ssh-serve.nix
+  ./services/misc/octoprint.nix
   ./services/misc/parsoid.nix
   ./services/misc/phd.nix
   ./services/misc/plex.nix
@@ -235,6 +240,7 @@
   ./services/misc/ripple-data-api.nix
   ./services/misc/rogue.nix
   ./services/misc/siproxd.nix
+  ./services/misc/spice-vdagentd.nix
   ./services/misc/subsonic.nix
   ./services/misc/sundtek.nix
   ./services/misc/svnserve.nix
@@ -249,6 +255,7 @@
   ./services/monitoring/dd-agent.nix
   ./services/monitoring/grafana.nix
   ./services/monitoring/graphite.nix
+  ./services/monitoring/hdaps.nix
   ./services/monitoring/heapster.nix
   ./services/monitoring/longview.nix
   ./services/monitoring/monit.nix
@@ -267,6 +274,7 @@
   ./services/monitoring/zabbix-agent.nix
   ./services/monitoring/zabbix-server.nix
   ./services/network-filesystems/drbd.nix
+  ./services/network-filesystems/netatalk.nix
   ./services/network-filesystems/nfsd.nix
   ./services/network-filesystems/openafs-client/default.nix
   ./services/network-filesystems/rsyncd.nix
@@ -315,11 +323,11 @@
   ./services/networking/hostapd.nix
   ./services/networking/i2pd.nix
   ./services/networking/i2p.nix
-  ./services/networking/ifplugd.nix
   ./services/networking/iodined.nix
   ./services/networking/ircd-hybrid/default.nix
   ./services/networking/kippo.nix
   ./services/networking/lambdabot.nix
+  ./services/networking/libreswan.nix
   ./services/networking/mailpile.nix
   ./services/networking/minidlna.nix
   ./services/networking/miniupnpd.nix
@@ -330,6 +338,7 @@
   ./services/networking/networkmanager.nix
   ./services/networking/ngircd.nix
   ./services/networking/nix-serve.nix
+  ./services/networking/nntp-proxy.nix
   ./services/networking/nsd.nix
   ./services/networking/ntopng.nix
   ./services/networking/ntpd.nix
@@ -339,6 +348,7 @@
   ./services/networking/openntpd.nix
   ./services/networking/openvpn.nix
   ./services/networking/ostinato.nix
+  ./services/networking/pdnsd.nix
   ./services/networking/polipo.nix
   ./services/networking/prayer.nix
   ./services/networking/privoxy.nix
@@ -395,6 +405,7 @@
   ./services/security/fprintd.nix
   ./services/security/fprot.nix
   ./services/security/frandom.nix
+  ./services/security/haka.nix
   ./services/security/haveged.nix
   ./services/security/hologram.nix
   ./services/security/munge.nix
@@ -437,6 +448,7 @@
   ./services/x11/display-managers/lightdm.nix
   ./services/x11/display-managers/sddm.nix
   ./services/x11/display-managers/slim.nix
+  ./services/x11/hardware/libinput.nix
   ./services/x11/hardware/multitouch.nix
   ./services/x11/hardware/synaptics.nix
   ./services/x11/hardware/wacom.nix
@@ -460,10 +472,10 @@
   ./system/boot/coredump.nix
   ./system/boot/emergency-mode.nix
   ./system/boot/initrd-network.nix
+  ./system/boot/initrd-ssh.nix
   ./system/boot/kernel.nix
   ./system/boot/kexec.nix
   ./system/boot/loader/efi.nix
-  ./system/boot/loader/loader.nix
   ./system/boot/loader/generations-dir/generations-dir.nix
   ./system/boot/loader/generic-extlinux-compatible
   ./system/boot/loader/grub/grub.nix
@@ -471,15 +483,16 @@
   ./system/boot/loader/grub/memtest.nix
   ./system/boot/loader/gummiboot/gummiboot.nix
   ./system/boot/loader/init-script/init-script.nix
+  ./system/boot/loader/loader.nix
   ./system/boot/loader/raspberrypi/raspberrypi.nix
   ./system/boot/luksroot.nix
   ./system/boot/modprobe.nix
+  ./system/boot/networkd.nix
+  ./system/boot/resolved.nix
   ./system/boot/shutdown.nix
   ./system/boot/stage-1.nix
   ./system/boot/stage-2.nix
   ./system/boot/systemd.nix
-  ./system/boot/networkd.nix
-  ./system/boot/resolved.nix
   ./system/boot/timesyncd.nix
   ./system/boot/tmp.nix
   ./system/etc/etc.nix
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
index 20a1f7f1ed8c..66b5765a895c 100644
--- a/nixos/modules/profiles/base.nix
+++ b/nixos/modules/profiles/base.nix
@@ -17,6 +17,7 @@
     pkgs.ddrescue
     pkgs.ccrypt
     pkgs.cryptsetup # needed for dm-crypt volumes
+    pkgs.which # 88K size
 
     # Some networking tools.
     pkgs.fuse
diff --git a/nixos/modules/profiles/qemu-guest.nix b/nixos/modules/profiles/qemu-guest.nix
index 759fdb7f8e5f..987eb051b98c 100644
--- a/nixos/modules/profiles/qemu-guest.nix
+++ b/nixos/modules/profiles/qemu-guest.nix
@@ -14,4 +14,6 @@
       # to the *boot time* of the host).
       hwclock -s
     '';
+
+  security.rngd.enable = false;
 }
diff --git a/nixos/modules/programs/bash/bash.nix b/nixos/modules/programs/bash/bash.nix
index 1c3c07a1c210..e4e264ec0036 100644
--- a/nixos/modules/programs/bash/bash.nix
+++ b/nixos/modules/programs/bash/bash.nix
@@ -56,7 +56,7 @@ in
       */
 
       shellAliases = mkOption {
-        default = config.environment.shellAliases // { which = "type -P"; };
+        default = config.environment.shellAliases;
         description = ''
           Set of aliases for bash shell. See <option>environment.shellAliases</option>
           for an option format description.
diff --git a/nixos/modules/programs/freetds.nix b/nixos/modules/programs/freetds.nix
index 398fd104363b..e0860a242b74 100644
--- a/nixos/modules/programs/freetds.nix
+++ b/nixos/modules/programs/freetds.nix
@@ -17,14 +17,14 @@ in
     environment.freetds = mkOption {
       type = types.attrsOf types.str;
       default = {};
-      example = {
-        MYDATABASE = 
-          ''
-          host = 10.0.2.100
-          port = 1433
-          tds version = 7.2
-          '';
-      };
+      example = literalExample ''
+        { MYDATABASE = '''
+            host = 10.0.2.100
+            port = 1433
+            tds version = 7.2
+          ''';
+        }
+      '';
       description = 
         ''
         Configure freetds database entries. Each attribute denotes
diff --git a/nixos/modules/programs/ibus.nix b/nixos/modules/programs/ibus.nix
deleted file mode 100644
index a42753a292b2..000000000000
--- a/nixos/modules/programs/ibus.nix
+++ /dev/null
@@ -1,51 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-with lib;
-
-let
-  cfg = config.programs.ibus;
-in
-{
-  options = {
-
-    programs.ibus = {
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        example = true;
-        description = "Enable IBus input method";
-      };
-      plugins = mkOption {
-        type = lib.types.listOf lib.types.path;
-        default = [];
-        description = ''
-          IBus plugin packages
-        '';
-      };
-    };
-
-  };
-
-  config = mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.ibus pkgs.gnome3.dconf ];
-
-    gtkPlugins = [ pkgs.ibus ];
-    qtPlugins = [ pkgs.ibus-qt ];
-
-    environment.variables =
-      let
-        env = pkgs.buildEnv {
-          name = "ibus-env";
-          paths = [ pkgs.ibus ] ++ cfg.plugins;
-        };
-      in {
-        GTK_IM_MODULE = "ibus";
-        QT_IM_MODULE = "ibus";
-        XMODIFIERS = "@im=ibus";
-
-        IBUS_COMPONENT_PATH = "${env}/share/ibus/component";
-      };
-
-    services.xserver.displayManager.sessionCommands = "${pkgs.ibus}/bin/ibus-daemon --daemonize --xim --cache=none";
-  };
-}
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
index 260888be485f..1ad45f468030 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -36,6 +36,7 @@ in
 
       askPassword = mkOption {
         type = types.str;
+        default = "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass";
         description = ''Program used by SSH to ask for passwords.'';
       };
 
@@ -186,6 +187,9 @@ in
 
         ForwardX11 ${if cfg.forwardX11 then "yes" else "no"}
 
+        # Allow DSA keys for now. (These were deprecated in OpenSSH 7.0.)
+        PubkeyAcceptedKeyTypes +ssh-dss
+
         ${cfg.extraConfig}
       '';
 
@@ -221,12 +225,7 @@ in
         fi
       '';
 
-    environment.interactiveShellInit = optionalString config.services.xserver.enable
-      ''
-        export SSH_ASKPASS=${askPassword}
-      '';
-
-    programs.ssh.askPassword = mkDefault "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass";
+    environment.variables.SSH_ASKPASS = optionalString config.services.xserver.enable askPassword;
 
   };
 }
diff --git a/nixos/modules/programs/uim.nix b/nixos/modules/programs/uim.nix
deleted file mode 100644
index 4bf2f9a17571..000000000000
--- a/nixos/modules/programs/uim.nix
+++ /dev/null
@@ -1,31 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-with lib;
-
-let
-  cfg = config.uim;
-in
-{
-  options = {
-
-    uim = {
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        example = true;
-        description = "Enable UIM input method";
-      };
-    };
-
-  };
-
-  config = mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.uim ];
-    gtkPlugins = [ pkgs.uim ];
-    qtPlugins = [ pkgs.uim ];
-    environment.variables.GTK_IM_MODULE = "uim";
-    environment.variables.QT_IM_MODULE = "uim";
-    environment.variables.XMODIFIERS = "@im=uim";
-    services.xserver.displayManager.sessionCommands = "uim-xim &";
-  };
-}
diff --git a/nixos/modules/programs/venus.nix b/nixos/modules/programs/venus.nix
index 8f85b602fe2c..731ebed14c7b 100644
--- a/nixos/modules/programs/venus.nix
+++ b/nixos/modules/programs/venus.nix
@@ -99,6 +99,7 @@ in
       };
 
       outputTheme = mkOption {
+        default = "${pkgs.venus}/themes/classic_fancy";
         type = types.path;
         description = ''
           Directory containing a config.ini file which is merged with this one.
@@ -165,11 +166,8 @@ in
         script = "exec venus-planet ${configFile}";
         serviceConfig.User = "${cfg.user}";
         serviceConfig.Group = "${cfg.group}";
-        environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
         startAt = cfg.dates;
       };
 
-    services.venus.outputTheme = mkDefault "${pkgs.venus}/themes/classic_fancy";
-
   };
 }
diff --git a/nixos/modules/programs/xfs_quota.nix b/nixos/modules/programs/xfs_quota.nix
index 90b6304fa999..648fd9a8a94f 100644
--- a/nixos/modules/programs/xfs_quota.nix
+++ b/nixos/modules/programs/xfs_quota.nix
@@ -89,8 +89,8 @@ in
       nameValuePair "xfs_quota-${name}" {
         description = "Setup xfs_quota for project ${name}";
         script = ''
-          ${pkgs.xfsprogs}/bin/xfs_quota -x -c 'project -s ${name}' ${opts.fileSystem}
-          ${pkgs.xfsprogs}/bin/xfs_quota -x -c 'limit -p ${limitOptions opts} ${name}' ${opts.fileSystem}
+          ${pkgs.xfsprogs.bin}/bin/xfs_quota -x -c 'project -s ${name}' ${opts.fileSystem}
+          ${pkgs.xfsprogs.bin}/bin/xfs_quota -x -c 'limit -p ${limitOptions opts} ${name}' ${opts.fileSystem}
         '';
 
         wantedBy = [ "multi-user.target" ];
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 010d44c40d19..85435884b199 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -28,6 +28,9 @@ with lib;
     (mkRenamedOptionModule [ "services" "subsonic" "host" ] [ "services" "subsonic" "listenAddress" ])
     (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ])
 
+    (mkRenamedOptionModule [ "services" "gitlab" "stateDir" ] [ "services" "gitlab" "statePath" ])
+    (mkRemovedOptionModule [ "services" "gitlab" "satelliteDir" ])
+
     # Old Grub-related options.
     (mkRenamedOptionModule [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ])
     (mkRenamedOptionModule [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ])
@@ -59,6 +62,9 @@ with lib;
     # Tarsnap
     (mkRenamedOptionModule [ "services" "tarsnap" "config" ] [ "services" "tarsnap" "archives" ])
 
+    # ibus
+    (mkRenamedOptionModule [ "programs" "ibus" "plugins" ] [ "i18n" "inputMethod" "ibus" "engines" ])
+
     # proxy
     (mkRenamedOptionModule [ "nix" "proxy" ] [ "networking" "proxy" "default" ])
 
@@ -77,6 +83,7 @@ with lib;
     (mkRenamedOptionModule [ "services" "xserver" "driSupport32Bit" ] [ "hardware" "opengl" "driSupport32Bit" ])
     (mkRenamedOptionModule [ "services" "xserver" "s3tcSupport" ] [ "hardware" "opengl" "s3tcSupport" ])
     (mkRenamedOptionModule [ "hardware" "opengl" "videoDrivers" ] [ "services" "xserver" "videoDrivers" ])
+    (mkRenamedOptionModule [ "services" "xserver" "vaapiDrivers" ] [ "hardware" "opengl" "extraPackages" ])
 
     (mkRenamedOptionModule [ "services" "mysql55" ] [ "services" "mysql" ])
 
@@ -99,6 +106,8 @@ with lib;
     (mkRemovedOptionModule [ "services" "syslog-ng" "listenToJournal" ])
     (mkRemovedOptionModule [ "ec2" "metadata" ])
     (mkRemovedOptionModule [ "services" "openvpn" "enable" ])
+    (mkRemovedOptionModule [ "services" "printing" "cupsFilesConf" ])
+    (mkRemovedOptionModule [ "services" "printing" "cupsdConf" ])
 
   ];
 }
diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix
index 15e5b49878f6..c5cd0fb60ee9 100644
--- a/nixos/modules/security/acme.nix
+++ b/nixos/modules/security/acme.nix
@@ -56,8 +56,8 @@ let
 
       plugins = mkOption {
         type = types.listOf (types.enum [
-          "cert.der" "cert.pem" "chain.der" "chain.pem" "external_pem.sh"
-          "fullchain.der" "fullchain.pem" "key.der" "key.pem" "account_key.json"
+          "cert.der" "cert.pem" "chain.pem" "external.sh"
+          "fullchain.pem" "full.pem" "key.der" "key.pem" "account_key.json"
         ]);
         default = [ "fullchain.pem" "key.pem" "account_key.json" ];
         description = ''
diff --git a/nixos/modules/security/apparmor-suid.nix b/nixos/modules/security/apparmor-suid.nix
index 3da6a81158d0..d766f6badfc7 100644
--- a/nixos/modules/security/apparmor-suid.nix
+++ b/nixos/modules/security/apparmor-suid.nix
@@ -29,8 +29,8 @@ with lib;
         network inet raw,
 
         ${pkgs.glibc.out}/lib/*.so mr,
-        ${pkgs.libcap}/lib/libcap.so* mr,
-        ${pkgs.attr}/lib/libattr.so* mr,
+        ${pkgs.libcap.out}/lib/libcap.so* mr,
+        ${pkgs.attr.out}/lib/libattr.so* mr,
 
         ${pkgs.iputils}/bin/ping mixr,
         /var/setuid-wrappers/ping.real r,
diff --git a/nixos/modules/security/audit.nix b/nixos/modules/security/audit.nix
index 3aa31e079073..f223f52ec487 100644
--- a/nixos/modules/security/audit.nix
+++ b/nixos/modules/security/audit.nix
@@ -93,9 +93,11 @@ in {
 
   config = mkIf (cfg.enable == "lock" || cfg.enable) {
     systemd.services.audit = {
-      description = "pseudo-service representing the kernel audit state";
+      description = "Kernel Auditing";
       wantedBy = [ "basic.target" ];
 
+      unitConfig.ConditionVirtualization = "!container";
+
       path = [ pkgs.audit ];
 
       serviceConfig = {
diff --git a/nixos/modules/security/ca.nix b/nixos/modules/security/ca.nix
index ddfad52d42ed..849530238e7e 100644
--- a/nixos/modules/security/ca.nix
+++ b/nixos/modules/security/ca.nix
@@ -4,7 +4,7 @@ with lib;
 
 let
 
-  caBundle = pkgs.runCommand "ca-bundle.crt"
+  caCertificates = pkgs.runCommand "ca-certificates.crt"
     { files =
         config.security.pki.certificateFiles ++
         [ (builtins.toFile "extra.crt" (concatStringsSep "\n" config.security.pki.certificates)) ];
@@ -26,7 +26,7 @@ in
       description = ''
         A list of files containing trusted root certificates in PEM
         format. These are concatenated to form
-        <filename>/etc/ssl/certs/ca-bundle.crt</filename>, which is
+        <filename>/etc/ssl/certs/ca-certificates.crt</filename>, which is
         used by many programs that use OpenSSL, such as
         <command>curl</command> and <command>git</command>.
       '';
@@ -35,14 +35,17 @@ in
     security.pki.certificates = mkOption {
       type = types.listOf types.str;
       default = [];
-      example = singleton ''
-        NixOS.org
-        =========
-        -----BEGIN CERTIFICATE-----
-        MIIGUDCCBTigAwIBAgIDD8KWMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
-        TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
-        ...
-        -----END CERTIFICATE-----
+      example = literalExample ''
+        [ '''
+            NixOS.org
+            =========
+            -----BEGIN CERTIFICATE-----
+            MIIGUDCCBTigAwIBAgIDD8KWMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
+            TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
+            ...
+            -----END CERTIFICATE-----
+          '''
+        ]
       '';
       description = ''
         A list of trusted root certificates in PEM format.
@@ -56,19 +59,13 @@ in
     security.pki.certificateFiles = [ "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" ];
 
     # NixOS canonical location + Debian/Ubuntu/Arch/Gentoo compatibility.
-    environment.etc."ssl/certs/ca-certificates.crt".source = caBundle;
+    environment.etc."ssl/certs/ca-certificates.crt".source = caCertificates;
 
     # Old NixOS compatibility.
-    environment.etc."ssl/certs/ca-bundle.crt".source = caBundle;
+    environment.etc."ssl/certs/ca-bundle.crt".source = caCertificates;
 
     # CentOS/Fedora compatibility.
-    environment.etc."pki/tls/certs/ca-bundle.crt".source = caBundle;
-
-    environment.sessionVariables =
-      { SSL_CERT_FILE          = "/etc/ssl/certs/ca-certificates.crt";
-        # FIXME: unneeded - remove eventually.
-        GIT_SSL_CAINFO         = "/etc/ssl/certs/ca-certificates.crt";
-      };
+    environment.etc."pki/tls/certs/ca-bundle.crt".source = caCertificates;
 
   };
 
diff --git a/nixos/modules/security/oath.nix b/nixos/modules/security/oath.nix
new file mode 100644
index 000000000000..20f3e2dd9f83
--- /dev/null
+++ b/nixos/modules/security/oath.nix
@@ -0,0 +1,50 @@
+# This module provides configuration for the OATH PAM modules.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  options = {
+
+    security.pam.oath = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable the OATH (one-time password) PAM module.
+        '';
+      };
+
+      digits = mkOption {
+        type = types.enum [ 6 7 8 ];
+        default = 6;
+        description = ''
+          Specify the length of the one-time password in number of
+          digits.
+        '';
+      };
+
+      window = mkOption {
+        type = types.int;
+        default = 5;
+        description = ''
+          Specify the number of one-time passwords to check in order
+          to accommodate for situations where the system and the
+          client are slightly out of sync (iteration for HOTP or time
+          steps for TOTP).
+        '';
+      };
+
+      usersFile = mkOption {
+        type = types.path;
+        default = "/etc/users.oath";
+        description = ''
+          Set the path to file where the user's credentials are
+          stored. This file must not be world readable!
+        '';
+      };
+    };
+
+  };
+}
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 2ee8a803d2fe..021c561af759 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -75,7 +75,7 @@ let
       };
 
       oathAuth = mkOption {
-        default = config.security.pam.enableOATH;
+        default = config.security.pam.oath.enable;
         type = types.bool;
         description = ''
           If set, the OATH Toolkit will be used.
@@ -259,8 +259,8 @@ let
               "auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth try_first_pass"}
           ${optionalString cfg.otpwAuth
               "auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so"}
-          ${optionalString cfg.oathAuth
-              "auth sufficient ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"}
+          ${let oath = config.security.pam.oath; in optionalString cfg.oathAuth
+              "auth sufficient ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}"}
           ${optionalString config.users.ldap.enable
               "auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass"}
           ${optionalString config.krb5.enable ''
@@ -302,8 +302,6 @@ let
               "session optional ${pam_krb5}/lib/security/pam_krb5.so"}
           ${optionalString cfg.otpwAuth
               "session optional ${pkgs.otpw}/lib/security/pam_otpw.so"}
-          ${optionalString cfg.oathAuth
-              "session optional ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"}
           ${optionalString cfg.startSession
               "session optional ${pkgs.systemd}/lib/security/pam_systemd.so"}
           ${optionalString cfg.forwardXAuth
@@ -405,13 +403,6 @@ in
       '';
     };
 
-    security.pam.enableOATH = mkOption {
-      default = false;
-      description = ''
-        Enable the OATH (one-time password) PAM module.
-      '';
-    };
-
     security.pam.enableU2F = mkOption {
       default = false;
       description = ''
@@ -446,7 +437,7 @@ in
       ++ optional config.users.ldap.enable pam_ldap
       ++ optionals config.krb5.enable [pam_krb5 pam_ccreds]
       ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ]
-      ++ optionals config.security.pam.enableOATH [ pkgs.oathToolkit ]
+      ++ optionals config.security.pam.oath.enable [ pkgs.oathToolkit ]
       ++ optionals config.security.pam.enableU2F [ pkgs.pam_u2f ]
       ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ];
 
diff --git a/nixos/modules/services/amqp/activemq/default.nix b/nixos/modules/services/amqp/activemq/default.nix
index 56ff388f8a9e..261f97617664 100644
--- a/nixos/modules/services/amqp/activemq/default.nix
+++ b/nixos/modules/services/amqp/activemq/default.nix
@@ -32,6 +32,7 @@ in {
         '';
       };
       configurationDir = mkOption {
+        default = "${activemq}/conf";
         description = ''
           The base directory for ActiveMQ's configuration.
           By default, this directory is searched for a file named activemq.xml,
@@ -125,8 +126,6 @@ in {
       '';
     };
 
-    services.activemq.configurationDir = mkDefault "${activemq}/conf";
-
   };
 
 }
diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix
index cf00d8946557..ad8836f40094 100644
--- a/nixos/modules/services/computing/slurm/slurm.nix
+++ b/nixos/modules/services/computing/slurm/slurm.nix
@@ -37,6 +37,7 @@ in
       package = mkOption {
         type = types.package;
         default = pkgs.slurm-llnl;
+        defaultText = "pkgs.slurm-llnl";
         example = literalExample "pkgs.slurm-llnl-full";
         description = ''
           The packge to use for slurm binaries.
diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix
index fb77586f6894..6fd39e68b1d9 100644
--- a/nixos/modules/services/continuous-integration/jenkins/default.nix
+++ b/nixos/modules/services/continuous-integration/jenkins/default.nix
@@ -92,11 +92,12 @@ in {
         type = with types; attrsOf str;
         description = ''
           Additional environment variables to be passed to the jenkins process.
-          As a base environment, jenkins receives NIX_PATH, SSL_CERT_FILE and
-          GIT_SSL_CAINFO from <option>environment.sessionVariables</option>,
-          NIX_REMOTE is set to "daemon" and JENKINS_HOME is set to
-          the value of <option>services.jenkins.home</option>. This option has
-          precedence and can be used to override those mentioned variables.
+          As a base environment, jenkins receives NIX_PATH from
+          <option>environment.sessionVariables</option>, NIX_REMOTE is set to
+          "daemon" and JENKINS_HOME is set to the value of
+          <option>services.jenkins.home</option>.
+          This option has precedence and can be used to override those
+          mentioned variables.
         '';
       };
 
@@ -136,11 +137,7 @@ in {
       environment =
         let
           selectedSessionVars =
-            lib.filterAttrs (n: v: builtins.elem n
-                [ "NIX_PATH"
-                  "SSL_CERT_FILE"
-                  "GIT_SSL_CAINFO"
-                ])
+            lib.filterAttrs (n: v: builtins.elem n [ "NIX_PATH" ])
               config.environment.sessionVariables;
         in
           selectedSessionVars //
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index c2045a5859c5..31ffe51c11ef 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -158,7 +158,7 @@ in
       # Note: when changing the default, make it conditional on
       # ‘system.stateVersion’ to maintain compatibility with existing
       # systems!
-      mkDefault pkgs.postgresql94;
+      mkDefault (if versionAtLeast config.system.stateVersion "16.03" then pkgs.postgresql95 else pkgs.postgresql94);
 
     services.postgresql.authentication = mkAfter
       ''
@@ -177,7 +177,7 @@ in
 
     users.extraGroups.postgres.gid = config.ids.gids.postgres;
 
-    environment.systemPackages = [postgresql];
+    environment.systemPackages = [ postgresql ];
 
     systemd.services.postgresql =
       { description = "PostgreSQL Server";
@@ -187,35 +187,37 @@ in
 
         environment.PGDATA = cfg.dataDir;
 
-        path = [ pkgs.su postgresql ];
+        path = [ postgresql ];
 
         preStart =
           ''
-            # Initialise the database.
+            # Create data directory.
             if ! test -e ${cfg.dataDir}/PG_VERSION; then
-                mkdir -m 0700 -p ${cfg.dataDir}
-                rm -f ${cfg.dataDir}/*.conf
-                if [ "$(id -u)" = 0 ]; then
-                  chown -R postgres ${cfg.dataDir}
-                  su -s ${pkgs.stdenv.shell} postgres -c 'initdb -U root'
-                else
-                  # For non-root operation.
-                  initdb
-                fi
-                # See postStart!
-                touch "${cfg.dataDir}/.first_startup"
+              mkdir -m 0700 -p ${cfg.dataDir}
+              rm -f ${cfg.dataDir}/*.conf
+              chown -R postgres:postgres ${cfg.dataDir}
             fi
+          ''; # */
 
+        script =
+          ''
+            # Initialise the database.
+            if ! test -e ${cfg.dataDir}/PG_VERSION; then
+              initdb -U root
+              # See postStart!
+              touch "${cfg.dataDir}/.first_startup"
+            fi
             ln -sfn "${configFile}" "${cfg.dataDir}/postgresql.conf"
             ${optionalString (cfg.recoveryConfig != null) ''
               ln -sfn "${pkgs.writeText "recovery.conf" cfg.recoveryConfig}" \
                 "${cfg.dataDir}/recovery.conf"
             ''}
-          ''; # */
+
+             exec postgres ${toString flags}
+          '';
 
         serviceConfig =
-          { ExecStart = "@${postgresql}/bin/postgres postgres ${toString flags}";
-            ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+          { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
             User = "postgres";
             Group = "postgres";
             PermissionsStartOnly = true;
diff --git a/nixos/modules/services/hardware/acpid.nix b/nixos/modules/services/hardware/acpid.nix
index 48b2b6be09ed..bb17c8859d84 100644
--- a/nixos/modules/services/hardware/acpid.nix
+++ b/nixos/modules/services/hardware/acpid.nix
@@ -4,111 +4,38 @@ with lib;
 
 let
 
-  acpiConfDir = pkgs.runCommand "acpi-events" {}
-    ''
-      mkdir -p $out
-      ${
-        # Generate a configuration file for each event. (You can't have
-        # multiple events in one config file...)
-        let f = event:
-          ''
-            fn=$out/${event.name}
-            echo "event=${event.event}" > $fn
-            echo "action=${pkgs.writeScript "${event.name}.sh" event.action}" >> $fn
-          '';
-        in lib.concatMapStrings f events
-      }
-    '';
-
-  events = [powerEvent lidEvent acEvent muteEvent volumeDownEvent volumeUpEvent cdPlayEvent cdNextEvent cdPrevEvent];
-
-  # Called when the power button is pressed.
-  powerEvent =
-    { name = "power-button";
+  canonicalHandlers = {
+    powerEvent = {
       event = "button/power.*";
-      action =
-        ''
-          #! ${pkgs.bash}/bin/sh
-          ${config.services.acpid.powerEventCommands}
-        '';
+      action = config.services.acpid.powerEventCommands;
     };
 
-  # Called when the laptop lid is opened/closed.
-  lidEvent =
-    { name = "lid";
+    lidEvent = {
       event = "button/lid.*";
-      action =
-        ''
-          #! ${pkgs.bash}/bin/sh
-          ${config.services.acpid.lidEventCommands}
-        '';
+      action = config.services.acpid.lidEventCommands;
     };
 
-  # Called when the AC power is connected or disconnected.
-  acEvent =
-    { name = "ac-power";
+    acEvent = {
       event = "ac_adapter.*";
-      action =
-        ''
-          #! ${pkgs.bash}/bin/sh
-          ${config.services.acpid.acEventCommands}
-        '';
+      action = config.services.acpid.acEventCommands;
     };
-
-  muteEvent = {
-    name = "mute";
-    event = "button/mute.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.muteCommands}
-    '';
-  };
-
-  volumeDownEvent = {
-    name = "volume-down";
-    event = "button/volumedown.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.volumeDownEventCommands}
-    '';
   };
 
-  volumeUpEvent = {
-    name = "volume-up";
-    event = "button/volumeup.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.volumeUpEventCommands}
-    '';
-  };
-
-  cdPlayEvent = {
-    name = "cd-play";
-    event = "cd/play.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.cdPlayEventCommands}
-    '';
-  };
-
-  cdNextEvent = {
-    name = "cd-next";
-    event = "cd/next.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.cdNextEventCommands}
-    '';
-  };
-
-  cdPrevEvent = {
-    name = "cd-prev";
-    event = "cd/prev.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.cdPrevEventCommands}
+  acpiConfDir = pkgs.runCommand "acpi-events" {}
+    ''
+      mkdir -p $out
+      ${
+        # Generate a configuration file for each event. (You can't have
+        # multiple events in one config file...)
+        let f = name: handler:
+          ''
+            fn=$out/${name}
+            echo "event=${handler.event}" > $fn
+            echo "action=${pkgs.writeScript "${name}.sh" (concatStringsSep "\n" [ "#! ${pkgs.bash}/bin/sh" handler.action ])}" >> $fn
+          '';
+        in concatStringsSep "\n" (mapAttrsToList f (canonicalHandlers // config.services.acpid.handlers))
+      }
     '';
-  };
-
 
 in
 
@@ -126,58 +53,45 @@ in
         description = "Whether to enable the ACPI daemon.";
       };
 
-      powerEventCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on a button/power.* event.";
-      };
+      handlers = mkOption {
+        type = types.attrsOf (types.submodule {
+          options = {
+            event = mkOption {
+              type = types.str;
+              example = [ "button/power.*" "button/lid.*" "ac_adapter.*" "button/mute.*" "button/volumedown.*" "cd/play.*" "cd/next.*" ];
+              description = "Event type.";
+            };
 
-      lidEventCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on a button/lid.* event.";
-      };
+            action = mkOption {
+              type = types.lines;
+              description = "Shell commands to execute when the event is triggered.";
+            };
+          };
+        });
 
-      acEventCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on an ac_adapter.* event.";
-      };
-
-      muteCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on an button/mute.* event.";
-      };
+        description = "Event handlers.";
+        default = {};
+        example = { mute = { event = "button/mute.*"; action = "amixer set Master toggle"; }; };
 
-      volumeDownEventCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on an button/volumedown.* event.";
-      };
 
-      volumeUpEventCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on an button/volumeup.* event.";
       };
 
-      cdPlayEventCommands = mkOption {
+      powerEventCommands = mkOption {
         type = types.lines;
         default = "";
-        description = "Shell commands to execute on an cd/play.* event.";
+        description = "Shell commands to execute on a button/power.* event.";
       };
 
-      cdNextEventCommands = mkOption {
+      lidEventCommands = mkOption {
         type = types.lines;
         default = "";
-        description = "Shell commands to execute on an cd/next.* event.";
+        description = "Shell commands to execute on a button/lid.* event.";
       };
 
-      cdPrevEventCommands = mkOption {
+      acEventCommands = mkOption {
         type = types.lines;
         default = "";
-        description = "Shell commands to execute on an cd/prev.* event.";
+        description = "Shell commands to execute on an ac_adapter.* event.";
       };
 
     };
diff --git a/nixos/modules/services/hardware/bluetooth.nix b/nixos/modules/services/hardware/bluetooth.nix
index 68d0406e63bd..fc95c4910bf7 100644
--- a/nixos/modules/services/hardware/bluetooth.nix
+++ b/nixos/modules/services/hardware/bluetooth.nix
@@ -1,6 +1,43 @@
 { config, lib, pkgs, ... }:
 
 with lib;
+let
+    bluez-bluetooth = if config.services.xserver.desktopManager.kde4.enable then pkgs.bluez else pkgs.bluez5;
+
+    configBluez = {
+        description = "Bluetooth Service";
+        serviceConfig = {
+          Type = "dbus";
+          BusName = "org.bluez";
+          ExecStart = "${bluez-bluetooth}/sbin/bluetoothd -n";
+        };
+        wantedBy = [ "bluetooth.target" ];
+    };
+
+    configBluez5 =  {
+        description = "Bluetooth Service";
+        serviceConfig = {
+          Type = "dbus";
+          BusName = "org.bluez";
+          ExecStart = "${bluez-bluetooth}/sbin/bluetoothd -n";
+          NotifyAccess="main";
+          CapabilityBoundingSet="CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
+          LimitNPROC=1;
+        };
+        wantedBy = [ "bluetooth.target" ];
+    };
+
+    obexConfig = {
+        description = "Bluetooth OBEX service";
+        serviceConfig = {
+          Type = "dbus";
+          BusName = "org.bluez.obex";
+          ExecStart = "${bluez-bluetooth}/sbin/obexd";
+        };
+    };
+
+    bluezConfig = if config.services.xserver.desktopManager.kde4.enable then configBluez else configBluez5;
+in
 
 {
 
@@ -16,26 +53,15 @@ with lib;
 
   };
 
-
   ###### implementation
-
+  
   config = mkIf config.hardware.bluetooth.enable {
 
-    environment.systemPackages = [ pkgs.bluez pkgs.openobex pkgs.obexftp ];
-
-    services.udev.packages = [ pkgs.bluez ];
-
-    services.dbus.packages = [ pkgs.bluez ];
-
-    systemd.services."dbus-org.bluez" = {
-      description = "Bluetooth Service";
-      serviceConfig = {
-        Type = "dbus";
-        BusName = "org.bluez";
-        ExecStart = "${pkgs.bluez}/sbin/bluetoothd -n";
-      };
-      wantedBy = [ "bluetooth.target" ];
-    };
+    environment.systemPackages = [ bluez-bluetooth pkgs.openobex pkgs.obexftp ];
+    services.udev.packages = [ bluez-bluetooth ];
+    services.dbus.packages = [ bluez-bluetooth ];
+    systemd.services."dbus-org.bluez" = bluezConfig;
+    systemd.services."dbus-org.bluez.obex" = obexConfig;
 
   };
 
diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix
index 56504cd2361d..a34037403123 100644
--- a/nixos/modules/services/hardware/sane.nix
+++ b/nixos/modules/services/hardware/sane.nix
@@ -21,7 +21,13 @@ in
     hardware.sane.enable = mkOption {
       type = types.bool;
       default = false;
-      description = "Enable support for SANE scanners.";
+      description = ''
+        Enable support for SANE scanners.
+
+        <note><para>
+          Users in the "scanner" group will gain access to the scanner.
+        </para></note>
+      '';
     };
 
     hardware.sane.snapshot = mkOption {
@@ -33,7 +39,14 @@ in
     hardware.sane.extraBackends = mkOption {
       type = types.listOf types.path;
       default = [];
-      description = "Packages providing extra SANE backends to enable.";
+      description = ''
+        Packages providing extra SANE backends to enable.
+
+        <note><para>
+          The example contains the package for HP scanners.
+        </para></note>
+      '';
+      example = literalExample "[ pkgs.hplipWithPlugin ]";
     };
 
     hardware.sane.configDir = mkOption {
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 107e1012b88d..8e883ed7775f 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -13,7 +13,13 @@ let
   extraUdevRules = pkgs.writeTextFile {
     name = "extra-udev-rules";
     text = cfg.extraRules;
-    destination = "/etc/udev/rules.d/10-local.rules";
+    destination = "/etc/udev/rules.d/99-local.rules";
+  };
+
+  extraHwdbFile = pkgs.writeTextFile {
+    name = "extra-hwdb-file";
+    text = cfg.extraHwdb;
+    destination = "/etc/udev/hwdb.d/99-local.hwdb";
   };
 
   nixosRules = ''
@@ -55,7 +61,9 @@ let
           --replace \"/sbin/modprobe \"${config.system.sbin.modprobe}/sbin/modprobe \
           --replace \"/sbin/mdadm \"${pkgs.mdadm}/sbin/mdadm \
           --replace \"/sbin/blkid \"${pkgs.utillinux}/sbin/blkid \
-          --replace \"/bin/mount \"${pkgs.utillinux}/bin/mount
+          --replace \"/bin/mount \"${pkgs.utillinux}/bin/mount \
+          --replace /usr/bin/readlink ${pkgs.coreutils}/bin/readlink \
+          --replace /usr/bin/basename ${pkgs.coreutils}/bin/basename
       done
 
       echo -n "Checking that all programs called by relative paths in udev rules exist in ${udev}/lib/udev... "
@@ -86,10 +94,30 @@ let
       done
       echo "OK"
 
-      echo "Consider fixing the following udev rules:"
-      for i in ${toString cfg.packages}; do
-        grep -l '\(RUN+\|IMPORT{program}\)="\(/usr\)\?/s\?bin' $i/*/udev/rules.d/* || true
-      done
+      filesToFixup="$(for i in "$out"/*; do
+        grep -l '\B\(/usr\)\?/s\?bin' "$i" || :
+      done)"
+
+      if [ -n "$filesToFixup" ]; then
+        echo "Consider fixing the following udev rules:"
+        echo "$filesToFixup" | while read localFile; do
+          remoteFile="origin unknown"
+          for i in ${toString cfg.packages}; do
+            for j in "$i"/*/udev/rules.d/*; do
+              [ -e "$out/$(basename "$j")" ] || continue
+              [ "$(basename "$j")" = "$(basename "$localFile")" ] || continue
+              remoteFile="originally from $j"
+              break 2
+            done
+          done
+          refs="$(
+            grep -o '\B\(/usr\)\?/s\?bin/[^ "]\+' "$localFile" \
+              | sed -e ':r;N;''${s/\n/ and /;br};s/\n/, /g;br'
+          )"
+          echo "$localFile ($remoteFile) contains references to $refs."
+        done
+        exit 1
+      fi
 
       ${optionalString config.networking.usePredictableInterfaceNames ''
         cp ${./80-net-setup-link.rules} $out/80-net-setup-link.rules
@@ -104,6 +132,27 @@ let
     ''; # */
   };
 
+  hwdbBin = stdenv.mkDerivation {
+    name = "hwdb.bin";
+
+    preferLocalBuild = true;
+    allowSubstitutes = false;
+
+    buildCommand = ''
+      mkdir -p etc/udev/hwdb.d
+      for i in ${toString ([udev] ++ cfg.packages)}; do
+        echo "Adding hwdb files for package $i"
+        for j in $i/{etc,lib}/udev/hwdb.d/*; do
+          ln -s $j etc/udev/hwdb.d/$(basename $j)
+        done
+      done
+
+      echo "Generating hwdb database..."
+      ${udev}/bin/udevadm hwdb --update --root=$(pwd)
+      mv etc/udev/hwdb.bin $out
+    '';
+  };
+
   # Udev has a 512-character limit for ENV{PATH}, so create a symlink
   # tree to work around this.
   udevPath = pkgs.buildEnv {
@@ -163,8 +212,23 @@ in
         type = types.lines;
         description = ''
           Additional <command>udev</command> rules. They'll be written
-          into file <filename>10-local.rules</filename>. Thus they are
-          read before all other rules.
+          into file <filename>99-local.rules</filename>. Thus they are
+          read and applied after all other rules.
+        '';
+      };
+
+      extraHwdb = mkOption {
+        default = "";
+        example = ''
+          evdev:input:b0003v05AFp8277*
+            KEYBOARD_KEY_70039=leftalt
+            KEYBOARD_KEY_700e2=leftctrl
+        '';
+        type = types.lines;
+        description = ''
+          Additional <command>hwdb</command> files. They'll be written
+          into file <filename>10-local.hwdb</filename>. Thus they are
+          read before all other files.
         '';
       };
 
@@ -216,7 +280,7 @@ in
 
     services.udev.extraRules = nixosRules;
 
-    services.udev.packages = [ extraUdevRules ];
+    services.udev.packages = [ extraUdevRules extraHwdbFile ];
 
     services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.utillinux udev ];
 
@@ -224,6 +288,9 @@ in
       [ { source = udevRules;
           target = "udev/rules.d";
         }
+        { source = hwdbBin;
+          target = "udev/hwdb.bin";
+        }
       ];
 
     system.requiredKernelConfig = with config.lib.kernelConfig; [
@@ -241,13 +308,6 @@ in
           echo "" > /proc/sys/kernel/hotplug
         fi
 
-        # Regenerate the hardware database /var/lib/udev/hwdb.bin
-        # whenever systemd changes.
-        if [ ! -e /var/lib/udev/prev-systemd -o "$(readlink /var/lib/udev/prev-systemd)" != ${config.systemd.package} ]; then
-          echo "regenerating udev hardware database..."
-          ${config.systemd.package}/bin/udevadm hwdb --update && ln -sfn ${config.systemd.package} /var/lib/udev/prev-systemd
-        fi
-
         # Allow the kernel to find our firmware.
         if [ -e /sys/module/firmware_class/parameters/path ]; then
           echo -n "${config.hardware.firmware}/lib/firmware" > /sys/module/firmware_class/parameters/path
@@ -256,6 +316,7 @@ in
 
     systemd.services.systemd-udevd =
       { environment.MODULE_DIR = "/run/booted-system/kernel-modules/lib/modules";
+        restartTriggers = cfg.packages;
       };
 
   };
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index 36bdcaca47a3..3935c14dc8cc 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -9,16 +9,11 @@ let
   baseDir = "/run/dovecot2";
   stateDir = "/var/lib/dovecot";
 
-  protocols = concatStrings [
-    (optionalString cfg.enableImap "imap")
-    (optionalString cfg.enablePop3 "pop3")
-    (optionalString cfg.enableLmtp "lmtp")
-  ];
-
   dovecotConf = concatStrings [
     ''
       base_dir = ${baseDir}
-      protocols = ${protocols}
+      protocols = ${concatStringsSep " " cfg.protocols}
+      sendmail_path = /var/setuid-wrappers/sendmail
     ''
 
     (if isNull cfg.sslServerCert then ''
@@ -33,6 +28,8 @@ let
 
     ''
       default_internal_user = ${cfg.user}
+      ${optionalString (cfg.mailUser != null) "mail_uid = ${cfg.mailUser}"}
+      ${optionalString (cfg.mailGroup != null) "mail_gid = ${cfg.mailGroup}"}
 
       mail_location = ${cfg.mailLocation}
 
@@ -57,11 +54,17 @@ let
       }
     '')
 
+    (optionalString (cfg.sieveScripts != {}) ''
+      plugin {
+        ${concatStringsSep "\n" (mapAttrsToList (to: from: "sieve_${to} = ${stateDir}/sieve/${to}") cfg.sieveScripts)}
+      }
+    '')
+
     cfg.extraConfig
   ];
 
   modulesDir = pkgs.symlinkJoin "dovecot-modules"
-    (map (module: "${module}/lib/dovecot") cfg.modules);
+    (map (pkg: "${pkg}/lib/dovecot") ([ dovecotPkg ] ++ map (module: module.override { dovecot = dovecotPkg; }) cfg.modules));
 
 in
 {
@@ -87,6 +90,12 @@ in
       description = "Start the LMTP listener (when Dovecot is enabled).";
     };
 
+    protocols = mkOption {
+      type = types.listOf types.str;
+      default = [ ];
+      description = "Additional listeners to start when Dovecot is enabled.";
+    };
+
     package = mkOption {
       type = types.package;
       default = pkgs.dovecot22;
@@ -129,13 +138,25 @@ in
       '';
     };
 
+    mailUser = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = "Default user to store mail for virtual users.";
+    };
+
+    mailGroup = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = "Default group to store mail for virtual users.";
+    };
+
     modules = mkOption {
       type = types.listOf types.package;
       default = [];
       example = literalExample "[ pkgs.dovecot_pigeonhole ]";
       description = ''
         Symlinks the contents of lib/dovecot of every given package into
-        /var/lib/dovecot/modules. This will make the given modules available
+        /etc/dovecot/modules. This will make the given modules available
         if a dovecot package with the module_dir patch applied (like
         pkgs.dovecot22, the default) is being used.
       '';
@@ -162,7 +183,13 @@ in
     enablePAM = mkOption {
       type = types.bool;
       default = true;
-      description = "Wether to create a own Dovecot PAM service and configure PAM user logins.";
+      description = "Whether to create a own Dovecot PAM service and configure PAM user logins.";
+    };
+
+    sieveScripts = mkOption {
+      type = types.attrsOf types.path;
+      default = {};
+      description = "Sieve scripts to be executed. Key is a sequence, e.g. 'before2', 'after' etc.";
     };
 
     showPAMFailure = mkOption {
@@ -177,23 +204,31 @@ in
 
     security.pam.services.dovecot2 = mkIf cfg.enablePAM {};
 
+    services.dovecot2.protocols =
+     optional cfg.enableImap "imap"
+     ++ optional cfg.enablePop3 "pop3"
+     ++ optional cfg.enableLmtp "lmtp";
+
     users.extraUsers = [
-      { name = cfg.user;
-        uid = config.ids.uids.dovecot2;
-        description = "Dovecot user";
-        group = cfg.group;
-      }
       { name = "dovenull";
         uid = config.ids.uids.dovenull2;
         description = "Dovecot user for untrusted logins";
         group = cfg.group;
       }
-    ];
+    ] ++ optional (cfg.user == "dovecot2")
+         { name = "dovecot2";
+           uid = config.ids.uids.dovecot2;
+           description = "Dovecot user";
+           group = cfg.group;
+         };
+
+    users.extraGroups = optional (cfg.group == "dovecot2")
+      { name = "dovecot2";
+        gid = config.ids.gids.dovecot2;
+      };
 
-    users.extraGroups = singleton {
-      name = cfg.group;
-      gid = config.ids.gids.dovecot2;
-    };
+    environment.etc."dovecot/modules".source = modulesDir;
+    environment.etc."dovecot/dovecot.conf".source = cfg.configFile;
 
     systemd.services.dovecot2 = {
       description = "Dovecot IMAP/POP3 server";
@@ -201,26 +236,38 @@ in
       after = [ "keys.target" "network.target" ];
       wants = [ "keys.target" ];
       wantedBy = [ "multi-user.target" ];
-
-      preStart = ''
-        mkdir -p "${baseDir}/login"
-        chown -R ${cfg.user}:${cfg.group} "${baseDir}"
-        rm -f "${stateDir}/modules"
-        ln -s "${modulesDir}" "${stateDir}/modules"
-      '';
+      restartTriggers = [ cfg.configFile ];
 
       serviceConfig = {
-        ExecStart = "${dovecotPkg}/sbin/dovecot -F -c ${cfg.configFile}";
+        ExecStart = "${dovecotPkg}/sbin/dovecot -F";
+        ExecReload = "${dovecotPkg}/sbin/doveadm reload";
         Restart = "on-failure";
         RestartSec = "1s";
         StartLimitInterval = "1min";
+        RuntimeDirectory = [ "dovecot2" ];
       };
+
+      preStart = ''
+        rm -rf ${stateDir}/sieve
+      '' + optionalString (cfg.sieveScripts != {}) ''
+        mkdir -p ${stateDir}/sieve
+        ${concatStringsSep "\n" (mapAttrsToList (to: from: ''
+          if [ -d '${from}' ]; then
+            mkdir '${stateDir}/sieve/${to}'
+            cp "${from}/"*.sieve '${stateDir}/sieve/${to}'
+          else
+            cp '${from}' '${stateDir}/sieve/${to}'
+          fi
+           ${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/sieve/${to}'
+        '') cfg.sieveScripts)}
+        chown -R '${cfg.mailUser}:${cfg.mailGroup}' '${stateDir}/sieve'
+      '';
     };
 
     environment.systemPackages = [ dovecotPkg ];
 
     assertions = [
-      { assertion = cfg.enablePop3 || cfg.enableImap;
+      { assertion = intersectLists cfg.protocols [ "pop3" "imap" ] != [];
         message = "dovecot needs at least one of the IMAP or POP3 listeners enabled";
       }
       { assertion = isNull cfg.sslServerCert == isNull cfg.sslServerKey
diff --git a/nixos/modules/services/mail/dspam.nix b/nixos/modules/services/mail/dspam.nix
index 10352ba6abcc..46e6f216b21e 100644
--- a/nixos/modules/services/mail/dspam.nix
+++ b/nixos/modules/services/mail/dspam.nix
@@ -19,7 +19,10 @@ let
     SystemLog on
     UserLog on
 
-    ${optionalString (cfg.domainSocket != null) ''ServerDomainSocketPath "${cfg.domainSocket}"''}
+    ${optionalString (cfg.domainSocket != null) ''
+      ServerDomainSocketPath "${cfg.domainSocket}"
+      ClientHost "${cfg.domainSocket}"
+    ''}
 
     ${cfg.extraConfig}
   '';
@@ -108,7 +111,11 @@ in {
           User = cfg.user;
           Group = cfg.group;
           RuntimeDirectory = optional (cfg.domainSocket == defaultSock) "dspam";
+          RuntimeDirectoryMode = optional (cfg.domainSocket == defaultSock) "0750";
           PermissionsStartOnly = true;
+          # DSPAM segfaults on just about every error
+          Restart = "on-failure";
+          RestartSec = "1s";
         };
 
         preStart = ''
@@ -136,7 +143,7 @@ in {
         restartTriggers = [ cfgfile ];
 
         serviceConfig = {
-          ExecStart = "${dspam}/bin/dspam_maintenance";
+          ExecStart = "${dspam}/bin/dspam_maintenance --verbose";
           Type = "oneshot";
           User = cfg.user;
           Group = cfg.group;
diff --git a/nixos/modules/services/mail/opendkim.nix b/nixos/modules/services/mail/opendkim.nix
index 1cdae9cb6548..af996758f41f 100644
--- a/nixos/modules/services/mail/opendkim.nix
+++ b/nixos/modules/services/mail/opendkim.nix
@@ -49,7 +49,12 @@ in {
 
       domains = mkOption {
         type = types.str;
-        description = "Local domains set; messages from them are signed, not verified.";
+        default = "csl:${config.networking.hostName}";
+        example = "csl:example.com,mydomain.net";
+        description = ''
+          Local domains set (see <literal>opendkim(8)</literal> for more information on datasets).
+          Messages from them are signed, not verified.
+        '';
       };
 
       keyFile = mkOption {
@@ -77,8 +82,6 @@ in {
 
   config = mkIf cfg.enable {
 
-    services.opendkim.domains = mkDefault "csl:${config.networking.hostName}";
-
     users.extraUsers = optionalAttrs (cfg.user == "opendkim") (singleton
       { name = "opendkim";
         group = cfg.group;
diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix
index a1cfd84365a2..42a1244cde57 100644
--- a/nixos/modules/services/mail/opensmtpd.nix
+++ b/nixos/modules/services/mail/opensmtpd.nix
@@ -9,6 +9,11 @@ let
   conf = writeText "smtpd.conf" cfg.serverConfiguration;
   args = concatStringsSep " " cfg.extraServerArgs;
 
+  sendmail = pkgs.runCommand "opensmtpd-sendmail" {} ''
+    mkdir -p $out/bin
+    ln -s ${opensmtpd}/sbin/smtpctl $out/bin/sendmail
+  '';
+
 in {
 
   ###### interface
@@ -23,6 +28,15 @@ in {
         description = "Whether to enable the OpenSMTPD server.";
       };
 
+      addSendmailToSystemPath = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to add OpenSMTPD's sendmail binary to the
+          system path or not.
+        '';
+      };
+
       extraServerArgs = mkOption {
         type = types.listOf types.str;
         default = [];
@@ -64,7 +78,7 @@ in {
 
   ###### implementation
 
-  config = mkIf config.services.opensmtpd.enable {
+  config = mkIf cfg.enable {
     users.extraGroups = {
       smtpd.gid = config.ids.gids.smtpd;
       smtpq.gid = config.ids.gids.smtpq;
@@ -98,9 +112,6 @@ in {
       environment.OPENSMTPD_PROC_PATH = "${procEnv}/libexec/opensmtpd";
     };
 
-    environment.systemPackages = [ (pkgs.runCommand "opensmtpd-sendmail" {} ''
-      mkdir -p $out/bin
-      ln -s ${opensmtpd}/sbin/smtpctl $out/bin/sendmail
-    '') ];
+    environment.systemPackages = mkIf cfg.addSendmailToSystemPath [ sendmail ];
   };
 }
diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix
index 6c5d7e92702b..404cdf0f564b 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -13,6 +13,18 @@ let
   haveTransport = cfg.transport != "";
   haveVirtual = cfg.virtual != "";
 
+  clientAccess =
+    if (cfg.dnsBlacklistOverrides != "")
+    then [ "check_client_access hash:/etc/postfix/client_access" ]
+    else [];
+
+  dnsBl =
+    if (cfg.dnsBlacklists != [])
+    then [ (concatStringsSep ", " (map (s: "reject_rbl_client " + s) cfg.dnsBlacklists)) ]
+    else [];
+
+  clientRestrictions = concatStringsSep ", " (clientAccess ++ dnsBl);
+
   mainCf =
     ''
       compatibility_level = 2
@@ -20,6 +32,23 @@ let
       mail_owner = ${user}
       default_privs = nobody
 
+      # NixOS specific locations
+      data_directory = /var/lib/postfix/data
+      queue_directory = /var/lib/postfix/queue
+
+      # Default location of everything in package
+      meta_directory = ${pkgs.postfix}/etc/postfix
+      command_directory = ${pkgs.postfix}/bin
+      sample_directory = /etc/postfix
+      newaliases_path = ${pkgs.postfix}/bin/newaliases
+      mailq_path = ${pkgs.postfix}/bin/mailq
+      readme_directory = no
+      sendmail_path = ${pkgs.postfix}/bin/sendmail
+      daemon_directory = ${pkgs.postfix}/libexec/postfix
+      manpage_directory = ${pkgs.postfix}/share/man
+      html_directory = ${pkgs.postfix}/share/postfix/doc/html
+      shlib_directory = no
+
     ''
     + optionalString config.networking.enableIPv6 ''
       inet_protocols = all
@@ -87,6 +116,9 @@ let
     + optionalString haveVirtual ''
       virtual_alias_maps = hash:/etc/postfix/virtual
     ''
+    + optionalString (cfg.dnsBlacklists != []) ''
+      smtpd_client_restrictions = ${clientRestrictions}
+    ''
     + cfg.extraConfig;
 
   masterCf = ''
@@ -144,6 +176,7 @@ let
 
   aliasesFile = pkgs.writeText "postfix-aliases" aliases;
   virtualFile = pkgs.writeText "postfix-virtual" cfg.virtual;
+  checkClientAccessFile = pkgs.writeText "postfix-check-client-access" cfg.dnsBlacklistOverrides;
   mainCfFile = pkgs.writeText "postfix-main.cf" mainCf;
   masterCfFile = pkgs.writeText "postfix-master.cf" masterCf;
   transportFile = pkgs.writeText "postfix-transport" cfg.transport;
@@ -349,6 +382,17 @@ in
         ";
       };
 
+      dnsBlacklists = mkOption {
+        default = [];
+        type = with types; listOf string;
+        description = "dns blacklist servers to use with smtpd_client_restrictions";
+      };
+
+      dnsBlacklistOverrides = mkOption {
+        default = "";
+        description = "contents of check_client_access for overriding dnsBlacklists";
+      };
+
       extraMasterConf = mkOption {
         type = types.lines;
         default = "";
@@ -435,31 +479,35 @@ in
               mkdir -p /var/lib
               mv /var/postfix /var/lib/postfix
             fi
-            mkdir -p /var/lib/postfix/data /var/lib/postfix/queue/{pid,public,maildrop}
 
-            chown -R ${user}:${group} /var/lib/postfix
-            chown root /var/lib/postfix/queue
-            chown root /var/lib/postfix/queue/pid
-            chgrp -R ${setgidGroup} /var/lib/postfix/queue/{public,maildrop}
-            chmod 770 /var/lib/postfix/queue/{public,maildrop}
+            # All permissions set according ${pkgs.postfix}/etc/postfix/postfix-files script
+            mkdir -p /var/lib/postfix /var/lib/postfix/queue/{pid,public,maildrop}
+            chmod 0755 /var/lib/postfix
+            chown root:root /var/lib/postfix
 
             rm -rf /var/lib/postfix/conf
             mkdir -p /var/lib/postfix/conf
+            chmod 0755 /var/lib/postfix/conf
+            ln -sf ${pkgs.postfix}/etc/postfix/postfix-files /var/lib/postfix/conf/postfix-files
             ln -sf ${mainCfFile} /var/lib/postfix/conf/main.cf
             ln -sf ${masterCfFile} /var/lib/postfix/conf/master.cf
+
             ${concatStringsSep "\n" (mapAttrsToList (to: from: ''
               ln -sf ${from} /var/lib/postfix/conf/${to}
-              postalias /var/lib/postfix/conf/${to}
+              ${pkgs.postfix}/bin/postalias /var/lib/postfix/conf/${to}
             '') cfg.aliasFiles)}
             ${concatStringsSep "\n" (mapAttrsToList (to: from: ''
               ln -sf ${from} /var/lib/postfix/conf/${to}
-              postmap /var/lib/postfix/conf/${to}
+              ${pkgs.postfix}/bin/postmap /var/lib/postfix/conf/${to}
             '') cfg.mapFiles)}
 
             mkdir -p /var/spool/mail
             chown root:root /var/spool/mail
             chmod a+rwxt /var/spool/mail
             ln -sf /var/spool/mail /var/
+
+            #Finally delegate to postfix checking remain directories in /var/lib/postfix and set permissions on them
+            ${pkgs.postfix}/bin/postfix set-permissions config_directory=/var/lib/postfix/conf
           '';
         };
     }
@@ -473,6 +521,9 @@ in
     (mkIf haveVirtual {
       services.postfix.mapFiles."virtual" = virtualFile;
     })
+    (mkIf (cfg.dnsBlacklists != []) {
+      services.postfix.mapFiles."client_access" = checkClientAccessFile;
+    })
   ]);
 
 }
diff --git a/nixos/modules/services/mail/postsrsd.nix b/nixos/modules/services/mail/postsrsd.nix
index 36a0f8218d88..68a4c1012064 100644
--- a/nixos/modules/services/mail/postsrsd.nix
+++ b/nixos/modules/services/mail/postsrsd.nix
@@ -95,7 +95,11 @@ in {
       preStart = ''
         if [ ! -e "${cfg.secretsFile}" ]; then
           echo "WARNING: secrets file not found, autogenerating!"
-          mkdir -p -m750 "$(dirname "${cfg.secretsFile}")"
+          DIR="$(dirname "${cfg.secretsFile}")"
+          if [ ! -d "$DIR" ]; then
+            mkdir -p -m750 "$DIR"
+            chown "${cfg.user}:${cfg.group}" "$DIR"
+          fi
           dd if=/dev/random bs=18 count=1 | base64 > "${cfg.secretsFile}"
           chmod 600 "${cfg.secretsFile}"
         fi
diff --git a/nixos/modules/services/misc/bepasty.nix b/nixos/modules/services/misc/bepasty.nix
index 12671cb1b6cd..5bda73ab64f0 100644
--- a/nixos/modules/services/misc/bepasty.nix
+++ b/nixos/modules/services/misc/bepasty.nix
@@ -103,9 +103,13 @@ in
           after = [ "network.target" ];
           restartIfChanged = true;
 
-          environment = {
+          environment = let
+            penv = python.buildEnv.override {
+              extraLibs = [ bepasty gevent ];
+            };
+          in {
             BEPASTY_CONFIG = "${server.workDir}/bepasty-${name}.conf";
-            PYTHONPATH= "${bepasty}/lib/${python.libPrefix}/site-packages:${gevent}/lib/${python.libPrefix}/site-packages";
+            PYTHONPATH= "${penv}/${python.sitePackages}/";
           };
 
           serviceConfig = {
diff --git a/nixos/modules/services/misc/cfdyndns.nix b/nixos/modules/services/misc/cfdyndns.nix
new file mode 100644
index 000000000000..69a33d0b8c1b
--- /dev/null
+++ b/nixos/modules/services/misc/cfdyndns.nix
@@ -0,0 +1,70 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.cfdyndns;
+in
+{
+  options = {
+    services.cfdyndns = {
+      enable = mkEnableOption "Cloudflare Dynamic DNS Client";
+
+      email = mkOption {
+        type = types.str;
+        description = ''
+          The email address to use to authenticate to CloudFlare.
+        '';
+      };
+
+      apikey = mkOption {
+        type = types.str;
+        description = ''
+          The API Key to use to authenticate to CloudFlare.
+        '';
+      };
+
+      records = mkOption {
+        default = [];
+        example = [ "host.tld" ];
+        type = types.listOf types.str;
+        description = ''
+          The records to update in CloudFlare.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.cfdyndns = {
+      description = "CloudFlare Dynamic DNS Client";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      startAt = "5 minutes";
+      serviceConfig = {
+        Type = "simple";
+        User = config.ids.uids.cfdyndns;
+        Group = config.ids.gids.cfdyndns;
+        ExecStart = "/bin/sh -c '${pkgs.cfdyndns}/bin/cfdyndns'";
+      };
+      environment = {
+        CLOUDFLARE_EMAIL="${cfg.email}";
+        CLOUDFLARE_APIKEY="${cfg.apikey}";
+        CLOUDFLARE_RECORDS="${concatStringsSep "," cfg.records}";
+      };
+    };
+
+    users.extraUsers = {
+      cfdyndns = {
+        group = "cfdyndns";
+        uid = config.ids.uids.cfdyndns;
+      };
+    };
+
+    users.extraGroups = {
+      cfdyndns = {
+        gid = config.ids.gids.cfdyndns;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/defaultUnicornConfig.rb b/nixos/modules/services/misc/defaultUnicornConfig.rb
index 81abaf336dc0..84622622db70 100644
--- a/nixos/modules/services/misc/defaultUnicornConfig.rb
+++ b/nixos/modules/services/misc/defaultUnicornConfig.rb
@@ -187,7 +187,6 @@ working_directory ENV["GITLAB_PATH"]
 pid ENV["UNICORN_PATH"] + "/tmp/pids/unicorn.pid"
 
 listen ENV["UNICORN_PATH"] + "/tmp/sockets/gitlab.socket", :backlog => 1024
-listen "127.0.0.1:8080", :tcp_nopush => true
 
 timeout 60
 
diff --git a/nixos/modules/services/misc/gammu-smsd.nix b/nixos/modules/services/misc/gammu-smsd.nix
new file mode 100644
index 000000000000..91047ead4364
--- /dev/null
+++ b/nixos/modules/services/misc/gammu-smsd.nix
@@ -0,0 +1,253 @@
+{ pkgs, lib, config, ... }:
+
+with lib;
+let
+  cfg = config.services.gammu-smsd;
+
+  configFile = pkgs.writeText "gammu-smsd.conf" ''
+    [gammu]
+    Device = ${cfg.device.path}
+    Connection = ${cfg.device.connection}
+    SynchronizeTime = ${if cfg.device.synchronizeTime then "yes" else "no"}
+    LogFormat = ${cfg.log.format}
+    ${if (cfg.device.pin != null) then "PIN = ${cfg.device.pin}" else ""}
+    ${cfg.extraConfig.gammu}
+
+
+    [smsd]
+    LogFile = ${cfg.log.file}
+    Service = ${cfg.backend.service}
+
+    ${optionalString (cfg.backend.service == "files") ''
+      InboxPath = ${cfg.backend.files.inboxPath}
+      OutboxPath = ${cfg.backend.files.outboxPath}
+      SentSMSPath = ${cfg.backend.files.sentSMSPath}
+      ErrorSMSPath = ${cfg.backend.files.errorSMSPath}
+    ''}
+
+    ${optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "sqlite") ''
+      Driver = ${cfg.backend.sql.driver}
+      DBDir = ${cfg.backend.sql.database}
+    ''}
+
+    ${optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "native_pgsql") (
+      with cfg.backend; ''
+        Driver = ${sql.driver}
+        ${if (sql.database!= null) then "Database = ${sql.database}" else ""}
+        ${if (sql.host != null) then "Host = ${sql.host}" else ""}
+        ${if (sql.user != null) then "User = ${sql.user}" else ""}
+        ${if (sql.password != null) then "Password = ${sql.password}" else ""}
+      '')}
+
+    ${cfg.extraConfig.smsd}
+  '';
+
+  initDBDir = "share/doc/gammu/examples/sql";
+
+  gammuPackage = with cfg.backend; (pkgs.gammu.override {
+    dbiSupport = (service == "sql" && sql.driver == "sqlite");
+    postgresSupport = (service == "sql" && sql.driver == "native_pgsql");
+  });
+
+in {
+  options = {
+    services.gammu-smsd = {
+
+      enable = mkEnableOption "gammu-smsd daemon";
+
+      user = mkOption {
+        type = types.str;
+        default = "smsd";
+        description = "User that has access to the device";
+      };
+
+      device = {
+        path = mkOption {
+          type = types.path;
+          description = "Device node or address of the phone";
+          example = "/dev/ttyUSB2";
+        };
+
+        group = mkOption {
+          type = types.str;
+          default = "root";
+          description = "Owner group of the device";
+          example = "dialout";
+        };
+
+        connection = mkOption {
+          type = types.str;
+          default = "at";
+          description = "Protocol which will be used to talk to the phone";
+        };
+
+        synchronizeTime = mkOption {
+          type = types.bool;
+          default = true;
+          description = "Whether to set time from computer to the phone during starting connection";
+        };
+
+        pin = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          description = "PIN code for the simcard";
+        };
+      };
+
+
+      log = {
+        file = mkOption {
+          type = types.str;
+          default = "syslog";
+          description = "Path to file where information about communication will be stored";
+        };
+
+        format = mkOption {
+          type = types.enum [ "nothing" "text" "textall" "textalldate" "errors" "errorsdate" "binary" ];
+          default = "errors";
+          description = "Determines what will be logged to the LogFile";
+        };
+      };
+
+
+      extraConfig = {
+        gammu = mkOption {
+          type = types.lines;
+          default = "";
+          description = "Extra config lines to be added into [gammu] section";
+        };
+
+
+        smsd = mkOption {
+          type = types.lines;
+          default = "";
+          description = "Extra config lines to be added into [smsd] section";
+        };
+      };
+
+
+      backend = {
+        service = mkOption {
+          type = types.enum [ "null" "files" "sql" ];
+          default = "null";
+          description = "Service to use to store sms data.";
+        };
+
+        files = {
+          inboxPath = mkOption {
+            type = types.path;
+            default = "/var/spool/sms/inbox/";
+            description = "Where the received SMSes are stored";
+          };
+
+          outboxPath = mkOption {
+            type = types.path;
+            default = "/var/spool/sms/outbox/";
+            description = "Where SMSes to be sent should be placed";
+          };
+
+          sentSMSPath = mkOption {
+            type = types.path;
+            default = "/var/spool/sms/sent/";
+            description = "Where the transmitted SMSes are placed";
+          };
+
+          errorSMSPath = mkOption {
+            type = types.path;
+            default = "/var/spool/sms/error/";
+            description = "Where SMSes with error in transmission is placed";
+          };
+        };
+
+        sql = {
+          driver = mkOption {
+            type = types.enum [ "native_mysql" "native_pgsql" "odbc" "dbi" ];
+            description = "DB driver to use";
+          };
+
+          sqlDialect = mkOption {
+            type = types.nullOr types.str;
+            default = null;
+            description = "SQL dialect to use (odbc driver only)";
+          };
+
+          database = mkOption {
+            type = types.str;
+            default = null;
+            description = "Database name to store sms data";
+          };
+
+          host = mkOption {
+            type = types.str;
+            default = "localhost";
+            description = "Database server address";
+          };
+
+          user = mkOption {
+            type = types.nullOr types.str;
+            default = null;
+            description = "User name used for connection to the database";
+          };
+
+          password = mkOption {
+            type = types.nullOr types.str;
+            default = null;
+            description = "User password used for connetion to the database";
+          };
+        };
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraUsers.${cfg.user} = {
+      description = "gammu-smsd user";
+      uid = config.ids.uids.gammu-smsd;
+      extraGroups = [ "${cfg.device.group}" ];
+    };
+
+    environment.systemPackages = with cfg.backend; [ gammuPackage ]
+    ++ optionals (service == "sql" && sql.driver == "sqlite")  [ pkgs.sqlite ];
+
+    systemd.services.gammu-smsd = {
+      description = "gammu-smsd daemon";
+
+      wantedBy = [ "multi-user.target" ];
+
+      wants = with cfg.backend; [ ]
+      ++ optionals (service == "sql" && sql.driver == "native_pgsql") [ "postgresql.service" ];
+
+      preStart = with cfg.backend;
+
+        optionalString (service == "files") (with files; ''
+          mkdir -m 755 -p ${inboxPath} ${outboxPath} ${sentSMSPath} ${errorSMSPath}
+          chown ${cfg.user} -R ${inboxPath}
+          chown ${cfg.user} -R ${outboxPath}
+          chown ${cfg.user} -R ${sentSMSPath}
+          chown ${cfg.user} -R ${errorSMSPath}
+        '')
+      + optionalString (service == "sql" && sql.driver == "sqlite") ''
+         cat "${gammuPackage}/${initDBDir}/sqlite.sql" \
+         | ${pkgs.sqlite}/bin/sqlite3 ${sql.database}
+        ''
+      + (let execPsql = extraArgs: concatStringsSep " " [
+          (optionalString (sql.password != null) "PGPASSWORD=${sql.password}")
+          "${config.services.postgresql.package}/bin/psql"
+          (optionalString (sql.host != null) "-h ${sql.host}")
+          (optionalString (sql.user != null) "-U ${sql.user}")
+          "$extraArgs"
+          "${sql.database}"
+        ]; in optionalString (service == "sql" && sql.driver == "native_pgsql") ''
+         echo '\i '"${gammuPackage}/${initDBDir}/pgsql.sql" | ${execPsql ""}
+       '');
+
+      serviceConfig = {
+        User = "${cfg.user}";
+        Group = "${cfg.device.group}";
+        PermissionsStartOnly = true;
+        ExecStart = "${gammuPackage}/bin/gammu-smsd -c ${configFile}";
+      };
+
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/gitit.nix b/nixos/modules/services/misc/gitit.nix
index ab4d385ba165..befd8c628f16 100644
--- a/nixos/modules/services/misc/gitit.nix
+++ b/nixos/modules/services/misc/gitit.nix
@@ -35,7 +35,6 @@ let
       };
 
       haskellPackages = mkOption {
-        type = types.attrsOf types.package;
         default = pkgs.haskellPackages;
         defaultText = "pkgs.haskellPackages";
         example = literalExample "pkgs.haskell.packages.ghc784";
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 949357ab20f4..cc50bfbea531 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -7,10 +7,13 @@ with lib;
 let
   cfg = config.services.gitlab;
 
-  ruby = pkgs.gitlab.ruby;
+  ruby = cfg.packages.gitlab.ruby;
   bundler = pkgs.bundler;
 
-  gemHome = "${pkgs.gitlab.env}/${ruby.gemPath}";
+  gemHome = "${cfg.packages.gitlab.env}/${ruby.gemPath}";
+
+  gitlabSocket = "${cfg.statePath}/tmp/sockets/gitlab.socket";
+  pathUrlQuote = url: replaceStrings ["/"] ["%2F"] url;
 
   databaseYml = ''
     production:
@@ -21,14 +24,15 @@ let
       username: ${cfg.databaseUsername}
       encoding: utf8
   '';
+
   gitlabShellYml = ''
-    user: gitlab
-    gitlab_url: "http://${cfg.host}:${toString cfg.port}/"
+    user: ${cfg.user}
+    gitlab_url: "http+unix://${pathUrlQuote gitlabSocket}"
     http_settings:
       self_signed_cert: false
-    repos_path: "${cfg.stateDir}/repositories"
-    secret_file: "${cfg.stateDir}/config/gitlab_shell_secret"
-    log_file: "${cfg.stateDir}/log/gitlab-shell.log"
+    repos_path: "${cfg.statePath}/repositories"
+    secret_file: "${cfg.statePath}/config/gitlab_shell_secret"
+    log_file: "${cfg.statePath}/log/gitlab-shell.log"
     redis:
       bin: ${pkgs.redis}/bin/redis-cli
       host: 127.0.0.1
@@ -37,33 +41,102 @@ let
       namespace: resque:gitlab
   '';
 
+  gitlabConfig = {
+    # These are the default settings from config/gitlab.example.yml
+    production = flip recursiveUpdate cfg.extraConfig {
+      gitlab = {
+        host = cfg.host;
+        port = cfg.port;
+        https = cfg.https;
+        user = cfg.user;
+        email_enabled = true;
+        email_display_name = "GitLab";
+        email_reply_to = "noreply@localhost";
+        default_theme = 2;
+        default_projects_features = {
+          issues = true;
+          merge_requests = true;
+          wiki = true;
+          snippets = false;
+          builds = true;
+        };
+      };
+      artifacts = {
+        enabled = true;
+      };
+      lfs = {
+        enabled = true;
+      };
+      gravatar = {
+        enabled = true;
+      };
+      cron_jobs = {
+        stuck_ci_builds_worker = {
+          cron = "0 0 * * *";
+        };
+      };
+      gitlab_ci = {
+        builds_path = "${cfg.statePath}/builds";
+      };
+      ldap = {
+        enabled = false;
+      };
+      omniauth = {
+        enabled = false;
+      };
+      shared = {
+        path = "${cfg.statePath}/shared";
+      };
+      backup = {
+        path = "${cfg.backupPath}";
+      };
+      gitlab_shell = {
+        path = "${cfg.packages.gitlab-shell}";
+        repos_path = "${cfg.statePath}/repositories";
+        hooks_path = "${cfg.statePath}/shell/hooks";
+        secret_file = "${cfg.statePath}/config/gitlab_shell_secret";
+        upload_pack = true;
+        receive_pack = true;
+      };
+      git = {
+        bin_path = "git";
+        max_size = 20971520; # 20MB
+        timeout = 10;
+      };
+      extra = {};
+    };
+  };
+
+  gitlabEnv = {
+    HOME = "${cfg.statePath}/home";
+    GEM_HOME = gemHome;
+    BUNDLE_GEMFILE = "${cfg.packages.gitlab}/share/gitlab/Gemfile";
+    UNICORN_PATH = "${cfg.statePath}/";
+    GITLAB_PATH = "${cfg.packages.gitlab}/share/gitlab/";
+    GITLAB_STATE_PATH = "${cfg.statePath}";
+    GITLAB_UPLOADS_PATH = "${cfg.statePath}/uploads";
+    GITLAB_LOG_PATH = "${cfg.statePath}/log";
+    GITLAB_SHELL_PATH = "${cfg.packages.gitlab-shell}";
+    GITLAB_SHELL_CONFIG_PATH = "${cfg.statePath}/shell/config.yml";
+    GITLAB_SHELL_SECRET_PATH = "${cfg.statePath}/config/gitlab_shell_secret";
+    GITLAB_SHELL_HOOKS_PATH = "${cfg.statePath}/shell/hooks";
+    RAILS_ENV = "production";
+  };
+
   unicornConfig = builtins.readFile ./defaultUnicornConfig.rb;
 
   gitlab-runner = pkgs.stdenv.mkDerivation rec {
     name = "gitlab-runner";
-    buildInputs = [ pkgs.gitlab pkgs.bundler pkgs.makeWrapper ];
+    buildInputs = [ cfg.packages.gitlab bundler pkgs.makeWrapper ];
     phases = "installPhase fixupPhase";
     buildPhase = "";
     installPhase = ''
       mkdir -p $out/bin
-      makeWrapper ${bundler}/bin/bundle $out/bin/gitlab-runner\
-          --set RAKEOPT '"-f ${pkgs.gitlab}/share/gitlab/Rakefile"'\
-          --set GEM_HOME '${gemHome}'\
-          --set UNICORN_PATH "${cfg.stateDir}/"\
-          --set GITLAB_PATH "${pkgs.gitlab}/share/gitlab/"\
-          --set GITLAB_APPLICATION_LOG_PATH "${cfg.stateDir}/log/application.log"\
-          --set GITLAB_SATELLITES_PATH "${cfg.stateDir}/satellites"\
-          --set GITLAB_SHELL_PATH "${pkgs.gitlab-shell}"\
-          --set GITLAB_REPOSITORIES_PATH "${cfg.stateDir}/repositories"\
-          --set GITLAB_SHELL_HOOKS_PATH "${cfg.stateDir}/shell/hooks"\
-          --set BUNDLE_GEMFILE "${pkgs.gitlab}/share/gitlab/Gemfile"\
-          --set GITLAB_EMAIL_FROM "${cfg.emailFrom}"\
-          --set GITLAB_SHELL_CONFIG_PATH "${cfg.stateDir}/shell/config.yml"\
-          --set GITLAB_SHELL_SECRET_PATH "${cfg.stateDir}/config/gitlab_shell_secret"\
-          --set GITLAB_HOST "${cfg.host}"\
-          --set GITLAB_PORT "${toString cfg.port}"\
-          --set GITLAB_BACKUP_PATH "${cfg.backupPath}"\
-          --set RAILS_ENV "production"
+      makeWrapper ${bundler}/bin/bundle $out/bin/gitlab-runner \
+          ${concatStrings (mapAttrsToList (name: value: "--set ${name} '\"${value}\"' ") gitlabEnv)} \
+          --set GITLAB_CONFIG_PATH '"${cfg.statePath}/config"' \
+          --set PATH '"${pkgs.nodejs}/bin:${pkgs.gzip}/bin:${config.services.postgresql.package}/bin:$PATH"' \
+          --set RAKEOPT '"-f ${cfg.packages.gitlab}/share/gitlab/Rakefile"'
     '';
   };
 
@@ -79,13 +152,25 @@ in {
         '';
       };
 
-      satelliteDir = mkOption {
-        type = types.str;
-        default = "/var/gitlab/git-satellites";
-        description = "Gitlab directory to store checked out git trees requires for operation.";
+      packages.gitlab = mkOption {
+        type = types.package;
+        default = pkgs.gitlab;
+        description = "Reference to the gitlab package";
+      };
+
+      packages.gitlab-shell = mkOption {
+        type = types.package;
+        default = pkgs.gitlab-shell;
+        description = "Reference to the gitlab-shell package";
+      };
+
+      packages.gitlab-workhorse = mkOption {
+        type = types.package;
+        default = pkgs.gitlab-workhorse;
+        description = "Reference to the gitlab-workhorse package";
       };
 
-      stateDir = mkOption {
+      statePath = mkOption {
         type = types.str;
         default = "/var/gitlab/state";
         description = "Gitlab state directory, logs are stored here.";
@@ -93,7 +178,7 @@ in {
 
       backupPath = mkOption {
         type = types.str;
-        default = cfg.stateDir + "/backup";
+        default = cfg.statePath + "/backup";
         description = "Gitlab path for backups.";
       };
 
@@ -136,14 +221,67 @@ in {
       port = mkOption {
         type = types.int;
         default = 8080;
-        description = "Gitlab server listening port.";
+        description = ''
+          Gitlab server port for copy-paste URLs, e.g. 80 or 443 if you're
+          service over https.
+        '';
+      };
+
+      https = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether gitlab prints URLs with https as scheme.";
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "gitlab";
+        description = "User to run gitlab and all related services.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "gitlab";
+        description = "Group to run gitlab and all related services.";
+      };
+
+      initialRootEmail = mkOption {
+        type = types.str;
+        default = "admin@local.host";
+        description = ''
+          Initial email address of the root account if this is a new install.
+        '';
+      };
+
+      initialRootPassword = mkOption {
+        type = types.str;
+        default = "UseNixOS!";
+        description = ''
+          Initial password of the root account if this is a new install.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.attrs;
+        default = {};
+        example = {
+          gitlab = {
+            default_projects_features = {
+              builds = false;
+            };
+          };
+        };
+        description = ''
+          Extra options to be merged into config/gitlab.yml as nix
+          attribute set.
+        '';
       };
     };
   };
 
   config = mkIf cfg.enable {
 
-    environment.systemPackages = [ pkgs.git gitlab-runner pkgs.gitlab-shell ];
+    environment.systemPackages = [ pkgs.git gitlab-runner cfg.packages.gitlab-shell ];
 
     assertions = [
       { assertion = cfg.databasePassword != "";
@@ -159,39 +297,24 @@ in {
     services.postfix.enable = mkDefault true;
 
     users.extraUsers = [
-      { name = "gitlab";
-        group = "gitlab";
-        home = "${cfg.stateDir}/home";
+      { name = cfg.user;
+        group = cfg.group;
+        home = "${cfg.statePath}/home";
         shell = "${pkgs.bash}/bin/bash";
         uid = config.ids.uids.gitlab;
-      } ];
+      }
+    ];
 
     users.extraGroups = [
-      { name = "gitlab";
+      { name = cfg.group;
         gid = config.ids.gids.gitlab;
-      } ];
+      }
+    ];
 
     systemd.services.gitlab-sidekiq = {
       after = [ "network.target" "redis.service" ];
       wantedBy = [ "multi-user.target" ];
-      environment.HOME = "${cfg.stateDir}/home";
-      environment.GEM_HOME = gemHome;
-      environment.UNICORN_PATH = "${cfg.stateDir}/";
-      environment.GITLAB_PATH = "${pkgs.gitlab}/share/gitlab/";
-      environment.GITLAB_APPLICATION_LOG_PATH = "${cfg.stateDir}/log/application.log";
-      environment.GITLAB_SATELLITES_PATH = "${cfg.stateDir}/satellites";
-      environment.GITLAB_SHELL_PATH = "${pkgs.gitlab-shell}";
-      environment.GITLAB_REPOSITORIES_PATH = "${cfg.stateDir}/repositories";
-      environment.GITLAB_SHELL_HOOKS_PATH = "${cfg.stateDir}/shell/hooks";
-      environment.BUNDLE_GEMFILE = "${pkgs.gitlab}/share/gitlab/Gemfile";
-      environment.GITLAB_EMAIL_FROM = "${cfg.emailFrom}";
-      environment.GITLAB_SHELL_CONFIG_PATH = "${cfg.stateDir}/shell/config.yml";
-      environment.GITLAB_SHELL_SECRET_PATH = "${cfg.stateDir}/config/gitlab_shell_secret";
-      environment.GITLAB_HOST = "${cfg.host}";
-      environment.GITLAB_PORT = "${toString cfg.port}";
-      environment.GITLAB_DATABASE_HOST = "${cfg.databaseHost}";
-      environment.GITLAB_DATABASE_PASSWORD = "${cfg.databasePassword}";
-      environment.RAILS_ENV = "production";
+      environment = gitlabEnv;
       path = with pkgs; [
         config.services.postgresql.package
         gitAndTools.git
@@ -201,116 +324,131 @@ in {
       ];
       serviceConfig = {
         Type = "simple";
-        User = "gitlab";
-        Group = "gitlab";
+        User = cfg.user;
+        Group = cfg.group;
         TimeoutSec = "300";
-        WorkingDirectory = "${pkgs.gitlab}/share/gitlab";
-        ExecStart="${bundler}/bin/bundle exec \"sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.stateDir}/tmp/sidekiq.pid\"";
+        WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab";
+        ExecStart="${bundler}/bin/bundle exec \"sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.statePath}/tmp/sidekiq.pid\"";
       };
     };
 
-    systemd.services.gitlab-git-http-server = {
+    systemd.services.gitlab-workhorse = {
       after = [ "network.target" "gitlab.service" ];
       wantedBy = [ "multi-user.target" ];
-      environment.HOME = "${cfg.stateDir}/home";
+      environment.HOME = gitlabEnv.HOME;
+      environment.GITLAB_SHELL_CONFIG_PATH = gitlabEnv.GITLAB_SHELL_CONFIG_PATH;
       path = with pkgs; [
         gitAndTools.git
         openssh
       ];
+      preStart = ''
+        mkdir -p /run/gitlab
+        chown ${cfg.user}:${cfg.group} /run/gitlab
+      '';
       serviceConfig = {
+        PermissionsStartOnly = true; # preStart must be run as root
         Type = "simple";
-        User = "gitlab";
-        Group = "gitlab";
+        User = cfg.user;
+        Group = cfg.group;
         TimeoutSec = "300";
-        ExecStart = "${pkgs.gitlab-git-http-server}/bin/gitlab-git-http-server -listenUmask 0 -listenNetwork unix -listenAddr ${cfg.stateDir}/tmp/sockets/gitlab-git-http-server.socket -authBackend http://localhost:8080 ${cfg.stateDir}/repositories";
+        ExecStart =
+          "${cfg.packages.gitlab-workhorse}/bin/gitlab-workhorse "
+          + "-listenUmask 0 "
+          + "-listenNetwork unix "
+          + "-listenAddr /run/gitlab/gitlab-workhorse.socket "
+          + "-authSocket ${gitlabSocket} "
+          + "-documentRoot ${cfg.packages.gitlab}/share/gitlab/public";
       };
     };
 
     systemd.services.gitlab = {
       after = [ "network.target" "postgresql.service" "redis.service" ];
       wantedBy = [ "multi-user.target" ];
-      environment.HOME = "${cfg.stateDir}/home";
-      environment.GEM_HOME = gemHome;
-      environment.UNICORN_PATH = "${cfg.stateDir}/";
-      environment.GITLAB_PATH = "${pkgs.gitlab}/share/gitlab/";
-      environment.GITLAB_APPLICATION_LOG_PATH = "${cfg.stateDir}/log/application.log";
-      environment.GITLAB_SATELLITES_PATH = "${cfg.stateDir}/satellites";
-      environment.GITLAB_SHELL_PATH = "${pkgs.gitlab-shell}";
-      environment.GITLAB_SHELL_CONFIG_PATH = "${cfg.stateDir}/shell/config.yml";
-      environment.GITLAB_SHELL_SECRET_PATH = "${cfg.stateDir}/config/gitlab_shell_secret";
-      environment.GITLAB_REPOSITORIES_PATH = "${cfg.stateDir}/repositories";
-      environment.GITLAB_SHELL_HOOKS_PATH = "${cfg.stateDir}/shell/hooks";
-      environment.BUNDLE_GEMFILE = "${pkgs.gitlab}/share/gitlab/Gemfile";
-      environment.GITLAB_EMAIL_FROM = "${cfg.emailFrom}";
-      environment.GITLAB_HOST = "${cfg.host}";
-      environment.GITLAB_PORT = "${toString cfg.port}";
-      environment.GITLAB_DATABASE_HOST = "${cfg.databaseHost}";
-      environment.GITLAB_DATABASE_PASSWORD = "${cfg.databasePassword}";
-      environment.RAILS_ENV = "production";
+      environment = gitlabEnv;
       path = with pkgs; [
         config.services.postgresql.package
         gitAndTools.git
-        ruby
         openssh
         nodejs
       ];
       preStart = ''
-        # TODO: use env vars
-        mkdir -p ${cfg.stateDir}
-        mkdir -p ${cfg.stateDir}/log
-        mkdir -p ${cfg.stateDir}/satellites
-        mkdir -p ${cfg.stateDir}/repositories
-        mkdir -p ${cfg.stateDir}/shell/hooks
-        mkdir -p ${cfg.stateDir}/tmp/pids
-        mkdir -p ${cfg.stateDir}/tmp/sockets
-        rm -rf ${cfg.stateDir}/config
-        mkdir -p ${cfg.stateDir}/config
-        # TODO: What exactly is gitlab-shell doing with the secret?
-        tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 20 > ${cfg.stateDir}/config/gitlab_shell_secret
-        mkdir -p ${cfg.stateDir}/home/.ssh
-        touch ${cfg.stateDir}/home/.ssh/authorized_keys
-
-        cp -rf ${pkgs.gitlab}/share/gitlab/config ${cfg.stateDir}/
-        cp ${pkgs.gitlab}/share/gitlab/VERSION ${cfg.stateDir}/VERSION
+        mkdir -p ${cfg.backupPath}
+        mkdir -p ${cfg.statePath}/builds
+        mkdir -p ${cfg.statePath}/repositories
+        mkdir -p ${gitlabConfig.production.shared.path}/artifacts
+        mkdir -p ${gitlabConfig.production.shared.path}/lfs-objects
+        mkdir -p ${cfg.statePath}/log
+        mkdir -p ${cfg.statePath}/shell
+        mkdir -p ${cfg.statePath}/tmp/pids
+        mkdir -p ${cfg.statePath}/tmp/sockets
+
+        rm -rf ${cfg.statePath}/config ${cfg.statePath}/shell/hooks
+        mkdir -p ${cfg.statePath}/config ${cfg.statePath}/shell
 
-        ln -fs ${pkgs.writeText "database.yml" databaseYml} ${cfg.stateDir}/config/database.yml
-        ln -fs ${pkgs.writeText "unicorn.rb" unicornConfig} ${cfg.stateDir}/config/unicorn.rb
-
-        chown -R gitlab:gitlab ${cfg.stateDir}/
-        chmod -R 755 ${cfg.stateDir}/
+        # TODO: What exactly is gitlab-shell doing with the secret?
+        tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 20 > ${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
+        # configurable
+        mkdir -p /run/gitlab
+        mkdir -p ${cfg.statePath}/uploads
+        ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads
+        chown -R ${cfg.user}:${cfg.group} /run/gitlab
+
+        # Prepare home directory
+        mkdir -p ${gitlabEnv.HOME}/.ssh
+        touch ${gitlabEnv.HOME}/.ssh/authorized_keys
+        chown -R ${cfg.user}:${cfg.group} ${gitlabEnv.HOME}/
+        chmod -R u+rwX,go-rwx+X ${gitlabEnv.HOME}/
+
+        cp -rf ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config
+        ln -sf ${cfg.statePath}/config /run/gitlab/config
+        cp ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION
+
+        # JSON is a subset of YAML
+        ln -fs ${pkgs.writeText "gitlab.yml" (builtins.toJSON gitlabConfig)} ${cfg.statePath}/config/gitlab.yml
+        ln -fs ${pkgs.writeText "database.yml" databaseYml} ${cfg.statePath}/config/database.yml
+        ln -fs ${pkgs.writeText "unicorn.rb" unicornConfig} ${cfg.statePath}/config/unicorn.rb
+
+        chown -R ${cfg.user}:${cfg.group} ${cfg.statePath}/
+        chmod -R ug+rwX,o-rwx+X ${cfg.statePath}/
+
+        # Install the shell required to push repositories
+        ln -fs ${pkgs.writeText "config.yml" gitlabShellYml} "$GITLAB_SHELL_CONFIG_PATH"
+        ln -fs ${cfg.packages.gitlab-shell}/hooks "$GITLAB_SHELL_HOOKS_PATH"
+        ${cfg.packages.gitlab-shell}/bin/install
 
         if [ "${cfg.databaseHost}" = "127.0.0.1" ]; then
-          if ! test -e "${cfg.stateDir}/db-created"; then
+          if ! test -e "${cfg.statePath}/db-created"; then
             psql postgres -c "CREATE ROLE gitlab WITH LOGIN NOCREATEDB NOCREATEROLE NOCREATEUSER ENCRYPTED PASSWORD '${cfg.databasePassword}'"
             ${config.services.postgresql.package}/bin/createdb --owner gitlab gitlab || true
-            touch "${cfg.stateDir}/db-created"
+            touch "${cfg.statePath}/db-created"
 
-            # force=yes disables the manual-interaction yes/no prompt
-            # which breaks without an stdin.
-            force=yes ${bundler}/bin/bundle exec rake -f ${pkgs.gitlab}/share/gitlab/Rakefile gitlab:setup RAILS_ENV=production
+            # The gitlab:setup task is horribly broken somehow, these two tasks will do the same for setting up the initial database
+            ${gitlab-runner}/bin/gitlab-runner exec rake db:migrate RAILS_ENV=production
+            ${gitlab-runner}/bin/gitlab-runner exec rake db:seed_fu RAILS_ENV=production \
+              GITLAB_ROOT_PASSWORD="${cfg.initialRootPassword}" GITLAB_ROOT_EMAIL="${cfg.initialRootEmail}";
           fi
         fi
 
-      ${bundler}/bin/bundle exec rake -f ${pkgs.gitlab}/share/gitlab/Rakefile db:migrate RAILS_ENV=production
-      # Install the shell required to push repositories
-      ln -fs ${pkgs.writeText "config.yml" gitlabShellYml} ${cfg.stateDir}/shell/config.yml
-      export GITLAB_SHELL_CONFIG_PATH=""${cfg.stateDir}/shell/config.yml
-      ${pkgs.gitlab-shell}/bin/install
+        # Always do the db migrations just to be sure the database is up-to-date
+        ${gitlab-runner}/bin/gitlab-runner exec rake db:migrate RAILS_ENV=production
 
-      # Change permissions in the last step because some of the
-      # intermediary scripts like to create directories as root.
-      chown -R gitlab:gitlab ${cfg.stateDir}/
-      chmod -R 755 ${cfg.stateDir}/
+        # 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}
+        chmod -R u+rwX,go-rwx+X ${cfg.statePath}
       '';
 
       serviceConfig = {
         PermissionsStartOnly = true; # preStart must be run as root
         Type = "simple";
-        User = "gitlab";
-        Group = "gitlab";
+        User = cfg.user;
+        Group = cfg.group;
         TimeoutSec = "300";
-        WorkingDirectory = "${pkgs.gitlab}/share/gitlab";
-        ExecStart="${bundler}/bin/bundle exec \"unicorn -c ${cfg.stateDir}/config/unicorn.rb -E production\"";
+        WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab";
+        ExecStart="${bundler}/bin/bundle exec \"unicorn -c ${cfg.statePath}/config/unicorn.rb -E production\"";
       };
 
     };
diff --git a/nixos/modules/services/misc/gitlab.xml b/nixos/modules/services/misc/gitlab.xml
new file mode 100644
index 000000000000..b630fe421130
--- /dev/null
+++ b/nixos/modules/services/misc/gitlab.xml
@@ -0,0 +1,103 @@
+<chapter xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="module-services-gitlab">
+
+<title>Gitlab</title>
+
+<para>Gitlab is a feature-rich git hosting service.</para>
+
+<section><title>Prerequisites</title>
+
+<para>The gitlab service exposes only an Unix socket at
+<literal>/run/gitlab/gitlab-workhorse.socket</literal>. You need to configure a
+webserver to proxy HTTP requests to the socket.</para>
+
+<para>For instance, this could be used for Nginx:
+
+<programlisting>
+services.nginx.httpConfig = ''
+  server {
+    server_name git.example.com;
+    listen 443 ssl spdy;
+    listen [::]:443 ssl spdy;
+
+    ssl_certificate /var/lib/acme/git.example.com/fullchain.pem;
+    ssl_certificate_key /var/lib/acme/git.example.com/key.pem;
+
+    location / {
+      proxy_http_version 1.1;
+      proxy_set_header    Host                $http_host;
+      proxy_set_header    X-Real-IP           $remote_addr;
+      proxy_set_header    X-Forwarded-Ssl     on;
+      proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
+      proxy_set_header    X-Forwarded-Proto   $scheme;
+
+      proxy_pass http://unix:/run/gitlab/gitlab-workhorse.socket;
+    }
+  }
+'';
+</programlisting>
+</para>
+
+</section>
+
+<section><title>Configuring</title>
+
+<para>Gitlab depends on both PostgreSQL and Redis and will automatically enable
+both services. In the case of PostgreSQL, a database and a role will be created.
+</para>
+
+<para>The default state dir is /var/gitlab/state. This is where all data like
+the repositories and uploads will be stored.</para>
+
+<para>A basic configuration could look like this:
+
+<programlisting>
+services.gitlab = {
+  enable = true;
+  databasePassword = "eXaMpl3";
+  initialRootPassword = "UseNixOS!";
+  https = true;
+  host = "git.example.com";
+  port = 443;
+  user = "git";
+  group = "git";
+  extraConfig = {
+    gitlab = {
+      default_projects_features = { builds = false; };
+    };
+  };
+};
+</programlisting>
+</para>
+
+<para>Refer to <xref linkend="ch-options" /> for all available configuration
+options for the <literal>services.gitlab</literal> module.</para>
+
+</section>
+
+<section><title>Maintenance</title>
+
+<para>You can run all Gitlab related commands like rake tasks with
+<literal>gitlab-runner</literal> which will be available on the system
+when gitlab is enabled. You will have to run the commands as the user that
+you configured to run gitlab.</para>
+
+<para>For instance, to backup a Gitlab instance:
+
+<programlisting>
+$ sudo -u git -H gitlab-runner exec rake gitlab:backup:create
+</programlisting>
+
+A list of all availabe rake tasks can be obtained by running:
+
+<programlisting>
+$ sudo -u git -H gitlab-runner exec rake -T
+</programlisting>
+</para>
+
+</section>
+
+</chapter>
diff --git a/nixos/modules/services/misc/ihaskell.nix b/nixos/modules/services/misc/ihaskell.nix
index 1927922909ee..d0e9b839e754 100644
--- a/nixos/modules/services/misc/ihaskell.nix
+++ b/nixos/modules/services/misc/ihaskell.nix
@@ -6,7 +6,6 @@ let
 
   cfg = config.services.ihaskell;
   ihaskell = pkgs.ihaskell.override {
-    inherit (cfg.haskellPackages) ihaskell ghcWithPackages;
     packages = self: cfg.extraPackages self;
   };
 
@@ -22,7 +21,6 @@ in
       };
 
       haskellPackages = mkOption {
-        type = types.attrsOf types.package;
         default = pkgs.haskellPackages;
         defaultText = "pkgs.haskellPackages";
         example = literalExample "pkgs.haskell.packages.ghc784";
diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix
index 27c5a38e6b88..0ae0516769c0 100644
--- a/nixos/modules/services/misc/matrix-synapse.nix
+++ b/nixos/modules/services/misc/matrix-synapse.nix
@@ -61,6 +61,7 @@ in {
       package = mkOption {
         type = types.package;
         default = pkgs.matrix-synapse;
+        defaultText = "pkgs.matrix-synapse";
         description = ''
           Overridable attribute of the matrix synapse server package to use.
         '';
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 60e826bafd1e..b0e4bf106d31 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -364,9 +364,11 @@ in
           ++ optionals cfg.distributedBuilds [ pkgs.gzip ];
 
         environment = cfg.envVars
-          // { CURL_CA_BUNDLE = "/etc/ssl/certs/ca-bundle.crt"; }
+          // { CURL_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt"; }
           // config.networking.proxy.envVars;
 
+        unitConfig.RequiresMountsFor = "/nix/store";
+
         serviceConfig =
           { Nice = cfg.daemonNiceLevel;
             IOSchedulingPriority = cfg.daemonIONiceLevel;
diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix
index 3e1f53e79f3e..37ea339300d4 100644
--- a/nixos/modules/services/misc/nixos-manual.nix
+++ b/nixos/modules/services/misc/nixos-manual.nix
@@ -17,16 +17,32 @@ let
       nixpkgs.system = config.nixpkgs.system;
     };
 
-  eval = evalModules {
-    modules = [ versionModule ] ++ baseModules;
-    args = (config._module.args) // { modules = [ ]; };
-  };
-
+  /* For the purpose of generating docs, evaluate options with each derivation
+    in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}".
+    It isn't perfect, but it seems to cover a vast majority of use cases.
+    Caveat: even if the package is reached by a different means,
+    the path above will be shown and not e.g. `${config.services.foo.package}`. */
   manual = import ../../../doc/manual {
     inherit pkgs;
     version = config.system.nixosVersion;
     revision = config.system.nixosRevision;
-    options = eval.options;
+    options =
+      let
+        scrubbedEval = evalModules {
+          modules = [ versionModule ] ++ baseModules;
+          args = (config._module.args) // { modules = [ ]; };
+          specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; };
+        };
+        scrubDerivations = namePrefix: pkgSet: mapAttrs
+          (name: value:
+            let wholeName = "${namePrefix}.${name}"; in
+            if isAttrs value then
+              scrubDerivations wholeName value
+              // (optionalAttrs (isDerivation value) { outPath = "\${${wholeName}}"; })
+            else value
+          )
+          pkgSet;
+      in scrubbedEval.options;
   };
 
   entry = "${manual.manual}/share/doc/nixos/index.html";
@@ -72,7 +88,8 @@ in
     };
 
     services.nixosManual.ttyNumber = mkOption {
-      default = "8";
+      type = types.int;
+      default = 8;
       description = ''
         Virtual console on which to show the manual.
       '';
@@ -80,6 +97,7 @@ in
 
     services.nixosManual.browser = mkOption {
       type = types.path;
+      default = "${pkgs.w3m-nox}/bin/w3m";
       description = ''
         Browser used to show the manual.
       '';
@@ -96,7 +114,7 @@ in
       [ manual.manual help ]
       ++ optional config.programs.man.enable manual.manpages;
 
-    boot.extraTTYs = mkIf cfg.showManual ["tty${cfg.ttyNumber}"];
+    boot.extraTTYs = mkIf cfg.showManual ["tty${toString cfg.ttyNumber}"];
 
     systemd.services = optionalAttrs cfg.showManual
       { "nixos-manual" =
@@ -106,7 +124,7 @@ in
             { ExecStart = "${cfg.browser} ${entry}";
               StandardInput = "tty";
               StandardOutput = "tty";
-              TTYPath = "/dev/tty${cfg.ttyNumber}";
+              TTYPath = "/dev/tty${toString cfg.ttyNumber}";
               TTYReset = true;
               TTYVTDisallocate = true;
               Restart = "always";
@@ -117,8 +135,6 @@ in
     services.mingetty.helpLine = mkIf cfg.showManual
       "\nPress <Alt-F${toString cfg.ttyNumber}> for the NixOS manual.";
 
-    services.nixosManual.browser = mkDefault "${pkgs.w3m-nox}/bin/w3m";
-
   };
 
 }
diff --git a/nixos/modules/services/misc/octoprint.nix b/nixos/modules/services/misc/octoprint.nix
new file mode 100644
index 000000000000..9cf46345c228
--- /dev/null
+++ b/nixos/modules/services/misc/octoprint.nix
@@ -0,0 +1,120 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.octoprint;
+
+  cfgUpdate = pkgs.writeText "octoprint-config.yaml" (builtins.toJSON {
+    plugins.cura.cura_engine = "${pkgs.curaengine}/bin/CuraEngine";
+    server.host = cfg.host;
+    server.port = cfg.port;
+    webcam.ffmpeg = "${pkgs.ffmpeg}/bin/ffmpeg";
+  });
+
+  pluginsEnv = pkgs.python.buildEnv.override {
+    extraLibs = cfg.plugins pkgs.octoprint-plugins;
+  };
+
+in
+{
+  ##### interface
+
+  options = {
+
+    services.octoprint = {
+
+      enable = mkEnableOption "OctoPrint, web interface for 3D printers";
+
+      host = mkOption {
+        type = types.str;
+        default = "0.0.0.0";
+        description = ''
+          Host to bind OctoPrint to.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 5000;
+        description = ''
+          Port to bind OctoPrint to.
+        '';
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "octoprint";
+        description = "User for the daemon.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "octoprint";
+        description = "Group for the daemon.";
+      };
+
+      stateDir = mkOption {
+        type = types.path;
+        default = "/var/lib/octoprint";
+        description = "State directory of the daemon.";
+      };
+
+      plugins = mkOption {
+        #type = types.functionTo (types.listOf types.package);
+        default = plugins: [];
+        defaultText = "plugins: []";
+        example = literalExample "plugins: [ m3d-fio ]";
+        description = "Additional plugins.";
+      };
+
+    };
+
+  };
+
+  ##### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = optionalAttrs (cfg.user == "octoprint") (singleton
+      { name = "octoprint";
+        group = cfg.group;
+        uid = config.ids.uids.octoprint;
+      });
+
+    users.extraGroups = optionalAttrs (cfg.group == "octoprint") (singleton
+      { name = "octoprint";
+        gid = config.ids.gids.octoprint;
+      });
+
+    systemd.services.octoprint = {
+      description = "OctoPrint, web interface for 3D printers";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      path = [ pluginsEnv ];
+      environment.PYTHONPATH = makeSearchPath pkgs.python.sitePackages [ pluginsEnv ];
+
+      preStart = ''
+        mkdir -p "${cfg.stateDir}"
+        if [ -e "${cfg.stateDir}/config.yaml" ]; then
+          ${pkgs.yaml-merge}/bin/yaml-merge "${cfg.stateDir}/config.yaml" "${cfgUpdate}" > "${cfg.stateDir}/config.yaml.tmp"
+          mv "${cfg.stateDir}/config.yaml.tmp" "${cfg.stateDir}/config.yaml"
+        else
+          cp "${cfgUpdate}" "${cfg.stateDir}/config.yaml"
+          chmod 600 "${cfg.stateDir}/config.yaml"
+        fi
+        chown -R ${cfg.user}:${cfg.group} "${cfg.stateDir}"
+      '';
+
+      serviceConfig = {
+        ExecStart = "${pkgs.octoprint}/bin/octoprint -b ${cfg.stateDir}";
+        User = cfg.user;
+        Group = cfg.group;
+        PermissionsStartOnly = true;
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix
index fb62351365ed..875771dfa37f 100644
--- a/nixos/modules/services/misc/plex.nix
+++ b/nixos/modules/services/misc/plex.nix
@@ -58,6 +58,7 @@ in
       package = mkOption {
         type = types.package;
         default = pkgs.plex;
+        defaultText = "pkgs.plex";
         description = ''
           The Plex package to use. Plex subscribers may wish to use their own
           package here, pointing to subscriber-only server versions.
diff --git a/nixos/modules/services/misc/spice-vdagentd.nix b/nixos/modules/services/misc/spice-vdagentd.nix
new file mode 100644
index 000000000000..f8133394ffd3
--- /dev/null
+++ b/nixos/modules/services/misc/spice-vdagentd.nix
@@ -0,0 +1,30 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+let
+  cfg = config.services.spice-vdagentd;
+in
+{
+  options = {
+    services.spice-vdagentd = {
+      enable = mkEnableOption "Spice guest vdagent daemon";
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.spice-vdagent ];
+
+    systemd.services.spice-vdagentd = {
+      description = "spice-vdagent daemon";
+      wantedBy = [ "graphical.target" ];
+      preStart = ''
+        mkdir -p "/var/run/spice-vdagentd/"
+      '';
+      serviceConfig = {
+        Type = "forking";
+        ExecStart = "/bin/sh -c '${pkgs.spice-vdagent}/bin/spice-vdagentd'";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/subsonic.nix b/nixos/modules/services/misc/subsonic.nix
index 5a33aa33b260..c1ebe418f727 100644
--- a/nixos/modules/services/misc/subsonic.nix
+++ b/nixos/modules/services/misc/subsonic.nix
@@ -97,6 +97,7 @@ in
 
       transcoders = mkOption {
         type = types.listOf types.path;
+        default = [ "${pkgs.ffmpeg.bin}/bin/ffmpeg" ];
         description = ''
           List of paths to transcoder executables that should be accessible
           from Subsonic. Symlinks will be created to each executable inside
@@ -152,8 +153,5 @@ in
     };
 
     users.extraGroups.subsonic.gid = config.ids.gids.subsonic;
-
-    services.subsonic.transcoders = mkDefault [ "${pkgs.ffmpeg.bin}/bin/ffmpeg" ];
-
   };
 }
diff --git a/nixos/modules/services/misc/sundtek.nix b/nixos/modules/services/misc/sundtek.nix
index 8438ef79904f..e3234518c940 100644
--- a/nixos/modules/services/misc/sundtek.nix
+++ b/nixos/modules/services/misc/sundtek.nix
@@ -23,7 +23,7 @@ in
         Type = "oneshot";
         ExecStart = ''
           ${pkgs.sundtek}/bin/mediasrv -d -v -p ${pkgs.sundtek}/bin ;\
-          ${pkgs.sundtek}/bin/mediaclient --start=5 --wait-for-devices
+          ${pkgs.sundtek}/bin/mediaclient --start --wait-for-devices
           '';
         ExecStop = "${pkgs.sundtek}/bin/mediaclient --shutdown";
         RemainAfterExit = true;
diff --git a/nixos/modules/services/monitoring/bosun.nix b/nixos/modules/services/monitoring/bosun.nix
index 46273fc12187..51d38e8db4de 100644
--- a/nixos/modules/services/monitoring/bosun.nix
+++ b/nixos/modules/services/monitoring/bosun.nix
@@ -129,17 +129,19 @@ in {
       description = "bosun metrics collector (part of Bosun)";
       wantedBy = [ "multi-user.target" ];
 
-      preStart =
-        ''
-        mkdir -p `dirname ${cfg.stateFile}`;
-        touch ${cfg.stateFile}
-        touch ${cfg.stateFile}.tmp
+      preStart = ''
+        mkdir -p "$(dirname "${cfg.stateFile}")";
+        touch "${cfg.stateFile}"
+        touch "${cfg.stateFile}.tmp"
+
+        mkdir -p "${cfg.ledisDir}";
 
         if [ "$(id -u)" = 0 ]; then
-          chown ${cfg.user}:${cfg.group} ${cfg.stateFile}
-          chown ${cfg.user}:${cfg.group} ${cfg.stateFile}.tmp
+          chown ${cfg.user}:${cfg.group} "${cfg.stateFile}"
+          chown ${cfg.user}:${cfg.group} "${cfg.stateFile}.tmp"
+          chown ${cfg.user}:${cfg.group} "${cfg.ledisDir}"
         fi
-        '';
+      '';
 
       serviceConfig = {
         PermissionsStartOnly = true;
diff --git a/nixos/modules/services/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix
index 717c2c481683..3c3d83c66ed0 100644
--- a/nixos/modules/services/monitoring/collectd.nix
+++ b/nixos/modules/services/monitoring/collectd.nix
@@ -34,6 +34,15 @@ in {
       type = bool;
     };
 
+    package = mkOption {
+      default = pkgs.collectd;
+      defaultText = "pkgs.collectd";
+      description = ''
+        Which collectd package to use.
+      '';
+      type = package;
+    };
+
     user = mkOption {
       default = "collectd";
       description = ''
@@ -91,7 +100,7 @@ in {
       wantedBy = [ "multi-user.target" ];
 
       serviceConfig = {
-        ExecStart = "${pkgs.collectd}/sbin/collectd -C ${conf} -P ${cfg.pidFile}";
+        ExecStart = "${cfg.package}/sbin/collectd -C ${conf} -P ${cfg.pidFile}";
         Type = "forking";
         PIDFile = cfg.pidFile;
         User = optional (cfg.user!="root") cfg.user;
diff --git a/nixos/modules/services/monitoring/dd-agent.nix b/nixos/modules/services/monitoring/dd-agent.nix
index 8c847af3bfc0..bd8d9950f77c 100644
--- a/nixos/modules/services/monitoring/dd-agent.nix
+++ b/nixos/modules/services/monitoring/dd-agent.nix
@@ -183,7 +183,6 @@ in {
         Restart = "always";
         RestartSec = 2;
       };
-      environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
       restartTriggers = [ pkgs.dd-agent ddConf diskConfig networkConfig postgresqlConfig nginxConfig mongoConfig ];
     };
 
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
index 0b49038dd273..5c6f063b1493 100644
--- a/nixos/modules/services/monitoring/grafana.nix
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -87,6 +87,7 @@ in {
 
     staticRootPath = mkOption {
       description = "Root path for static assets.";
+      default = "${cfg.package}/share/grafana/public";
       type = types.str;
     };
 
@@ -232,8 +233,5 @@ in {
       home = cfg.dataDir;
       createHome = true;
     };
-
-    services.grafana.staticRootPath = mkDefault "${cfg.package}/share/grafana/public";
-
   };
 }
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index 976fd253a7cd..e59be1ea6c31 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -490,7 +490,7 @@ in {
             "${cfg.api.package}/lib/python2.7/site-packages:" +
             concatMapStringsSep ":" (f: f + "/lib/python2.7/site-packages") cfg.api.finders;
           GRAPHITE_API_CONFIG = graphiteApiConfig;
-          LD_LIBRARY_PATH = "${pkgs.cairo}/lib";
+          LD_LIBRARY_PATH = "${pkgs.cairo.out}/lib";
         };
         serviceConfig = {
           ExecStart = ''
diff --git a/nixos/modules/services/monitoring/hdaps.nix b/nixos/modules/services/monitoring/hdaps.nix
new file mode 100644
index 000000000000..be26c44e78d1
--- /dev/null
+++ b/nixos/modules/services/monitoring/hdaps.nix
@@ -0,0 +1,22 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.hdapsd;
+  hdapsd = [ pkgs.hdapsd ];
+in
+{
+  options = {
+    services.hdapsd.enable = mkEnableOption
+      ''
+        Hard Drive Active Protection System Daemon,
+        devices are detected and managed automatically by udev and systemd
+      '';
+  };
+
+  config = mkIf cfg.enable {
+    services.udev.packages = hdapsd;
+    systemd.packages = hdapsd;
+  };
+}
diff --git a/nixos/modules/services/network-filesystems/netatalk.nix b/nixos/modules/services/network-filesystems/netatalk.nix
new file mode 100644
index 000000000000..bff54406a2b0
--- /dev/null
+++ b/nixos/modules/services/network-filesystems/netatalk.nix
@@ -0,0 +1,150 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.netatalk;
+
+  extmapFile = pkgs.writeText "extmap.conf" cfg.extmap;
+
+  afpToString = x: if builtins.typeOf x == "bool"
+                   then (if x then "true" else "false")
+                   else toString x;
+
+  volumeConfig = name:
+    let vol = getAttr name cfg.volumes; in
+    "[${name}]\n " + (toString (
+       map
+         (key: "${key} = ${afpToString (getAttr key vol)}\n")
+         (attrNames vol)
+    ));
+
+  afpConf = ''[Global]
+    extmap file = ${extmapFile}
+    afp port = ${toString cfg.port}
+
+    ${cfg.extraConfig}
+
+    ${if cfg.homes.enable then ''[Homes]
+    ${optionalString (cfg.homes.path != "") "path = ${cfg.homes.path}"}
+    basedir regex = ${cfg.homes.basedirRegex}
+    ${cfg.homes.extraConfig}
+    '' else ""}
+
+     ${toString (map volumeConfig (attrNames cfg.volumes))}
+  '';
+
+  afpConfFile = pkgs.writeText "afp.conf" afpConf;
+
+in
+
+{
+  options = {
+    services.netatalk = {
+
+      enable = mkOption {
+          default = false;
+          description = "Whether to enable the Netatalk AFP fileserver.";
+        };
+
+      port = mkOption {
+        default = 548;
+        description = "TCP port to be used for AFP.";
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        example = "uam list = uams_guest.so";
+        description = ''
+          Lines of configuration to add to the <literal>[Global]</literal> section.
+          See <literal>man apf.conf</literal> for more information.
+        '';
+      };
+
+      homes = {
+        enable = mkOption {
+          default = false;
+          description = "Enable sharing of the UNIX server user home directories.";
+        };
+
+        path = mkOption {
+          default = "";
+          example = "afp-data";
+          description = "Share not the whole user home but this subdirectory path.";
+        };
+
+        basedirRegex = mkOption {
+          example = "/home";
+          description = "Regex which matches the parent directory of the user homes.";
+        };
+
+        extraConfig = mkOption {
+          type = types.lines;
+          default = "";
+          description = ''
+            Lines of configuration to add to the <literal>[Homes]</literal> section.
+            See <literal>man apf.conf</literal> for more information.
+          '';
+         };
+      };
+
+      volumes = mkOption {
+        default = { };
+        type = types.attrsOf (types.attrsOf types.unspecified);
+        description =
+          ''
+            Set of AFP volumes to export.
+            See <literal>man apf.conf</literal> for more information.
+          '';
+        example =
+          { srv =
+             { path = "/srv";
+               "read only" = true;
+               "hosts allow" = "10.1.0.0/16 10.2.1.100 2001:0db8:1234::/48";
+             };
+          };
+      };
+
+      extmap = mkOption {
+        type = types.lines;
+	default = "";
+	description = ''
+	  File name extension mappings.
+	  See <literal>man extmap.conf</literal> for more information.
+        '';
+      };
+
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd.services.netatalk = {
+      description = "Netatalk AFP fileserver for Macintosh clients";
+      unitConfig.Documentation = "man:afp.conf(5) man:netatalk(8) man:afpd(8) man:cnid_metad(8) man:cnid_dbd(8)";
+      after = [ "network.target" "avahi-daemon.service" ];
+      wantedBy = [ "multi-user.target" ];
+
+      path = [ pkgs.netatalk ];
+
+      serviceConfig = {
+        Type = "forking";
+        GuessMainPID = "no";
+        PIDFile = "/run/lock/netatalk";
+	ExecStartPre = "${pkgs.coreutils}/bin/mkdir -m 0755 -p /var/lib/netatalk/CNID";
+        ExecStart  = "${pkgs.netatalk}/sbin/netatalk -F ${afpConfFile}";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP  $MAINPID";
+	ExecStop   = "${pkgs.coreutils}/bin/kill -TERM $MAINPID";
+        Restart = "always";
+        RestartSec = 1;
+      };
+
+    };
+
+    security.pam.services.netatalk.unixAuth = true;
+
+  };
+
+}
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index 576e5c9e87a3..a186982ec9c0 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -79,6 +79,14 @@ in
         description = ''
           Whether to enable Samba, which provides file and print
           services to Windows clients through the SMB/CIFS protocol.
+
+          <note>
+            <para>If you use the firewall consider adding the following:</para>
+            <programlisting>
+              networking.firewall.allowedTCPPorts = [ 139 445 ];
+              networking.firewall.allowedUDPPorts = [ 137 138 ];
+            </programlisting>
+          </note>
         '';
       };
 
@@ -86,7 +94,7 @@ in
         type = types.package;
         default = pkgs.samba;
         defaultText = "pkgs.samba";
-        example = literalExample "pkgs.samba4";
+        example = literalExample "pkgs.samba3";
         description = ''
           Defines which package should be used for the samba server.
         '';
@@ -118,6 +126,10 @@ in
         description = ''
           Additional global section and extra section lines go in here.
         '';
+        example = ''
+          guest account = nobody
+          map to guest = bad user
+        '';
       };
 
       configText = mkOption {
@@ -154,9 +166,11 @@ in
         '';
         type = types.attrsOf (types.attrsOf types.unspecified);
         example =
-          { srv =
-             { path = "/srv";
+          { public =
+             { path = "/srv/public";
                "read only" = true;
+               browseable = "yes";
+               "guest ok" = "yes";
                 comment = "Public samba share.";
              };
           };
diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix
index e7e1db191529..e76cdac14ca8 100644
--- a/nixos/modules/services/networking/bird.nix
+++ b/nixos/modules/services/networking/bird.nix
@@ -30,7 +30,7 @@ in
 
       user = mkOption {
         type = types.string;
-        default = "ircd";
+        default = "bird";
         description = ''
           BIRD Internet Routing Daemon user.
         '';
@@ -38,7 +38,7 @@ in
 
       group = mkOption {
         type = types.string;
-        default = "ircd";
+        default = "bird";
         description = ''
           BIRD Internet Routing Daemon group.
         '';
diff --git a/nixos/modules/services/networking/connman.nix b/nixos/modules/services/networking/connman.nix
index deb1cbfc1858..3fecfbb13a04 100644
--- a/nixos/modules/services/networking/connman.nix
+++ b/nixos/modules/services/networking/connman.nix
@@ -53,13 +53,13 @@ in {
   config = mkIf cfg.enable {
 
     assertions = [{
-      assertion = config.networking.useDHCP == false;
+      assertion = !config.networking.useDHCP;
       message = "You can not use services.networking.connman with services.networking.useDHCP";
     }{
-      assertion = config.networking.wireless.enable == true;
+      assertion = config.networking.wireless.enable;
       message = "You must use services.networking.connman with services.networking.wireless";
     }{
-      assertion = config.networking.networkmanager.enable == false;
+      assertion = !config.networking.networkmanager.enable;
       message = "You can not use services.networking.connman with services.networking.networkmanager";
     }];
 
diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix
index 58dad56014b0..2aa101f980da 100644
--- a/nixos/modules/services/networking/consul.nix
+++ b/nixos/modules/services/networking/consul.nix
@@ -33,6 +33,7 @@ in
       package = mkOption {
         type = types.package;
         default = pkgs.consul;
+        defaultText = "pkgs.consul";
         description = ''
           The package used for the Consul agent and CLI.
         '';
diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix
index ee06dfbbca3a..c5dd1e71c189 100644
--- a/nixos/modules/services/networking/ddclient.nix
+++ b/nixos/modules/services/networking/ddclient.nix
@@ -127,7 +127,6 @@ in
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
 
-      environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
       serviceConfig = {
         # Uncomment this if too many problems occur:
         # Type = "forking";
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix
index 9340be28205a..016b6a12cd61 100644
--- a/nixos/modules/services/networking/dnscrypt-proxy.nix
+++ b/nixos/modules/services/networking/dnscrypt-proxy.nix
@@ -52,7 +52,10 @@ in
         default = "opendns";
         type = types.nullOr types.string;
         description = ''
-          The name of the upstream DNSCrypt resolver to use.
+          The name of the upstream DNSCrypt resolver to use. See
+          <literal>${resolverListFile}</literal> for alternative resolvers
+          (e.g., if you are concerned about logging and/or server
+          location).
         '';
       };
       customResolver = mkOption {
diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix
index 7af11f37a43c..8ffce23a4b10 100644
--- a/nixos/modules/services/networking/ejabberd.nix
+++ b/nixos/modules/services/networking/ejabberd.nix
@@ -32,6 +32,7 @@ in {
       package = mkOption {
         type = types.package;
         default = pkgs.ejabberd;
+        defaultText = "pkgs.ejabberd";
         description = "ejabberd server package to use";
       };
 
diff --git a/nixos/modules/services/networking/gale.nix b/nixos/modules/services/networking/gale.nix
index 3a5d9bd63c7b..bc975159cdfd 100644
--- a/nixos/modules/services/networking/gale.nix
+++ b/nixos/modules/services/networking/gale.nix
@@ -76,7 +76,7 @@ in
 
        system.activationScripts.gale = mkIf cfg.enable (
          stringAfter [ "users" "groups" ] ''
-           chmod -R 755 ${home}
+           chmod 755 ${home}
            mkdir -m 0777 -p ${home}/auth/cache
            mkdir -m 1777 -p ${home}/auth/local # GALE_DOMAIN.gpub
            mkdir -m 0700 -p ${home}/auth/private # ROOT.gpub
@@ -86,7 +86,8 @@ in
            mkdir -m 0700 -p ${home}/.gale/auth/private # GALE_DOMAIN.gpri
 
            ln -sf ${pkgs.gale}/etc/gale/auth/trusted/ROOT "${home}/auth/trusted/ROOT"
-           chown -R ${cfg.user}:${cfg.group} ${home}
+           chown ${cfg.user}:${cfg.group} ${home} ${home}/auth ${home}/auth/*
+           chown ${cfg.user}:${cfg.group} ${home}/.gale ${home}/.gale/auth ${home}/.gale/auth/private
          ''
        );
 
@@ -149,10 +150,9 @@ in
          after = [ "network.target" ];
 
          preStart = ''
-           install -m 0640 ${keyPath}/${cfg.domain}.gpri "${home}/.gale/auth/private/"
-           install -m 0644 ${gpubFile} "${home}/.gale/auth/private/${cfg.domain}.gpub"
-           install -m 0644 ${gpubFile} "${home}/auth/local/${cfg.domain}.gpub"
-           chown -R ${cfg.user}:${cfg.group} ${home}
+           install -m 0640 -o ${cfg.user} -g ${cfg.group} ${keyPath}/${cfg.domain}.gpri "${home}/.gale/auth/private/"
+           install -m 0644 -o ${cfg.user} -g ${cfg.group} ${gpubFile} "${home}/.gale/auth/private/${cfg.domain}.gpub"
+           install -m 0644 -o ${cfg.user} -g ${cfg.group} ${gpubFile} "${home}/auth/local/${cfg.domain}.gpub"
          '';
 
          serviceConfig = {
diff --git a/nixos/modules/services/networking/gateone.nix b/nixos/modules/services/networking/gateone.nix
index 93273837181e..78ff0b76198c 100644
--- a/nixos/modules/services/networking/gateone.nix
+++ b/nixos/modules/services/networking/gateone.nix
@@ -21,7 +21,7 @@ options = {
 };
 config = mkIf cfg.enable {
   environment.systemPackages = with pkgs.pythonPackages; [
-    gateone pkgs.openssh pkgs.procps pkgs.coreutils ];
+    gateone pkgs.openssh pkgs.procps pkgs.coreutils pkgs.cacert];
 
   users.extraUsers.gateone = {
     description = "GateOne privilege separation user";
@@ -49,8 +49,6 @@ config = mkIf cfg.enable {
       User = "gateone";
       Group = "gateone";
       WorkingDirectory = cfg.settingsDir;
-      PermissionsStartOnly = true;
-
     };
 
     wantedBy = [ "multi-user.target" ];
diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix
index c467402dbcf6..c32b935cf940 100644
--- a/nixos/modules/services/networking/i2pd.nix
+++ b/nixos/modules/services/networking/i2pd.nix
@@ -12,21 +12,69 @@ let
 
   toOneZero = b: if b then "1" else "0";
 
+  mkEndpointOpt = name: addr: port: {
+    name = mkOption {
+      type = types.str;
+      default = name;
+      description = "The endpoint name.";
+    };
+    address = mkOption {
+      type = types.str;
+      default = addr;
+      description = "Bind address for ${name} endpoint. Default: " + addr;
+    };
+    port = mkOption {
+      type = types.int;
+      default = port;
+      description = "Bind port for ${name} endoint. Default: " + toString port;
+    };
+  };
+
+  commonTunOpts = let
+    i2cpOpts = {
+      length = mkOption {
+        type = types.int;
+        description = "Guaranteed minimum hops.";
+        default = 3;
+      };
+      quantity = mkOption {
+        type = types.int;
+        description = "Number of simultaneous tunnels.";
+        default = 5;
+      };
+    };
+  in name: {
+    outbound = i2cpOpts;
+    inbound = i2cpOpts;
+    crypto.tagsToSend = mkOption {
+      type = types.int;
+      description = "Number of ElGamal/AES tags to send.";
+      default = 40;
+    };
+   destination = mkOption {
+      type = types.str;
+      description = "Remote endpoint, I2P hostname or b32.i2p address.";
+    };
+    keys = mkOption {
+      type = types.str;
+      default = name + "-keys.dat";
+      description = "Keyset used for tunnel identity.";
+    };
+  } // mkEndpointOpt name "127.0.0.1" 0;
+
   i2pdConf = pkgs.writeText "i2pd.conf" ''
-      v6 = ${toOneZero cfg.enableIPv6}
-      unreachable = ${toOneZero cfg.unreachable}
+      ipv6 = ${toOneZero cfg.enableIPv6}
+      notransit = ${toOneZero cfg.notransit}
       floodfill = ${toOneZero cfg.floodfill}
       ${if isNull cfg.port then "" else "port = ${toString cfg.port}"}
-      httpproxyport = ${toString cfg.proxy.httpPort}
-      socksproxyport = ${toString cfg.proxy.socksPort}
-      ircaddress = ${cfg.irc.host}
-      ircport = ${toString cfg.irc.port}
-      ircdest = ${cfg.irc.dest}
-      irckeys = ${cfg.irc.keyFile}
-      eepport = ${toString cfg.eep.port}
-      ${if isNull cfg.sam.port then "" else "--samport=${toString cfg.sam.port}"}
-      eephost = ${cfg.eep.host}
-      eepkeys = ${cfg.eep.keyFile}
+      ${flip concatMapStrings
+        (collect (proto: proto ? port && proto ? address && proto ? name) cfg.proto)
+        (proto: let portStr = toString proto.port; in ''
+      [${proto.name}]
+      address = ${proto.address}
+      port = ${toString proto.port}
+      '')
+      }
   '';
 
   i2pdTunnelConf = pkgs.writeText "i2pd-tunnels.conf" ''
@@ -39,10 +87,15 @@ let
   keys = ${tun.keys}
   address = ${tun.address}
   port = ${toString tun.port}
+  inbound.length = ${toString tun.inbound.length}
+  outbound.length = ${toString tun.outbound.length}
+  inbound.quantity = ${toString tun.inbound.quantity}
+  outbound.quantity = ${toString tun.outbound.quantity}
+  crypto.tagsToSend = ${toString tun.crypto.tagsToSend}
   '')
   }
   ${flip concatMapStrings
-    (collect (tun: tun ? port && tun ? host) cfg.outTunnels)
+    (collect (tun: tun ? port && tun ? host) cfg.inTunnels)
     (tun: let portStr = toString tun.port; in ''
   [${tun.name}]
   type = server
@@ -59,10 +112,10 @@ let
   i2pdSh = pkgs.writeScriptBin "i2pd" ''
     #!/bin/sh
     ${if isNull cfg.extIp then extip else ""}
-    ${pkgs.i2pd}/bin/i2pd --log=1 --daemon=0 --service=0 \
+    ${pkgs.i2pd}/bin/i2pd --log=1 \
       --host=${if isNull cfg.extIp then "$EXTIP" else cfg.extIp} \
       --conf=${i2pdConf} \
-      --tunnelscfg=${i2pdTunnelConf}
+      --tunconf=${i2pdTunnelConf}
   '';
 
 in
@@ -91,11 +144,11 @@ in
         '';
       };
 
-      unreachable = mkOption {
+      notransit = mkOption {
         type = types.bool;
         default = false;
         description = ''
-          If the router is declared to be unreachable and needs introduction nodes.
+          Tells the router to not accept transit tunnels during startup.
         '';
       };
 
@@ -111,7 +164,7 @@ in
         type = with types; nullOr int;
         default = null;
         description = ''
-	        I2P listen port. If no one is given the router will pick between 9111 and 30777.
+          I2P listen port. If no one is given the router will pick between 9111 and 30777.
         '';
       };
 
@@ -123,184 +176,53 @@ in
         '';
       };
 
-      http = {
-        port = mkOption {
-          type = types.int;
-          default = 7070;
-          description = ''
-            HTTP listen port.
-          '';
-        };
-      };
-
-      proxy = {
-        httpPort = mkOption {
-          type = types.int;
-          default = 4446;
-          description = ''
-            HTTP proxy listen port.
-          '';
-        };
-        socksPort = mkOption {
-          type = types.int;
-          default = 4447;
-          description = ''
-            SOCKS proxy listen port.
-          '';
-        };
-      };
-
-      irc = {
-        host = mkOption {
-          type = types.str;
-          default = "127.0.0.1";
-          description = ''
-            Address to forward incoming traffic to. 127.0.0.1 by default.
-          '';
-        };
-        dest = mkOption {
-          type = types.str;
-          default = "irc.postman.i2p";
-          description = ''
-            Destination I2P tunnel endpoint address of IRC server. irc.postman.i2p by default.
-          '';
-        };
-        port = mkOption {
-          type = types.int;
-          default = 6668;
-          description = ''
-            Local IRC tunnel endoint port to listen on. 6668 by default.
-          '';
-        };
-        keyFile = mkOption {
-          type = types.str;
-          default = "privKeys.dat";
-          description = ''
-            File name containing destination keys. privKeys.dat by default.
-          '';
-        };
-      };
-
-      eep = {
-        host = mkOption {
-          type = types.str;
-          default = "127.0.0.1";
-          description = ''
-            Address to forward incoming traffic to. 127.0.0.1 by default.
-          '';
-        };
-        port = mkOption {
-          type = types.int;
-          default = 80;
-          description = ''
-            Port to forward incoming traffic to. 80 by default.
-          '';
-        };
-        keyFile = mkOption {
-          type = types.str;
-          default = "privKeys.dat";
-          description = ''
-            File name containing destination keys. privKeys.dat by default.
-          '';
-        };
-      };
-
-      sam = {
-        port = mkOption {
-          type = with types; nullOr int;
-          default = null;
-          description = ''
-            Local SAM tunnel endpoint. Usually 7656. SAM is disabled if not specified.
-          '';
-        };
-      };
+      proto.http = mkEndpointOpt "http" "127.0.0.1" 7070;
+      proto.sam = mkEndpointOpt "sam" "127.0.0.1" 7656;
+      proto.bob = mkEndpointOpt "bob" "127.0.0.1" 2827;
+      proto.i2pControl = mkEndpointOpt "i2pcontrol" "127.0.0.1" 7650;
+      proto.httpProxy = mkEndpointOpt "httpproxy" "127.0.0.1" 4446;
+      proto.socksProxy = mkEndpointOpt "socksproxy" "127.0.0.1" 4447;
 
       outTunnels = mkOption {
         default = {};
-	      type = with types; loaOf optionSet;
-	      description = ''
-	      '';
-	      options = [ ({ name, config, ... }: {
-
-	        options = {
-	          name = mkOption {
-	            type = types.str;
-	            description = "The name of the tunnel.";
-	          };
-	          destination = mkOption {
-	            type = types.str;
-	            description = "Remote endpoint, I2P hostname or b32.i2p address.";
-	          };
-	          keys = mkOption {
-	            type = types.str;
-	            default = name + "-keys.dat";
-	            description = "Keyset used for tunnel identity.";
-	          };
-	          address = mkOption {
-	            type = types.str;
-	            default = "127.0.0.1";
-	            description = "Local bind address for tunnel.";
-	          };
-	          port = mkOption {
-	            type = types.int;
-	            default = 0;
-	            description = "Local tunnel listen port.";
-	          };
-	        };
-
-	        config = {
-	          name = mkDefault name;
-	        };
-
-	      }) ];
+        type = with types; loaOf optionSet;
+        description = ''
+          Connect to someone as a client and establish a local accept endpoint
+        '';
+        options = [ ({ name, config, ... }: {
+          options = commonTunOpts name;
+          config = {
+            name = mkDefault name;
+          };
+        }) ];
       };
 
       inTunnels = mkOption {
         default = {};
-	      type = with types; loaOf optionSet;
-	      description = ''
-	      '';
-	      options = [ ({ name, config, ... }: {
-
-	        options = {
-
-	          name = mkOption {
-	            type = types.str;
-	            description = "The name of the tunnel.";
-	          };
-	          keys = mkOption {
-	            type = types.path;
-	            default = name + "-keys.dat";
-	            description = "Keyset used for tunnel identity.";
-	          };
-	          address = mkOption {
-	            type = types.str;
-	            default = "127.0.0.1";
-	            description = "Local service IP address.";
-	          };
-	          port = mkOption {
-	            type = types.int;
-	            default = 0;
-	            description = "Local tunnel listen port.";
-	          };
-	          inPort = mkOption {
-	            type = types.int;
-	            default = 0;
-	            description = "I2P service port. Default to the tunnel's listen port.";
-	          };
-	          accessList = mkOption {
-	            type = with types; listOf str;
-	            default = [];
-	            description = "I2P nodes that are allowed to connect to this service.";
-	          };
-
-	        };
-
-	        config = {
-	          name = mkDefault name;
-	        };
-
-	      }) ];
+        type = with types; loaOf optionSet;
+        description = ''
+          Serve something on I2P network at port and delegate requests to address inPort.
+        '';
+        options = [ ({ name, config, ... }: {
+
+          options = {
+            inPort = mkOption {
+              type = types.int;
+              default = 0;
+              description = "Service port. Default to the tunnel's listen port.";
+            };
+            accessList = mkOption {
+              type = with types; listOf str;
+              default = [];
+              description = "I2P nodes that are allowed to connect to this service.";
+            };
+          } // commonTunOpts name;
+
+          config = {
+            name = mkDefault name;
+          };
+
+        }) ];
       };
     };
   };
diff --git a/nixos/modules/services/networking/ifplugd.nix b/nixos/modules/services/networking/ifplugd.nix
deleted file mode 100644
index 00b94fe2284e..000000000000
--- a/nixos/modules/services/networking/ifplugd.nix
+++ /dev/null
@@ -1,82 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  inherit (pkgs) ifplugd;
-
-  cfg = config.networking.interfaceMonitor;
-
-  # The ifplugd action script, which is called whenever the link
-  # status changes (i.e., a cable is plugged in or unplugged).
-  plugScript = pkgs.writeScript "ifplugd.action"
-    ''
-      #! ${pkgs.stdenv.shell}
-      iface="$1"
-      status="$2"
-      ${cfg.commands}
-    '';
-
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    networking.interfaceMonitor.enable = mkOption {
-      type = types.bool;
-      default = false;
-      description = ''
-        If <literal>true</literal>, monitor Ethernet interfaces for
-        cables being plugged in or unplugged.  When this occurs, the
-        commands specified in
-        <option>networking.interfaceMonitor.commands</option> are
-        executed.
-      '';
-    };
-
-    networking.interfaceMonitor.beep = mkOption {
-      type = types.bool;
-      default = false;
-      description = ''
-        If <literal>true</literal>, beep when an Ethernet cable is
-        plugged in or unplugged.
-      '';
-    };
-
-    networking.interfaceMonitor.commands = mkOption {
-      type = types.lines;
-      default = "";
-      description = ''
-        Shell commands to be executed when the link status of an
-        interface changes.  On invocation, the shell variable
-        <varname>iface</varname> contains the name of the interface,
-        while the variable <varname>status</varname> contains either
-        <literal>up</literal> or <literal>down</literal> to indicate
-        the new status.
-      '';
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-    systemd.services.ifplugd = {
-      description = "Network interface connectivity monitor";
-      after = [ "network-interfaces.target" ];
-      wantedBy = [ "multi-user.target" ];
-      script = ''
-        ${ifplugd}/sbin/ifplugd --no-daemon --no-startup --no-shutdown \
-          ${if config.networking.interfaceMonitor.beep then "" else "--no-beep"} \
-          --run ${plugScript}
-      '';
-    };
-
-    environment.systemPackages = [ ifplugd ];
-  };
-}
diff --git a/nixos/modules/services/networking/kippo.nix b/nixos/modules/services/networking/kippo.nix
index 7d70a3d05fa7..5f3efcd133a1 100644
--- a/nixos/modules/services/networking/kippo.nix
+++ b/nixos/modules/services/networking/kippo.nix
@@ -54,7 +54,7 @@ rec {
   };
   config = mkIf cfg.enable {
     environment.systemPackages = with pkgs.pythonPackages; [
-      python twisted pycrypto pyasn1 ];
+      python twisted_11 pycrypto pyasn1 ];
 
     environment.etc."kippo.cfg".text = ''
         # Automatically generated by NixOS.
@@ -84,7 +84,7 @@ rec {
       description = "Kippo Web Server";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      environment.PYTHONPATH = "${pkgs.kippo}/src/:${pkgs.pythonPackages.pycrypto}/lib/python2.7/site-packages/:${pkgs.pythonPackages.pyasn1}/lib/python2.7/site-packages/:${pkgs.pythonPackages.python}/lib/python2.7/site-packages/:${pkgs.pythonPackages.twisted}/lib/python2.7/site-packages/:.";
+      environment.PYTHONPATH = "${pkgs.kippo}/src/:${pkgs.pythonPackages.pycrypto}/lib/python2.7/site-packages/:${pkgs.pythonPackages.pyasn1}/lib/python2.7/site-packages/:${pkgs.pythonPackages.python}/lib/python2.7/site-packages/:${pkgs.pythonPackages.twisted_11}/lib/python2.7/site-packages/:.";
       preStart = ''
         if [ ! -d ${cfg.varPath}/ ] ; then
             mkdir -p ${cfg.logPath}/tty
@@ -107,7 +107,7 @@ rec {
         fi
       '';
 
-      serviceConfig.ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd -y ${pkgs.kippo}/src/kippo.tac --syslog --rundir=${cfg.varPath}/ --pidfile=${cfg.pidPath}/kippo.pid --prefix=kippo -n";
+      serviceConfig.ExecStart = "${pkgs.pythonPackages.twisted_11}/bin/twistd -y ${pkgs.kippo}/src/kippo.tac --syslog --rundir=${cfg.varPath}/ --pidfile=${cfg.pidPath}/kippo.pid --prefix=kippo -n";
       serviceConfig.PermissionsStartOnly = true;
       serviceConfig.User = "kippo"; 
       serviceConfig.Group = "kippo"; 
diff --git a/nixos/modules/services/networking/libreswan.nix b/nixos/modules/services/networking/libreswan.nix
new file mode 100644
index 000000000000..3866b216f8ef
--- /dev/null
+++ b/nixos/modules/services/networking/libreswan.nix
@@ -0,0 +1,126 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.libreswan;
+
+  libexec = "${pkgs.libreswan}/libexec/ipsec";
+  ipsec = "${pkgs.libreswan}/sbin/ipsec";
+
+  trim = chars: str: let
+      nonchars = filter (x : !(elem x.value chars))
+                  (imap (i: v: {ind = (sub i 1); value = v;}) (stringToCharacters str));
+    in
+      if length nonchars == 0 then ""
+      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: 
+    ''
+      conn ${n}
+      ${indent v}
+
+    '') cfg.connections);
+  configFile = pkgs.writeText "ipsec.conf"
+    ''
+      config setup
+      ${configText}
+      
+      ${connectionText}
+    '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.libreswan = {
+
+      enable = mkEnableOption "libreswan ipsec service";
+
+      configSetup = mkOption {
+        type = types.lines;
+        default = ''
+            protostack=netkey
+            nat_traversal=yes
+            virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v4:100.64.0.0/10,%v6:fd00::/8,%v6:fe80::/10
+        '';
+        example = ''
+            secretsfile=/root/ipsec.secrets
+            protostack=netkey
+            nat_traversal=yes
+            virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v4:100.64.0.0/10,%v6:fd00::/8,%v6:fe80::/10
+        '';
+        description = "Options to go in the 'config setup' section of the libreswan ipsec configuration";
+      };
+
+      connections = mkOption {
+        type = types.attrsOf types.lines;
+        default = {};
+        example = {
+          myconnection = ''
+            auto=add
+            left=%defaultroute
+            leftid=@user
+
+            right=my.vpn.com
+
+            ikev2=no
+            ikelifetime=8h
+          '';
+        };
+        description = "A set of connections to define for the libreswan ipsec service";
+      };
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.libreswan pkgs.iproute ];
+
+    systemd.services.ipsec = {
+      description = "Internet Key Exchange (IKE) Protocol Daemon for IPsec";
+      path = [
+        "${pkgs.libreswan}"
+        "${pkgs.iproute}"
+        "${pkgs.procps}"
+      ];
+
+      wants = [ "network-online.target" ];
+      after = [ "network-online.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = {
+        Type = "simple";
+        Restart = "always";
+        EnvironmentFile = "${pkgs.libreswan}/etc/sysconfig/pluto";
+        ExecStartPre = [
+          "${libexec}/addconn --config ${configFile} --checkconfig"
+          "${libexec}/_stackmanager start"
+          "${ipsec} --checknss"
+          "${ipsec} --checknflog"
+        ];
+        ExecStart = "${libexec}/pluto --config ${configFile} --nofork \$PLUTO_OPTIONS";
+        ExecStop = "${libexec}/whack --shutdown";
+        ExecStopPost = [
+          "${pkgs.iproute}/bin/ip xfrm policy flush"
+          "${pkgs.iproute}/bin/ip xfrm state flush"
+          "${ipsec} --stopnflog"
+        ];
+        ExecReload = "${libexec}/whack --listen";
+      };
+
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index 01c05fb4a245..9912ad9ae3fc 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -21,6 +21,9 @@ let
 
     [logging]
     level=WARN
+
+    [connection]
+    ipv6.ip6-privacy=2
   '';
 
   /*
@@ -228,6 +231,11 @@ in {
     users.extraUsers = [{
       name = "nm-openvpn";
       uid = config.ids.uids.nm-openvpn;
+    }
+    {
+      # to enable link-local connections
+      name = "avahi-autoipd";
+      uid = config.ids.uids.avahi-autoipd;
     }];
 
     systemd.packages = cfg.packages;
diff --git a/nixos/modules/services/networking/nix-serve.nix b/nixos/modules/services/networking/nix-serve.nix
index 880a1d361dfe..8f6881441cf7 100644
--- a/nixos/modules/services/networking/nix-serve.nix
+++ b/nixos/modules/services/networking/nix-serve.nix
@@ -50,7 +50,7 @@ in
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
 
-      path = [ config.nix.package pkgs.bzip2 ];
+      path = [ config.nix.package pkgs.bzip2.bin ];
       environment.NIX_REMOTE = "daemon";
       environment.NIX_SECRET_KEY_FILE = cfg.secretKeyFile;
 
diff --git a/nixos/modules/services/networking/nntp-proxy.nix b/nixos/modules/services/networking/nntp-proxy.nix
new file mode 100644
index 000000000000..cfa662c7311b
--- /dev/null
+++ b/nixos/modules/services/networking/nntp-proxy.nix
@@ -0,0 +1,235 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  inherit (pkgs) nntp-proxy;
+
+  proxyUser = "nntp-proxy";
+
+  cfg = config.services.nntp-proxy;
+
+  configBool = b: if b then "TRUE" else "FALSE";
+
+  confFile = pkgs.writeText "nntp-proxy.conf" ''
+    nntp_server:
+    {
+      # NNTP Server host and port address
+      server = "${cfg.upstreamServer}";
+      port = ${toString cfg.upstreamPort};
+      # NNTP username
+      username = "${cfg.upstreamUser}";
+      # NNTP password in clear text
+      password = "${cfg.upstreamPassword}";
+      # Maximum number of connections allowed by the NNTP
+      max_connections = ${toString cfg.upstreamMaxConnections};
+    };
+
+    proxy:
+    {
+      # Local address and port to bind to
+      bind_ip = "${cfg.listenAddress}";
+      bind_port = ${toString cfg.port};
+
+      # SSL key and cert file
+      ssl_key = "${cfg.sslKey}";
+      ssl_cert = "${cfg.sslCert}";
+
+      # prohibit users from posting
+      prohibit_posting = ${configBool cfg.prohibitPosting};
+      # Verbose levels: ERROR, WARNING, NOTICE, INFO, DEBUG
+      verbose = "${toUpper cfg.verbosity}";
+      # Password is made with: 'mkpasswd -m sha-512 <password>'
+      users = (${concatStringsSep ",\n" (mapAttrsToList (username: userConfig:
+        ''
+          {
+              username = "${username}";
+              password = "${userConfig.passwordHash}";
+              max_connections = ${toString userConfig.maxConnections};
+          }
+        '') cfg.users)});
+    };
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.nntp-proxy = {
+      enable = mkEnableOption "NNTP-Proxy";
+
+      upstreamServer = mkOption {
+        type = types.str;
+        default = "";
+        example = "ssl-eu.astraweb.com";
+        description = ''
+          Upstream server address
+        '';
+      };
+
+      upstreamPort = mkOption {
+        type = types.int;
+        default = 563;
+        description = ''
+          Upstream server port
+        '';
+      };
+
+      upstreamMaxConnections = mkOption {
+        type = types.int;
+        default = 20;
+        description = ''
+          Upstream server maximum allowed concurrent connections
+        '';
+      };
+
+      upstreamUser = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Upstream server username
+        '';
+      };
+
+      upstreamPassword = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Upstream server password
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        example = "[::]";
+        description = ''
+          Proxy listen address (IPv6 literal addresses need to be enclosed in "[" and "]" characters)
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 5555;
+        description = ''
+          Proxy listen port
+        '';
+      };
+
+      sslKey = mkOption {
+        type = types.str;
+        default = "key.pem";
+        example = "/path/to/your/key.file";
+        description = ''
+          Proxy ssl key path
+        '';
+      };
+
+      sslCert = mkOption {
+        type = types.str;
+        default = "cert.pem";
+        example = "/path/to/your/cert.file";
+        description = ''
+          Proxy ssl certificate path
+        '';
+      };
+
+      prohibitPosting = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to prohibit posting to the upstream server
+        '';
+      };
+
+      verbosity = mkOption {
+        type = types.str;
+        default = "info";
+        example = "error";
+        description = ''
+          Verbosity level (error, warning, notice, info, debug)
+        '';
+      };
+
+      users = mkOption {
+        type = types.attrsOf (types.submodule {
+          options = {
+            username = mkOption {
+              type = types.str;
+              default = null;
+              description = ''
+                Username
+              '';
+            };
+
+            passwordHash = mkOption {
+              type = types.str;
+              default = null;
+              example = "$6$GtzE7FrpE$wwuVgFYU.TZH4Rz.Snjxk9XGua89IeVwPQ/fEUD8eujr40q5Y021yhn0aNcsQ2Ifw.BLclyzvzgegopgKcneL0";
+              description = ''
+                SHA-512 password hash (can be generated by
+                <code>mkpasswd -m sha-512 &lt;password&gt;</code>)
+              '';
+            };
+
+            maxConnections = mkOption {
+              type = types.int;
+              default = 1;
+              description = ''
+                Maximum number of concurrent connections to the proxy for this user
+              '';
+            };
+          };
+        });
+        description = ''
+          NNTP-Proxy user configuration
+        '';
+
+        default = {};
+        example = literalExample ''
+          "user1" = {
+            passwordHash = "$6$1l0t5Kn2Dk$appzivc./9l/kjq57eg5UCsBKlcfyCr0zNWYNerKoPsI1d7eAwiT0SVsOVx/CTgaBNT/u4fi2vN.iGlPfv1ek0";
+            maxConnections = 5;
+          };
+          "anotheruser" = {
+            passwordHash = "$6$6lwEsWB.TmsS$W7m1riUx4QrA8pKJz8hvff0dnF1NwtZXgdjmGqA1Dx2MDPj07tI9GNcb0SWlMglE.2/hBgynDdAd/XqqtRqVQ0";
+            maxConnections = 7;
+          };
+        '';
+      };
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = singleton
+      { name = proxyUser;
+        uid = config.ids.uids.nntp-proxy;
+        description = "NNTP-Proxy daemon user";
+      };
+
+    systemd.services.nntp-proxy = {
+      description = "NNTP proxy";
+      after = [ "network.target" "nss-lookup.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = { User="${proxyUser}"; };
+      serviceConfig.ExecStart = "${nntp-proxy}/bin/nntp-proxy ${confFile}";
+      preStart = ''
+        if [ ! \( -f ${cfg.sslCert} -a -f ${cfg.sslKey} \) ]; then
+          ${pkgs.openssl}/bin/openssl req -subj '/CN=AutoGeneratedCert/O=NixOS Service/C=US' \
+          -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout ${cfg.sslKey} -out ${cfg.sslCert};
+        fi
+      '';
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix
index e85f26811257..333a3378c4cc 100644
--- a/nixos/modules/services/networking/nsd.nix
+++ b/nixos/modules/services/networking/nsd.nix
@@ -7,92 +7,118 @@ let
 
   username = "nsd";
   stateDir = "/var/lib/nsd";
-  pidFile  = stateDir + "/var/nsd.pid";
+  pidFile = stateDir + "/var/nsd.pid";
 
+  # build nsd with the options needed for the given config
   nsdPkg = pkgs.nsd.override {
     bind8Stats = cfg.bind8Stats;
-    ipv6       = cfg.ipv6;
-    ratelimit  = cfg.ratelimit.enable;
+    ipv6 = cfg.ipv6;
+    ratelimit = cfg.ratelimit.enable;
     rootServer = cfg.rootServer;
-    zoneStats  = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0;
+    zoneStats = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0;
   };
 
-  zoneFiles = pkgs.stdenv.mkDerivation {
-    preferLocalBuild = true;
+
+  nsdEnv = pkgs.buildEnv {
     name = "nsd-env";
-    buildCommand = concatStringsSep "\n"
-      [ "mkdir -p $out"
-        (concatStrings (mapAttrsToList (zoneName: zoneOptions: ''
-          cat > "$out/${zoneName}" <<_EOF_
-          ${zoneOptions.data}
-          _EOF_
-        '') zoneConfigs))
-      ];
+
+    paths = [ configFile ]
+      ++ mapAttrsToList (name: zone: writeZoneData name zone.data) zoneConfigs;
+
+    postBuild = ''
+      echo "checking zone files"
+      cd $out/zones
+
+      for zoneFile in *; do
+        ${nsdPkg}/sbin/nsd-checkzone "$zoneFile" "$zoneFile" || {
+          if grep -q \\\\\\$ "$zoneFile"; then
+            echo zone "$zoneFile" contains escaped dollar signes \\\$
+            echo Escaping them is not needed any more. Please make shure \
+                 to unescape them where they prefix a variable name
+          fi
+
+          exit 1
+        }
+      done
+
+      echo "checking configuration file"
+      ${nsdPkg}/sbin/nsd-checkconf $out/nsd.conf
+    '';
+  };
+
+  writeZoneData = name: text: pkgs.writeTextFile {
+    inherit name text;
+    destination = "/zones/${name}";
   };
 
-  configFile = pkgs.writeText "nsd.conf" ''
+
+  # options are ordered alphanumerically by the nixos option name
+  configFile = pkgs.writeTextDir "nsd.conf" ''
     server:
-      username: ${username}
       chroot:   "${stateDir}"
+      username: ${username}
 
       # The directory for zonefile: files. The daemon chdirs here.
       zonesdir: "${stateDir}"
 
       # the list of dynamically added zones.
-      zonelistfile: "${stateDir}/var/zone.list"
       database:     "${stateDir}/var/nsd.db"
       pidfile:      "${pidFile}"
       xfrdfile:     "${stateDir}/var/xfrd.state"
       xfrdir:       "${stateDir}/tmp"
+      zonelistfile: "${stateDir}/var/zone.list"
 
       # interfaces
     ${forEach "  ip-address: " cfg.interfaces}
 
-      server-count:        ${toString cfg.serverCount}
+      hide-version:        ${yesOrNo  cfg.hideVersion}
+      identity:            "${cfg.identity}"
       ip-transparent:      ${yesOrNo  cfg.ipTransparent}
       do-ip4:              ${yesOrNo  cfg.ipv4}
+      ipv4-edns-size:      ${toString cfg.ipv4EDNSSize}
       do-ip6:              ${yesOrNo  cfg.ipv6}
-      port:                ${toString cfg.port}
-      verbosity:           ${toString cfg.verbosity}
-      hide-version:        ${yesOrNo  cfg.hideVersion}
-      identity:            "${cfg.identity}"
+      ipv6-edns-size:      ${toString cfg.ipv6EDNSSize}
+      log-time-ascii:      ${yesOrNo  cfg.logTimeAscii}
       ${maybeString "nsid: " cfg.nsid}
+      port:                ${toString cfg.port}
+      reuseport:           ${yesOrNo  cfg.reuseport}
+      round-robin:         ${yesOrNo  cfg.roundRobin}
+      server-count:        ${toString cfg.serverCount}
+      ${if cfg.statistics == null then "" else "statistics:          ${toString cfg.statistics}"}
       tcp-count:           ${toString cfg.tcpCount}
       tcp-query-count:     ${toString cfg.tcpQueryCount}
       tcp-timeout:         ${toString cfg.tcpTimeout}
-      ipv4-edns-size:      ${toString cfg.ipv4EDNSSize}
-      ipv6-edns-size:      ${toString cfg.ipv6EDNSSize}
-      ${if cfg.statistics == null then "" else "statistics:          ${toString cfg.statistics}"}
+      verbosity:           ${toString cfg.verbosity}
+      ${maybeString "version: " cfg.version}
       xfrd-reload-timeout: ${toString cfg.xfrdReloadTimeout}
       zonefiles-check:     ${yesOrNo  cfg.zonefilesCheck}
 
-      rrl-size:                ${toString cfg.ratelimit.size}
-      rrl-ratelimit:           ${toString cfg.ratelimit.ratelimit}
-      rrl-whitelist-ratelimit: ${toString cfg.ratelimit.whitelistRatelimit}
-      ${maybeString "rrl-slip: "               cfg.ratelimit.slip}
       ${maybeString "rrl-ipv4-prefix-length: " cfg.ratelimit.ipv4PrefixLength}
       ${maybeString "rrl-ipv6-prefix-length: " cfg.ratelimit.ipv6PrefixLength}
+      rrl-ratelimit:           ${toString cfg.ratelimit.ratelimit}
+      ${maybeString "rrl-slip: "               cfg.ratelimit.slip}
+      rrl-size:                ${toString cfg.ratelimit.size}
+      rrl-whitelist-ratelimit: ${toString cfg.ratelimit.whitelistRatelimit}
 
     ${keyConfigFile}
 
     remote-control:
       control-enable:    ${yesOrNo  cfg.remoteControl.enable}
+      control-key-file:  "${cfg.remoteControl.controlKeyFile}"
+      control-cert-file: "${cfg.remoteControl.controlCertFile}"
     ${forEach "  control-interface: " cfg.remoteControl.interfaces}
-      control-port:      ${toString cfg.port}
+      control-port:      ${toString cfg.remoteControl.port}
       server-key-file:   "${cfg.remoteControl.serverKeyFile}"
       server-cert-file:  "${cfg.remoteControl.serverCertFile}"
-      control-key-file:  "${cfg.remoteControl.controlKeyFile}"
-      control-cert-file: "${cfg.remoteControl.controlCertFile}"
 
-    # zone files reside in "${zoneFiles}" linked to "${stateDir}/zones"
     ${concatStrings (mapAttrsToList zoneConfigFile zoneConfigs)}
 
     ${cfg.extraConfig}
   '';
 
-  yesOrNo     = b: if b then "yes" else "no";
+  yesOrNo = b: if b then "yes" else "no";
   maybeString = pre: s: if s == null then "" else ''${pre} "${s}"'';
-  forEach     = pre: l: concatMapStrings (x: pre + x + "\n") l;
+  forEach = pre: l: concatMapStrings (x: pre + x + "\n") l;
 
 
   keyConfigFile = concatStrings (mapAttrsToList (keyName: keyOptions: ''
@@ -106,22 +132,23 @@ let
     secret=$(cat "${keyOptions.keyFile}")
     dest="${stateDir}/private/${keyName}"
     echo "  secret: \"$secret\"" > "$dest"
-    ${pkgs.coreutils}/bin/chown ${username}:${username} "$dest"
-    ${pkgs.coreutils}/bin/chmod 0400 "$dest"
+    chown ${username}:${username} "$dest"
+    chmod 0400 "$dest"
   '') cfg.keys);
 
 
+  # options are ordered alphanumerically by the nixos option name
   zoneConfigFile = name: zone: ''
     zone:
       name:         "${name}"
       zonefile:     "${stateDir}/zones/${name}"
-      ${maybeString "zonestats: "          zone.zoneStats}
       ${maybeString "outgoing-interface: " zone.outgoingInterface}
     ${forEach     "  rrl-whitelist: "      zone.rrlWhitelist}
+      ${maybeString "zonestats: "          zone.zoneStats}
 
+      allow-axfr-fallback: ${yesOrNo       zone.allowAXFRFallback}
     ${forEach     "  allow-notify: "       zone.allowNotify}
     ${forEach     "  request-xfr: "        zone.requestXFR}
-      allow-axfr-fallback: ${yesOrNo       zone.allowAXFRFallback}
 
     ${forEach     "  notify: "             zone.notify}
       notify-retry:                        ${toString zone.notifyRetry}
@@ -142,7 +169,7 @@ let
       );
 
   # fighting infinite recursion
-  zoneOptions  = zoneOptionsRaw // childConfig zoneOptions1 true;
+  zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true;
   zoneOptions1 = zoneOptionsRaw // childConfig zoneOptions2 false;
   zoneOptions2 = zoneOptionsRaw // childConfig zoneOptions3 false;
   zoneOptions3 = zoneOptionsRaw // childConfig zoneOptions4 false;
@@ -152,26 +179,25 @@ let
 
   childConfig = x: v: { options.children = { type = types.attrsOf x; visible = v; }; };
 
+  # options are ordered alphanumerically
   zoneOptionsRaw = types.submodule {
     options = {
-      children = mkOption {
-        default     = {};
+
+      allowAXFRFallback = mkOption {
+        type = types.bool;
+        default = true;
         description = ''
-          Children zones inherit all options of their parents. Attributes
-          defined in a child will overwrite the ones of its parent. Only
-          leaf zones will be actually served. This way it's possible to
-          define maybe zones which share most attributes without
-          duplicating everything. This mechanism replaces nsd's patterns
-          in a save and functional way.
+          If NSD as secondary server should be allowed to AXFR if the primary
+          server does not allow IXFR.
         '';
       };
 
       allowNotify = mkOption {
-        type        = types.listOf types.str;
-        default     = [ ];
-        example     = [ "192.0.2.0/24 NOKEY" "10.0.0.1-10.0.0.5 my_tsig_key_name"
-                        "10.0.3.4&255.255.0.0 BLOCKED"
-                      ];
+        type = types.listOf types.str;
+        default = [ ];
+        example = [ "192.0.2.0/24 NOKEY" "10.0.0.1-10.0.0.5 my_tsig_key_name"
+                    "10.0.3.4&255.255.0.0 BLOCKED"
+                  ];
         description = ''
           Listed primary servers are allowed to notify this secondary server.
           <screen><![CDATA[
@@ -193,28 +219,32 @@ let
         '';
       };
 
-      requestXFR = mkOption {
-        type        = types.listOf types.str;
-        default     = [];
-        example     = [];
+      children = mkOption {
+        default = {};
         description = ''
-          Format: <code>[AXFR|UDP] &lt;ip-address&gt; &lt;key-name | NOKEY&gt;</code>
+          Children zones inherit all options of their parents. Attributes
+          defined in a child will overwrite the ones of its parent. Only
+          leaf zones will be actually served. This way it's possible to
+          define maybe zones which share most attributes without
+          duplicating everything. This mechanism replaces nsd's patterns
+          in a save and functional way.
         '';
       };
 
-      allowAXFRFallback = mkOption {
-        type        = types.bool;
-        default     = true;
+      data = mkOption {
+        type = types.str;
+        default = "";
+        example = "";
         description = ''
-          If NSD as secondary server should be allowed to AXFR if the primary
-          server does not allow IXFR.
+          The actual zone data. This is the content of your zone file.
+          Use imports or pkgs.lib.readFile if you don't want this data in your config file.
         '';
       };
 
       notify = mkOption {
-        type        = types.listOf types.str;
-        default     = [];
-        example     = [ "10.0.0.1@3721 my_key" "::5 NOKEY" ];
+        type = types.listOf types.str;
+        default = [];
+        example = [ "10.0.0.1@3721 my_key" "::5 NOKEY" ];
         description = ''
           This primary server will notify all given secondary servers about
           zone changes.
@@ -231,38 +261,47 @@ let
       };
 
       notifyRetry = mkOption {
-        type        = types.int;
-        default     = 5;
+        type = types.int;
+        default = 5;
         description = ''
           Specifies the number of retries for failed notifies. Set this along with notify.
         '';
       };
 
+      outgoingInterface = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "2000::1@1234";
+        description = ''
+          This address will be used for zone-transfere requests if configured
+          as a secondary server or notifications in case of a primary server.
+          Supply either a plain IPv4 or IPv6 address with an optional port
+          number (ip@port).
+        '';
+      };
+
       provideXFR = mkOption {
-        type        = types.listOf types.str;
-        default     = [];
-        example     = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ];
+        type = types.listOf types.str;
+        default = [];
+        example = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ];
         description = ''
           Allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED
           address range 192.0.2.0/24, 1.2.3.4&amp;255.255.0.0, 3.0.2.20-3.0.2.40
         '';
       };
 
-      outgoingInterface = mkOption {
-        type        = types.nullOr types.str;
-        default     = null;
-        example     = "2000::1@1234";
+      requestXFR = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [];
         description = ''
-          This address will be used for zone-transfere requests if configured
-          as a secondary server or notifications in case of a primary server.
-          Supply either a plain IPv4 or IPv6 address with an optional port
-          number (ip@port).
+          Format: <code>[AXFR|UDP] &lt;ip-address&gt; &lt;key-name | NOKEY&gt;</code>
         '';
       };
 
       rrlWhitelist = mkOption {
-        type        = types.listOf types.str;
-        default     = [];
+        type = types.listOf types.str;
+        default = [];
         description = ''
           Whitelists the given rrl-types.
           The RRL classification types are:  nxdomain,  error, referral, any,
@@ -270,20 +309,10 @@ let
         '';
       };
 
-      data = mkOption {
-        type        = types.str;
-        default     = "";
-        example     = "";
-        description = ''
-          The actual zone data. This is the content of your zone file.
-          Use imports or pkgs.lib.readFile if you don't want this data in your config file.
-        '';
-      };
-
       zoneStats = mkOption {
-        type        = types.nullOr types.str;
-        default     = null;
-        example     = "%s";
+        type = types.nullOr types.str;
+        default = null;
+        example = "%s";
         description = ''
           When set to something distinct to null NSD is able to collect
           statistics per zone. All statistics of this zone(s) will be added
@@ -292,419 +321,470 @@ let
           and stats_noreset.
         '';
       };
+
     };
   };
 
 in
 {
-  options = {
-    services.nsd = {
+  # options are ordered alphanumerically
+  options.services.nsd = {
 
-      enable = mkEnableOption "NSD authoritative DNS server";
-      bind8Stats = mkEnableOption "BIND8 like statistics";
+    enable = mkEnableOption "NSD authoritative DNS server";
 
-      rootServer = mkOption {
-        type        = types.bool;
-        default     = false;
-        description = ''
-          Wheter if this server will be a root server (a DNS root server, you
-          usually don't want that).
-        '';
-      };
+    bind8Stats = mkEnableOption "BIND8 like statistics";
 
-      interfaces = mkOption {
-        type        = types.listOf types.str;
-        default     = [ "127.0.0.0" "::1" ];
-        description = ''
-          What addresses the server should listen to.
-        '';
-      };
+    extraConfig = mkOption {
+      type = types.str;
+      default = "";
+      description = ''
+        Extra nsd config.
+      '';
+    };
 
-      serverCount = mkOption {
-        type        = types.int;
-        default     = 1;
-        description = ''
-          Number of NSD servers to fork. Put the number of CPUs to use here.
-        '';
-      };
+    hideVersion = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries.
+      '';
+    };
 
-      ipTransparent = mkOption {
-        type        = types.bool;
-        default     = false;
-        description = ''
-          Allow binding to non local addresses.
-        '';
-      };
+    identity = mkOption {
+      type = types.str;
+      default = "unidentified server";
+      description = ''
+        Identify the server (CH TXT ID.SERVER entry).
+      '';
+    };
 
-      ipv4 = mkOption {
-        type        = types.bool;
-        default     = true;
-        description = ''
-          Wheter to listen on IPv4 connections.
-        '';
-      };
+    interfaces = mkOption {
+      type = types.listOf types.str;
+      default = [ "127.0.0.0" "::1" ];
+      description = ''
+        What addresses the server should listen to.
+      '';
+    };
 
-      ipv6 = mkOption {
-        type        = types.bool;
-        default     = true;
-        description = ''
-          Wheter to listen on IPv6 connections.
-        '';
-      };
+    ipTransparent = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Allow binding to non local addresses.
+      '';
+    };
 
-      port = mkOption {
-        type        = types.int;
-        default     = 53;
-        description = ''
-          Port the service should bind do.
-        '';
-      };
+    ipv4 = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to listen on IPv4 connections.
+      '';
+    };
 
-      verbosity = mkOption {
-        type        = types.int;
-        default     = 0;
-        description = ''
-          Verbosity level.
-        '';
-      };
+    ipv4EDNSSize = mkOption {
+      type = types.int;
+      default = 4096;
+      description = ''
+        Preferred EDNS buffer size for IPv4.
+      '';
+    };
+
+    ipv6 = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to listen on IPv6 connections.
+      '';
+    };
+
+    ipv6EDNSSize = mkOption {
+      type = types.int;
+      default = 4096;
+      description = ''
+        Preferred EDNS buffer size for IPv6.
+      '';
+    };
+
+    logTimeAscii = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Log time in ascii, if false then in unix epoch seconds.
+      '';
+    };
+
+    nsid = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        NSID identity (hex string, or "ascii_somestring").
+      '';
+    };
+
+    port = mkOption {
+      type = types.int;
+      default = 53;
+      description = ''
+        Port the service should bind do.
+      '';
+    };
+
+    reuseport = mkOption {
+      type = types.bool;
+      default = pkgs.stdenv.isLinux;
+      description = ''
+        Whether to enable SO_REUSEPORT on all used sockets. This lets multiple
+        processes bind to the same port. This speeds up operation especially
+        if the server count is greater than one and makes fast restarts less
+        prone to fail
+      '';
+    };
+
+    rootServer = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether this server will be a root server (a DNS root server, you
+        usually don't want that).
+      '';
+    };
+
+    roundRobin = mkEnableOption "round robin rotation of records";
+
+    serverCount = mkOption {
+      type = types.int;
+      default = 1;
+      description = ''
+        Number of NSD servers to fork. Put the number of CPUs to use here.
+      '';
+    };
+
+    statistics = mkOption {
+      type = types.nullOr types.int;
+      default = null;
+      description = ''
+        Statistics are produced every number of seconds. Prints to log.
+        If null no statistics are logged.
+      '';
+    };
+
+    tcpCount = mkOption {
+      type = types.int;
+      default = 100;
+      description = ''
+        Maximum number of concurrent TCP connections per server.
+      '';
+    };
+
+    tcpQueryCount = mkOption {
+      type = types.int;
+      default = 0;
+      description = ''
+        Maximum number of queries served on a single TCP connection.
+        0 means no maximum.
+      '';
+    };
+
+    tcpTimeout = mkOption {
+      type = types.int;
+      default = 120;
+      description = ''
+        TCP timeout in seconds.
+      '';
+    };
+
+    verbosity = mkOption {
+      type = types.int;
+      default = 0;
+      description = ''
+        Verbosity level.
+      '';
+    };
+
+    version = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The version string replied for CH TXT version.server and version.bind
+        queries. Will use the compiled package version on null.
+        See hideVersion for enabling/disabling this responses.
+      '';
+    };
+
+    xfrdReloadTimeout = mkOption {
+      type = types.int;
+      default = 1;
+      description = ''
+        Number of seconds between reloads triggered by xfrd.
+      '';
+    };
+
+    zonefilesCheck = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to check mtime of all zone files on start and sighup.
+      '';
+    };
+
+
+    keys = mkOption {
+      type = types.attrsOf (types.submodule {
+        options = {
+
+          algorithm = mkOption {
+            type = types.str;
+            default = "hmac-sha256";
+            description = ''
+              Authentication algorithm for this key.
+            '';
+          };
+
+          keyFile = mkOption {
+            type = types.path;
+            description = ''
+              Path to the file which contains the actual base64 encoded
+              key. The key will be copied into "${stateDir}/private" before
+              NSD starts. The copied file is only accessibly by the NSD
+              user.
+            '';
+          };
+
+        };
+      });
+      default = {};
+      example = literalExample ''
+        { "tsig.example.org" = {
+            algorithm = "hmac-md5";
+            keyFile = "/path/to/my/key";
+          };
+        }
+      '';
+      description = ''
+        Define your TSIG keys here.
+      '';
+    };
+
+
+    ratelimit = {
+
+      enable = mkEnableOption "ratelimit capabilities";
 
-      hideVersion = mkOption {
-        type        = types.bool;
-        default     = true;
+      ipv4PrefixLength = mkOption {
+        type = types.nullOr types.int;
+        default = null;
         description = ''
-          Wheter NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries.
+          IPv4 prefix length. Addresses are grouped by netblock.
         '';
       };
 
-      identity = mkOption {
-        type        = types.str;
-        default     = "unidentified server";
+      ipv6PrefixLength = mkOption {
+        type = types.nullOr types.int;
+        default = null;
         description = ''
-          Identify the server (CH TXT ID.SERVER entry).
+          IPv6 prefix length. Addresses are grouped by netblock.
         '';
       };
 
-      nsid = mkOption {
-        type        = types.nullOr types.str;
-        default     = null;
+      ratelimit = mkOption {
+        type = types.int;
+        default = 200;
         description = ''
-          NSID identity (hex string, or "ascii_somestring").
+          Max qps allowed from any query source.
+          0 means unlimited. With an verbosity of 2 blocked and
+          unblocked subnets will be logged.
         '';
       };
 
-      tcpCount = mkOption {
-        type        = types.int;
-        default     = 100;
+      slip = mkOption {
+        type = types.nullOr types.int;
+        default = null;
         description = ''
-          Maximum number of concurrent TCP connections per server.
+          Number of packets that get discarded before replying a SLIP response.
+          0 disables SLIP responses. 1 will make every response a SLIP response.
         '';
       };
 
-      tcpQueryCount = mkOption {
-        type        = types.int;
-        default     = 0;
+      size = mkOption {
+        type = types.int;
+        default = 1000000;
         description = ''
-          Maximum number of queries served on a single TCP connection.
-          0 means no maximum.
+          Size of the hashtable. More buckets use more memory but lower
+          the chance of hash hash collisions.
         '';
       };
 
-      tcpTimeout = mkOption {
-        type        = types.int;
-        default     = 120;
+      whitelistRatelimit = mkOption {
+        type = types.int;
+        default = 2000;
         description = ''
-          TCP timeout in seconds.
+          Max qps allowed from whitelisted sources.
+          0 means unlimited. Set the rrl-whitelist option for specific
+          queries to apply this limit instead of the default to them.
         '';
       };
 
-      ipv4EDNSSize = mkOption {
-        type        = types.int;
-        default     = 4096;
+    };
+
+
+    remoteControl = {
+
+      enable = mkEnableOption "remote control via nsd-control";
+
+      controlCertFile = mkOption {
+        type = types.path;
+        default = "/etc/nsd/nsd_control.pem";
         description = ''
-          Preferred EDNS buffer size for IPv4.
+          Path to the client certificate signed with the server certificate.
+          This file is used by nsd-control and generated by nsd-control-setup.
         '';
       };
 
-      ipv6EDNSSize = mkOption {
-        type        = types.int;
-        default     = 4096;
+      controlKeyFile = mkOption {
+        type = types.path;
+        default = "/etc/nsd/nsd_control.key";
         description = ''
-          Preferred EDNS buffer size for IPv6.
+          Path to the client private key, which is used by nsd-control
+          but not by the server. This file is generated by nsd-control-setup.
         '';
       };
 
-      statistics = mkOption {
-        type        = types.nullOr types.int;
-        default     = null;
+      interfaces = mkOption {
+        type = types.listOf types.str;
+        default = [ "127.0.0.1" "::1" ];
         description = ''
-          Statistics are produced every number of seconds. Prints to log.
-          If null no statistics are logged.
+          Which interfaces NSD should bind to for remote control.
         '';
       };
 
-      xfrdReloadTimeout = mkOption {
-        type        = types.int;
-        default     = 1;
+      port = mkOption {
+        type = types.int;
+        default = 8952;
         description = ''
-          Number of seconds between reloads triggered by xfrd.
+          Port number for remote control operations (uses TLS over TCP).
         '';
       };
 
-      zonefilesCheck = mkOption {
-        type        = types.bool;
-        default     = true;
+      serverCertFile = mkOption {
+        type = types.path;
+        default = "/etc/nsd/nsd_server.pem";
         description = ''
-          Wheter to check mtime of all zone files on start and sighup.
+          Path to the server self signed certificate, which is used by the server
+          but and by nsd-control. This file is generated by nsd-control-setup.
         '';
       };
 
-
-      extraConfig = mkOption {
-        type        = types.str;
-        default     = "";
+      serverKeyFile = mkOption {
+        type = types.path;
+        default = "/etc/nsd/nsd_server.key";
         description = ''
-          Extra nsd config.
+          Path to the server private key, which is used by the server
+          but not by nsd-control. This file is generated by nsd-control-setup.
         '';
       };
 
+    };
 
-      ratelimit = {
-        enable = mkEnableOption "ratelimit capabilities";
-
-        size = mkOption {
-          type        = types.int;
-          default     = 1000000;
-          description = ''
-            Size of the hashtable. More buckets use more memory but lower
-            the chance of hash hash collisions.
-          '';
-        };
-
-        ratelimit = mkOption {
-          type        = types.int;
-          default     = 200;
-          description = ''
-            Max qps allowed from any query source.
-            0 means unlimited. With an verbosity of 2 blocked and
-            unblocked subnets will be logged.
-          '';
-        };
-
-        whitelistRatelimit = mkOption {
-          type        = types.int;
-          default     = 2000;
-          description = ''
-            Max qps allowed from whitelisted sources.
-            0 means unlimited. Set the rrl-whitelist option for specific
-            queries to apply this limit instead of the default to them.
-          '';
-        };
-
-        slip = mkOption {
-          type        = types.nullOr types.int;
-          default     = null;
-          description = ''
-            Number of packets that get discarded before replying a SLIP response.
-            0 disables SLIP responses. 1 will make every response a SLIP response.
-          '';
-        };
-
-        ipv4PrefixLength = mkOption {
-          type        = types.nullOr types.int;
-          default     = null;
-          description = ''
-            IPv4 prefix length. Addresses are grouped by netblock.
-          '';
-        };
-
-        ipv6PrefixLength = mkOption {
-          type        = types.nullOr types.int;
-          default     = null;
-          description = ''
-            IPv6 prefix length. Addresses are grouped by netblock.
-          '';
-        };
-      };
-
-
-      remoteControl = {
-        enable = mkEnableOption "remote control via nsd-control";
-
-        interfaces = mkOption {
-          type        = types.listOf types.str;
-          default     = [ "127.0.0.1" "::1" ];
-          description = ''
-            Which interfaces NSD should bind to for remote control.
-          '';
-        };
-
-        port = mkOption {
-          type        = types.int;
-          default     = 8952;
-          description = ''
-            Port number for remote control operations (uses TLS over TCP).
-          '';
-        };
-
-        serverKeyFile = mkOption {
-          type        = types.path;
-          default     = "/etc/nsd/nsd_server.key";
-          description = ''
-            Path to the server private key, which is used by the server
-            but not by nsd-control. This file is generated by nsd-control-setup.
-          '';
-        };
-
-        serverCertFile = mkOption {
-          type        = types.path;
-          default     = "/etc/nsd/nsd_server.pem";
-          description = ''
-            Path to the server self signed certificate, which is used by the server
-            but and by nsd-control. This file is generated by nsd-control-setup.
-          '';
-        };
-
-        controlKeyFile = mkOption {
-          type        = types.path;
-          default     = "/etc/nsd/nsd_control.key";
-          description = ''
-            Path to the client private key, which is used by nsd-control
-            but not by the server. This file is generated by nsd-control-setup.
-          '';
-        };
-
-        controlCertFile = mkOption {
-          type        = types.path;
-          default     = "/etc/nsd/nsd_control.pem";
-          description = ''
-            Path to the client certificate signed with the server certificate.
-            This file is used by nsd-control and generated by nsd-control-setup.
-          '';
-        };
-      };
-
-
-      keys = mkOption {
-        type = types.attrsOf (types.submodule {
-          options = {
-            algorithm = mkOption {
-              type        = types.str;
-              default     = "hmac-sha256";
-              description = ''
-                Authentication algorithm for this key.
-              '';
-            };
-
-            keyFile = mkOption {
-              type        = types.path;
-              description = ''
-                Path to the file which contains the actual base64 encoded
-                key. The key will be copied into "${stateDir}/private" before
-                NSD starts. The copied file is only accessibly by the NSD
-                user.
-              '';
-            };
-          };
-        });
-        default = {};
-        example = {
-          "tsig.example.org" = {
-            algorithm = "hmac-md5";
-            secret    = "aaaaaabbbbbbccccccdddddd";
-          };
-        };
-        description = ''
-          Define your TSIG keys here.
-        '';
-      };
 
-      zones = mkOption {
-        type        = types.attrsOf zoneOptions;
-        default     = {};
-        example     = {
-          "serverGroup1" = {
+    zones = mkOption {
+      type = types.attrsOf zoneOptions;
+      default = {};
+      example = literalExample ''
+        { "serverGroup1" = {
             provideXFR = [ "10.1.2.3 NOKEY" ];
             children = {
               "example.com." = {
-                data = ''
+                data = '''
                   $ORIGIN example.com.
                   $TTL    86400
                   @ IN SOA a.ns.example.com. admin.example.com. (
                   ...
-                '';
+                ''';
               };
               "example.org." = {
-                data = ''
+                data = '''
                   $ORIGIN example.org.
                   $TTL    86400
                   @ IN SOA a.ns.example.com. admin.example.com. (
                   ...
-                '';
+                ''';
               };
             };
           };
 
           "example.net." = {
             provideXFR = [ "10.3.2.1 NOKEY" ];
-            data = ''...'';
+            data = '''
+              ...
+            ''';
           };
-        };
-        description = ''
-          Define your zones here. Zones can cascade other zones and therefore
-          inherit settings from parent zones. Look at the definition of
-          children to learn about inheritance and child zones.
-          The given example will define 3 zones (example.(com|org|net).). Both
-          example.com. and example.org. inherit their configuration from
-          serverGroup1.
-        '';
-      };
-
+        }
+      '';
+      description = ''
+        Define your zones here. Zones can cascade other zones and therefore
+        inherit settings from parent zones. Look at the definition of
+        children to learn about inheritance and child zones.
+        The given example will define 3 zones (example.(com|org|net).). Both
+        example.com. and example.org. inherit their configuration from
+        serverGroup1.
+      '';
     };
+
   };
 
   config = mkIf cfg.enable {
 
     users.extraGroups = singleton {
       name = username;
-      gid  = config.ids.gids.nsd;
+      gid = config.ids.gids.nsd;
     };
 
     users.extraUsers = singleton {
-      name        = username;
+      name = username;
       description = "NSD service user";
-      home        = stateDir;
+      home = stateDir;
       createHome  = true;
-      uid         = config.ids.uids.nsd;
-      group       = username;
+      uid = config.ids.uids.nsd;
+      group = username;
     };
 
     systemd.services.nsd = {
       description = "NSD authoritative only domain name service";
-      wantedBy    = [ "multi-user.target" ];
-      after       = [ "network.target" ];
+
+      after = [ "keys.target" "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      wants = [ "keys.target" ];
 
       serviceConfig = {
-        PIDFile   = pidFile;
-        Restart   = "always";
-        ExecStart = "${nsdPkg}/sbin/nsd -d -c ${configFile}";
+        ExecStart = "${nsdPkg}/sbin/nsd -d -c ${nsdEnv}/nsd.conf";
+        PIDFile = pidFile;
+        Restart = "always";
+        RestartSec = "4s";
+        StartLimitBurst = 4;
+        StartLimitInterval = "5min";
       };
 
       preStart = ''
-        ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/private"
-        ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/tmp"
-        ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/var"
+        rm -Rf "${stateDir}/private/"
+        rm -Rf "${stateDir}/tmp/"
 
-        ${pkgs.coreutils}/bin/touch "${stateDir}/don't touch anything in here"
+        mkdir -m 0700 -p "${stateDir}/private"
+        mkdir -m 0700 -p "${stateDir}/tmp"
+        mkdir -m 0700 -p "${stateDir}/var"
 
-        ${pkgs.coreutils}/bin/rm -f "${stateDir}/private/"*
-        ${pkgs.coreutils}/bin/rm -f "${stateDir}/tmp/"*
+        cat > "${stateDir}/don't touch anything in here" << EOF
+        Everything in this directory except NSD's state in var is
+        automatically generated and will be purged and redeployed
+        by the nsd.service pre-start script.
+        EOF
 
-        ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/private"
-        ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/tmp"
-        ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/var"
+        chown ${username}:${username} -R "${stateDir}/private"
+        chown ${username}:${username} -R "${stateDir}/tmp"
+        chown ${username}:${username} -R "${stateDir}/var"
 
-        ${pkgs.coreutils}/bin/rm -rf "${stateDir}/zones"
-        ${pkgs.coreutils}/bin/cp -r  "${zoneFiles}" "${stateDir}/zones"
+        rm -rf "${stateDir}/zones"
+        cp -rL "${nsdEnv}/zones" "${stateDir}/zones"
 
         ${copyKeys}
       '';
diff --git a/nixos/modules/services/networking/pdnsd.nix b/nixos/modules/services/networking/pdnsd.nix
new file mode 100644
index 000000000000..f4467b818958
--- /dev/null
+++ b/nixos/modules/services/networking/pdnsd.nix
@@ -0,0 +1,93 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.pdnsd;
+  pdnsd = pkgs.pdnsd;
+  pdnsdUser = "pdnsd";
+  pdnsdGroup = "pdnsd";
+  pdnsdConf = pkgs.writeText "pdnsd.conf"
+    ''
+      global {
+        run_as=${pdnsdUser};
+        cache_dir="${cfg.cacheDir}";
+        ${cfg.globalConfig}
+      }
+
+      server {
+        ${cfg.serverConfig}
+      }
+      ${cfg.extraConfig}
+    '';
+in
+
+{ options =
+    { services.pdnsd =
+        { enable = mkEnableOption "pdnsd";
+
+          cacheDir = mkOption {
+            type = types.str;
+            default = "/var/cache/pdnsd";
+            description = "Directory holding the pdnsd cache";
+          };
+
+          globalConfig = mkOption {
+            type = types.lines;
+            default = "";
+            description = ''
+              Global configuration that should be added to the global directory
+              of <literal>pdnsd.conf</literal>.
+            '';
+          };
+
+          serverConfig = mkOption {
+            type = types.lines;
+            default = "";
+            description = ''
+              Server configuration that should be added to the server directory
+              of <literal>pdnsd.conf</literal>.
+            '';
+          };
+
+          extraConfig = mkOption {
+            type = types.lines;
+            default = "";
+            description = ''
+              Extra configuration directives that should be added to
+              <literal>pdnsd.conf</literal>.
+            '';
+          };
+        };
+    };
+
+  config = mkIf cfg.enable {
+    users.extraUsers = singleton {
+      name = pdnsdUser;
+      uid = config.ids.uids.pdnsd;
+      group = pdnsdGroup;
+      description = "pdnsd user";
+    };
+
+    users.extraGroups = singleton {
+      name = pdnsdGroup;
+      gid = config.ids.gids.pdnsd;
+    };
+
+    systemd.services.pdnsd =
+      { wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
+        preStart =
+          ''
+            mkdir -p "${cfg.cacheDir}"
+            touch "${cfg.cacheDir}/pdnsd.cache"
+            chown -R ${pdnsdUser}:${pdnsdGroup} "${cfg.cacheDir}"
+          '';
+        description = "pdnsd";
+        serviceConfig =
+          {
+            ExecStart = "${pdnsd}/bin/pdnsd -c ${pdnsdConf}";
+          };
+      };
+  };
+}
diff --git a/nixos/modules/services/networking/softether.nix b/nixos/modules/services/networking/softether.nix
index a421b32f02c2..5e49efc3aa3a 100644
--- a/nixos/modules/services/networking/softether.nix
+++ b/nixos/modules/services/networking/softether.nix
@@ -61,11 +61,14 @@ in
             dataDir = cfg.dataDir;
           }))
         ];
-      systemd.services.softether = {
-        description = "SoftEther VPN services initial job";
-        after = [ "network-interfaces.target" ];
-        wantedBy = [ "multi-user.target" ];
-        preStart = ''
+      systemd.services."softether-init" = {
+        description = "SoftEther VPN services initial task";
+        wantedBy = [ "network-interfaces.target" ];
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = false;
+        };
+        script = ''
             for d in vpnserver vpnbridge vpnclient vpncmd; do
                 if ! test -e ${cfg.dataDir}/$d; then
                     ${pkgs.coreutils}/bin/mkdir -m0700 -p ${cfg.dataDir}/$d
@@ -81,12 +84,12 @@ in
     (mkIf (cfg.vpnserver.enable) {
       systemd.services.vpnserver = {
         description = "SoftEther VPN Server";
-        after = [ "network-interfaces.target" ];
-        wantedBy = [ "multi-user.target" ];
+        after = [ "softether-init.service" ];
+        wantedBy = [ "network-interfaces.target" ];
         serviceConfig = {
+          Type = "forking";
           ExecStart = "${pkg}/bin/vpnserver start";
           ExecStop = "${pkg}/bin/vpnserver stop";
-          Type = "forking";
         };
         preStart = ''
             rm -rf ${cfg.dataDir}/vpnserver/vpnserver
@@ -101,12 +104,12 @@ in
     (mkIf (cfg.vpnbridge.enable) {
       systemd.services.vpnbridge = {
         description = "SoftEther VPN Bridge";
-        after = [ "network-interfaces.target" ];
-        wantedBy = [ "multi-user.target" ];
+        after = [ "softether-init.service" ];
+        wantedBy = [ "network-interfaces.target" ];
         serviceConfig = {
+          Type = "forking";
           ExecStart = "${pkg}/bin/vpnbridge start";
           ExecStop = "${pkg}/bin/vpnbridge stop";
-          Type = "forking";
         };
         preStart = ''
             rm -rf ${cfg.dataDir}/vpnbridge/vpnbridge
@@ -121,12 +124,12 @@ in
     (mkIf (cfg.vpnclient.enable) {
       systemd.services.vpnclient = {
         description = "SoftEther VPN Client";
-        after = [ "network-interfaces.target" ];
-        wantedBy = [ "multi-user.target" ];
+        after = [ "softether-init.service" ];
+        wantedBy = [ "network-interfaces.target" ];
         serviceConfig = {
+          Type = "forking";
           ExecStart = "${pkg}/bin/vpnclient start";
           ExecStop = "${pkg}/bin/vpnclient stop";
-          Type = "forking";
         };
         preStart = ''
             rm -rf ${cfg.dataDir}/vpnclient/vpnclient
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index 5baea4bc6aea..5971a5a250d3 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -52,6 +52,8 @@ let
     ));
   in listToAttrs (map mkAuthKeyFile usersWithKeys);
 
+  supportOldHostKeys = !versionAtLeast config.system.stateVersion "15.07";
+
 in
 
 {
@@ -177,7 +179,7 @@ in
         default =
           [ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; }
             { type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; }
-          ] ++ optionals (!versionAtLeast config.system.stateVersion "15.07")
+          ] ++ optionals supportOldHostKeys
           [ { type = "dsa"; path = "/etc/ssh/ssh_host_dsa_key"; }
             { type = "ecdsa"; bits = 521; path = "/etc/ssh/ssh_host_ecdsa_key"; }
           ];
@@ -261,7 +263,7 @@ in
 
             serviceConfig =
               { ExecStart =
-                  "${cfgc.package}/sbin/sshd " + (optionalString cfg.startWhenNeeded "-i ") +
+                  "${cfgc.package}/bin/sshd " + (optionalString cfg.startWhenNeeded "-i ") +
                   "-f ${pkgs.writeText "sshd_config" cfg.extraConfig}";
                 KillMode = "process";
               } // (if cfg.startWhenNeeded then {
@@ -302,7 +304,7 @@ in
     services.openssh.authorizedKeysFiles =
       [ ".ssh/authorized_keys" ".ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ];
 
-    services.openssh.extraConfig =
+    services.openssh.extraConfig = mkOrder 0
       ''
         PidFile /run/sshd.pid
 
@@ -347,6 +349,15 @@ in
         ${flip concatMapStrings cfg.hostKeys (k: ''
           HostKey ${k.path}
         '')}
+
+        # Allow DSA client keys for now. (These were deprecated
+        # in OpenSSH 7.0.)
+        PubkeyAcceptedKeyTypes +ssh-dss
+
+        # Re-enable DSA host keys for now.
+        ${optionalString supportOldHostKeys ''
+          HostKeyAlgorithms +ssh-dss
+        ''}
       '';
 
     assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;
diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix
index f5d5e1d25561..67b90516b996 100644
--- a/nixos/modules/services/networking/syncthing.nix
+++ b/nixos/modules/services/networking/syncthing.nix
@@ -33,6 +33,17 @@ in
         '';
       };
 
+      all_proxy = mkOption {
+        type = types.string;
+        default = "";
+        example = "socks5://address.com:1234";
+        description = ''
+          Overwrites all_proxy environment variable for the syncthing process to
+          the given value. This is normaly used to let relay client connect
+          through SOCKS5 proxy server.
+        '';
+      };
+
       dataDir = mkOption {
         default = "/var/lib/syncthing";
         description = ''
@@ -51,7 +62,6 @@ in
       };
 
 
-
     };
 
   };
@@ -66,8 +76,13 @@ in
         description = "Syncthing service";
         after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
-        environment.STNORESTART = "yes";  # do not self-restart
-        environment.STNOUPGRADE = "yes";
+        environment = {
+          STNORESTART = "yes";  # do not self-restart
+          STNOUPGRADE = "yes";
+        } //
+        (config.networking.proxy.envVars) //
+        (if cfg.all_proxy != "" then { all_proxy = cfg.all_proxy; } else {});
+
         serviceConfig = {
           User = "${cfg.user}";
           PermissionsStartOnly = true;
diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix
index 34f4f6b37b60..9330e6c92ba8 100644
--- a/nixos/modules/services/networking/tinc.nix
+++ b/nixos/modules/services/networking/tinc.nix
@@ -95,6 +95,16 @@ in
             '';
           };
 
+          chroot = mkOption {
+            default = true;
+            type = types.bool;
+            description = ''
+              Change process root directory to the directory where the config file is located (/etc/tinc/netname/), for added security.
+              The chroot is performed after all the initialization is done, after writing pid files and opening network sockets.
+
+              Note that tinc can't run scripts anymore (such as tinc-down or host-up), unless it is setup to be runnable inside chroot environment.
+            '';
+          };
         };
       };
     };
@@ -166,7 +176,7 @@ in
           fi
         '';
         script = ''
-          tincd -D -U tinc.${network} -n ${network} --pidfile /run/tinc.${network}.pid -d ${toString data.debugLevel}
+          tincd -D -U tinc.${network} -n ${network} ${optionalString (data.chroot) "-R"} --pidfile /run/tinc.${network}.pid -d ${toString data.debugLevel}
         '';
       })
     );
diff --git a/nixos/modules/services/networking/tlsdated.nix b/nixos/modules/services/networking/tlsdated.nix
index ff7d0178a81a..757cce287607 100644
--- a/nixos/modules/services/networking/tlsdated.nix
+++ b/nixos/modules/services/networking/tlsdated.nix
@@ -26,6 +26,7 @@ in
 
       extraOptions = mkOption {
         type = types.string;
+        default = "";
         description = ''
           Additional command line arguments to pass to tlsdated.
         '';
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index 73b10c1d5611..89762fe52488 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -16,6 +16,11 @@ let
     "forward-zone:\n  name: .\n" +
     concatMapStrings (x: "  forward-addr: ${x}\n") cfg.forwardAddresses;
 
+  rootTrustAnchorFile = "${stateDir}/root.key";
+
+  trustAnchor = optionalString cfg.enableRootTrustAnchor
+    "auto-trust-anchor-file: ${rootTrustAnchorFile}";
+
   confFile = pkgs.writeText "unbound.conf" ''
     server:
       directory: "${stateDir}"
@@ -24,6 +29,7 @@ let
       pidfile: ""
       ${interfaces}
       ${access}
+      ${trustAnchor}
     ${cfg.extraConfig}
     ${forward}
   '';
@@ -38,28 +44,39 @@ in
     services.unbound = {
 
       enable = mkOption {
-	default = false;
-	description = "Whether to enable the Unbound domain name server.";
+        default = false;
+        type = types.bool;
+        description = "Whether to enable the Unbound domain name server.";
       };
 
       allowedAccess = mkOption {
-	default = ["127.0.0.0/24"];
-	description = "What networks are allowed to use unbound as a resolver.";
+        default = ["127.0.0.0/24"];
+        type = types.listOf types.str;
+        description = "What networks are allowed to use unbound as a resolver.";
       };
 
       interfaces = mkOption {
-	default = [ "127.0.0.1" "::1" ];
-	description = "What addresses the server should listen on.";
+        default = [ "127.0.0.1" "::1" ];
+        type = types.listOf types.str;
+        description = "What addresses the server should listen on.";
       };
 
       forwardAddresses = mkOption {
-	default = [ ];
-	description = "What servers to forward queries to.";
+        default = [ ];
+        type = types.listOf types.str;
+        description = "What servers to forward queries to.";
+      };
+
+      enableRootTrustAnchor = mkOption {
+        default = true;
+        type = types.bool;
+        description = "Use and update root trust anchor for DNSSEC validation.";
       };
 
       extraConfig = mkOption {
-	default = "";
-	description = "Extra lines of unbound config.";
+        default = "";
+        type = types.str;
+        description = "Extra lines of unbound config.";
       };
 
     };
@@ -88,14 +105,15 @@ in
 
       preStart = ''
         mkdir -m 0755 -p ${stateDir}/dev/
-	cp ${confFile} ${stateDir}/unbound.conf
-	chown unbound ${stateDir}
-	touch ${stateDir}/dev/random
+        cp ${confFile} ${stateDir}/unbound.conf
+        ${pkgs.unbound}/bin/unbound-anchor -a ${rootTrustAnchorFile}
+        chown unbound ${stateDir} ${rootTrustAnchorFile}
+        touch ${stateDir}/dev/random
         ${pkgs.utillinux}/bin/mount --bind -n /dev/random ${stateDir}/dev/random
       '';
 
       serviceConfig = {
-        ExecStart = "${pkgs.unbound}/sbin/unbound -d -c ${stateDir}/unbound.conf";
+        ExecStart = "${pkgs.unbound}/bin/unbound -d -c ${stateDir}/unbound.conf";
         ExecStopPost="${pkgs.utillinux}/bin/umount ${stateDir}/dev/random";
       };
     };
diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix
index be8f12ecd32d..4dc0cd96904c 100644
--- a/nixos/modules/services/networking/unifi.nix
+++ b/nixos/modules/services/networking/unifi.nix
@@ -61,6 +61,8 @@ in
       partOf = systemdMountPoints;
       bindsTo = systemdMountPoints;
       unitConfig.RequiresMountsFor = stateDir;
+      # This a HACK to fix missing dependencies of dynamic libs extracted from jars
+      environment.LD_LIBRARY_PATH = with pkgs.stdenv; "${cc.cc}/lib";
 
       preStart = ''
         # Ensure privacy of state
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index 1b655af6c82d..a8f445a2c73c 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -8,11 +8,15 @@ let
     ${optionalString cfg.userControlled.enable ''
       ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=${cfg.userControlled.group}
       update_config=1''}
-    ${concatStringsSep "\n" (mapAttrsToList (ssid: networkConfig: ''
+    ${concatStringsSep "\n" (mapAttrsToList (ssid: networkConfig: let
+      psk = if networkConfig.psk != null
+        then ''"${networkConfig.psk}"''
+        else networkConfig.pskRaw;
+    in ''
       network={
         ssid="${ssid}"
-        ${optionalString (networkConfig.psk != null) ''psk="${networkConfig.psk}"''}
-        ${optionalString (networkConfig.psk == null) ''key_mgmt=NONE''}
+        ${optionalString (psk != null) ''psk=${psk}''}
+        ${optionalString (psk == null) ''key_mgmt=NONE''}
       }
     '') cfg.networks)}
   '' else "/etc/wpa_supplicant.conf";
@@ -49,6 +53,19 @@ in {
 
                 Be aware that these will be written to the nix store
                 in plaintext!
+
+                Mutually exclusive with <varname>pskRaw</varname>.
+              '';
+            };
+
+            pskRaw = mkOption {
+              type = types.nullOr types.str;
+              default = null;
+              description = ''
+                The network's pre-shared key in hex defaulting
+                to being a network without any authentication.
+
+                Mutually exclusive with <varname>psk</varname>.
               '';
             };
           };
@@ -61,10 +78,11 @@ in {
         '';
         default = {};
         example = literalExample ''
-          echelon = {
-            psk = "abcdefgh";
-          };
-          "free.wifi" = {};
+          { echelon = {
+              psk = "abcdefgh";
+            };
+            "free.wifi" = {};
+          }
         '';
       };
 
@@ -95,6 +113,11 @@ in {
 
   config = mkMerge [
     (mkIf cfg.enable {
+      assertions = flip mapAttrsToList cfg.networks (name: cfg: {
+        assertion = cfg.psk == null || cfg.pskRaw == null;
+        message = ''networking.wireless."${name}".psk and networking.wireless."${name}".pskRaw are mutually exclusive'';
+      });
+
       environment.systemPackages =  [ pkgs.wpa_supplicant ];
 
       services.dbus.packages = [ pkgs.wpa_supplicant ];
@@ -105,6 +128,7 @@ in {
       in {
         description = "WPA Supplicant";
 
+        after = [ "network-interfaces.target" ];
         wantedBy = [ "network.target" ];
 
         path = [ pkgs.wpa_supplicant ];
diff --git a/nixos/modules/services/networking/zerotierone.nix b/nixos/modules/services/networking/zerotierone.nix
index 886ea18d9809..6237f95b127b 100644
--- a/nixos/modules/services/networking/zerotierone.nix
+++ b/nixos/modules/services/networking/zerotierone.nix
@@ -21,10 +21,9 @@ in
         chown -R root:root /var/lib/zerotier-one
         '';
       serviceConfig = {
-        Type = "forking";
-        User = "root";
-        PIDFile = "/var/lib/zerotier-one/zerotier-one.pid";
-        ExecStart = "${pkgs.zerotierone}/bin/zerotier-one -d";
+        ExecStart = "${pkgs.zerotierone}/bin/zerotier-one";
+        Restart = "always";
+        KillMode = "process";
       };
     };
   environment.systemPackages = [ pkgs.zerotierone ];
diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix
index 0fe25b66da08..59416560655d 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -4,38 +4,104 @@ with lib;
 
 let
 
-  inherit (pkgs) cups cups_filters;
+  inherit (pkgs) cups cups-pk-helper cups_filters gutenprint;
 
   cfg = config.services.printing;
 
+  avahiEnabled = config.services.avahi.enable;
+  polkitEnabled = config.security.polkit.enable;
+
   additionalBackends = pkgs.runCommand "additional-cups-backends" { }
     ''
       mkdir -p $out
-      if [ ! -e ${cups}/lib/cups/backend/smb ]; then
+      if [ ! -e ${cups.out}/lib/cups/backend/smb ]; then
         mkdir -p $out/lib/cups/backend
         ln -sv ${pkgs.samba}/bin/smbspool $out/lib/cups/backend/smb
       fi
 
       # Provide support for printing via HTTPS.
-      if [ ! -e ${cups}/lib/cups/backend/https ]; then
+      if [ ! -e ${cups.out}/lib/cups/backend/https ]; then
         mkdir -p $out/lib/cups/backend
-        ln -sv ${cups}/lib/cups/backend/ipp $out/lib/cups/backend/https
+        ln -sv ${cups.out}/lib/cups/backend/ipp $out/lib/cups/backend/https
       fi
     '';
 
   # Here we can enable additional backends, filters, etc. that are not
   # part of CUPS itself, e.g. the SMB backend is part of Samba.  Since
-  # we can't update ${cups}/lib/cups itself, we create a symlink tree
+  # we can't update ${cups.out}/lib/cups itself, we create a symlink tree
   # here and add the additional programs.  The ServerBin directive in
   # cupsd.conf tells cupsd to use this tree.
   bindir = pkgs.buildEnv {
     name = "cups-progs";
-    paths = cfg.drivers;
-    pathsToLink = [ "/lib/cups" "/share/cups" "/bin" "/etc/cups" ];
+    paths =
+      [ cups additionalBackends cups_filters pkgs.ghostscript ]
+      ++ optional cfg.gutenprint gutenprint
+      ++ cfg.drivers;
+    pathsToLink = [ "/lib/cups" "/share/cups" "/bin" ];
     postBuild = cfg.bindirCmds;
     ignoreCollisions = true;
   };
 
+  writeConf = name: text: pkgs.writeTextFile {
+    inherit name text;
+    destination = "/etc/cups/${name}";
+  };
+
+  cupsFilesFile = writeConf "cups-files.conf" ''
+    SystemGroup root wheel
+
+    ServerBin ${bindir}/lib/cups
+    DataDir ${bindir}/share/cups
+
+    AccessLog syslog
+    ErrorLog syslog
+    PageLog syslog
+
+    TempDir ${cfg.tempDir}
+
+    # User and group used to run external programs, including
+    # those that actually send the job to the printer.  Note that
+    # Udev sets the group of printer devices to `lp', so we want
+    # these programs to run as `lp' as well.
+    User cups
+    Group lp
+
+    ${cfg.extraFilesConf}
+  '';
+
+  cupsdFile = writeConf "cupsd.conf" ''
+    ${concatMapStrings (addr: ''
+      Listen ${addr}
+    '') cfg.listenAddresses}
+    Listen /var/run/cups/cups.sock
+
+    SetEnv PATH ${bindir}/lib/cups/filter:${bindir}/bin
+
+    DefaultShared ${if cfg.defaultShared then "Yes" else "No"}
+
+    Browsing ${if cfg.browsing then "Yes" else "No"}
+
+    WebInterface ${if cfg.webInterface then "Yes" else "No"}
+
+    ${cfg.extraConf}
+  '';
+
+  browsedFile = writeConf "cups-browsed.conf" cfg.browsedConf;
+
+  rootdir = pkgs.buildEnv {
+    name = "cups-progs";
+    paths = [
+      cupsFilesFile
+      cupsdFile
+      (writeConf "client.conf" cfg.clientConf)
+      (writeConf "snmp.conf" cfg.snmpConf)
+    ] ++ optional avahiEnabled browsedFile
+      ++ optional cfg.gutenprint gutenprint
+      ++ cfg.drivers;
+    pathsToLink = [ "/etc/cups" ];
+    ignoreCollisions = true;
+  };
+
 in
 
 {
@@ -96,25 +162,11 @@ in
         '';
       };
 
-      cupsdConf = mkOption {
-        type = types.lines;
-        default = "";
-        example =
-          ''
-            BrowsePoll cups.example.com
-            LogLevel debug
-          '';
-        description = ''
-          The contents of the configuration file of the CUPS daemon
-          (<filename>cupsd.conf</filename>).
-        '';
-      };
-
-      cupsFilesConf = mkOption {
+      extraFilesConf = mkOption {
         type = types.lines;
         default = "";
         description = ''
-          The contents of the configuration file of the CUPS daemon
+          Extra contents of the configuration file of the CUPS daemon
           (<filename>cups-files.conf</filename>).
         '';
       };
@@ -171,8 +223,18 @@ in
         '';
       };
 
+      gutenprint = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable Gutenprint drivers for CUPS. This includes auto-updating
+          Gutenprint PPD files.
+        '';
+      };
+
       drivers = mkOption {
         type = types.listOf types.path;
+        default = [];
         example = literalExample "[ pkgs.splix ]";
         description = ''
           CUPS drivers to use. Drivers provided by CUPS, cups-filters, Ghostscript
@@ -204,15 +266,10 @@ in
         description = "CUPS printing services";
       };
 
-    environment.systemPackages = [ cups ];
+    environment.systemPackages = [ cups ] ++ optional polkitEnabled cups-pk-helper;
+    environment.etc."cups".source = "/var/lib/cups";
 
-    environment.etc."cups/client.conf".text = cfg.clientConf;
-    environment.etc."cups/cups-files.conf".text = cfg.cupsFilesConf;
-    environment.etc."cups/cupsd.conf".text = cfg.cupsdConf;
-    environment.etc."cups/cups-browsed.conf".text = cfg.browsedConf;
-    environment.etc."cups/snmp.conf".text = cfg.snmpConf;
-
-    services.dbus.packages = [ cups ];
+    services.dbus.packages = [ cups ] ++ optional polkitEnabled cups-pk-helper;
 
     # Cups uses libusb to talk to printers, and does not use the
     # linux kernel driver. If the driver is not in a black list, it
@@ -230,19 +287,35 @@ in
 
         preStart =
           ''
-            mkdir -m 0755 -p /etc/cups
             mkdir -m 0700 -p /var/cache/cups
             mkdir -m 0700 -p /var/spool/cups
             mkdir -m 0755 -p ${cfg.tempDir}
-          '';
 
-        restartTriggers =
-          [ config.environment.etc."cups/cups-files.conf".source
-            config.environment.etc."cups/cupsd.conf".source
-          ];
+            mkdir -m 0755 -p /var/lib/cups
+            # Backwards compatibility
+            if [ ! -L /etc/cups ]; then
+              mv /etc/cups/* /var/lib/cups
+              rmdir /etc/cups
+              ln -s /var/lib/cups /etc/cups
+            fi
+            # First, clean existing symlinks
+            if [ -n "$(ls /var/lib/cups)" ]; then
+              for i in /var/lib/cups/*; do
+                [ -L "$i" ] && rm "$i"
+              done
+            fi
+            # Then, populate it with static files
+            cd ${rootdir}/etc/cups
+            for i in *; do
+              [ ! -e "/var/lib/cups/$i" ] && ln -s "${rootdir}/etc/cups/$i" "/var/lib/cups/$i"
+            done
+            ${optionalString cfg.gutenprint ''
+              ${gutenprint}/bin/cups-genppdupdate -p /etc/cups/ppd
+            ''}
+          '';
       };
 
-    systemd.services.cups-browsed = mkIf config.services.avahi.enable
+    systemd.services.cups-browsed = mkIf avahiEnabled
       { description = "CUPS Remote Printer Discovery";
 
         wantedBy = [ "multi-user.target" ];
@@ -255,54 +328,13 @@ in
 
         serviceConfig.ExecStart = "${cups_filters}/bin/cups-browsed";
 
-        restartTriggers =
-          [ config.environment.etc."cups/cups-browsed.conf".source
-          ];
+        restartTriggers = [ browsedFile ];
       };
 
-    services.printing.drivers =
-      [ cups pkgs.ghostscript pkgs.cups_filters additionalBackends
-        pkgs.perl pkgs.coreutils pkgs.gnused pkgs.bc pkgs.gawk pkgs.gnugrep
-      ];
-
-    services.printing.cupsFilesConf =
-      ''
-        SystemGroup root wheel
-
-        ServerBin ${bindir}/lib/cups
-        DataDir ${bindir}/share/cups
-
-        AccessLog syslog
-        ErrorLog syslog
-        PageLog syslog
-
-        TempDir ${cfg.tempDir}
-
-        # User and group used to run external programs, including
-        # those that actually send the job to the printer.  Note that
-        # Udev sets the group of printer devices to `lp', so we want
-        # these programs to run as `lp' as well.
-        User cups
-        Group lp
-      '';
-
-    services.printing.cupsdConf =
+    services.printing.extraConf =
       ''
         LogLevel info
 
-        ${concatMapStrings (addr: ''
-          Listen ${addr}
-        '') cfg.listenAddresses}
-        Listen /var/run/cups/cups.sock
-
-        SetEnv PATH ${bindir}/lib/cups/filter:${bindir}/bin:${bindir}/sbin
-
-        DefaultShared ${if cfg.defaultShared then "Yes" else "No"}
-
-        Browsing ${if cfg.browsing then "Yes" else "No"}
-
-        WebInterface ${if cfg.webInterface then "Yes" else "No"}
-
         DefaultAuthType Basic
 
         <Location />
@@ -343,8 +375,6 @@ in
             Order deny,allow
           </Limit>
         </Policy>
-
-        ${cfg.extraConf}
       '';
 
     security.pam.services.cups = {};
diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix
index e586600cdffd..c51a42b8e9c1 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -9,6 +9,8 @@ let
     network.host: ${cfg.listenAddress}
     network.port: ${toString cfg.port}
     network.tcp.port: ${toString cfg.tcp_port}
+    # TODO: find a way to enable security manager
+    security.manager.enabled: false
     cluster.name: ${cfg.cluster_name}
     ${cfg.extraConf}
   '';
@@ -39,8 +41,8 @@ in {
 
     package = mkOption {
       description = "Elasticsearch package to use.";
-      default = pkgs.elasticsearch;
-      defaultText = "pkgs.elasticsearch";
+      default = pkgs.elasticsearch2;
+      defaultText = "pkgs.elasticsearch2";
       type = types.package;
     };
 
@@ -128,7 +130,10 @@ in {
       description = "Elasticsearch Daemon";
       wantedBy = [ "multi-user.target" ];
       after = [ "network-interfaces.target" ];
-      environment = { ES_HOME = cfg.dataDir; };
+      path = [ pkgs.inetutils ];
+      environment = {
+        ES_HOME = cfg.dataDir;
+      };
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/elasticsearch -Des.path.conf=${configDir} ${toString cfg.extraCmdLineOptions}";
         User = "elasticsearch";
@@ -136,11 +141,11 @@ in {
       };
       preStart = ''
         mkdir -m 0700 -p ${cfg.dataDir}
-        if [ "$(id -u)" = 0 ]; then chown -R elasticsearch ${cfg.dataDir}; fi
 
         # Install plugins
-        rm ${cfg.dataDir}/plugins || true
-        ln -s ${esPlugins}/plugins ${cfg.dataDir}/plugins
+        ln -sfT ${esPlugins}/plugins ${cfg.dataDir}/plugins
+        ln -sfT ${cfg.package}/lib ${cfg.dataDir}/lib
+        if [ "$(id -u)" = 0 ]; then chown -R elasticsearch ${cfg.dataDir}; fi
       '';
       postStart = mkBefore ''
         until ${pkgs.curl.bin}/bin/curl -s -o /dev/null ${cfg.listenAddress}:${toString cfg.port}; do
diff --git a/nixos/modules/services/search/kibana.nix b/nixos/modules/services/search/kibana.nix
index 4263ed22a8db..033b8139d341 100644
--- a/nixos/modules/services/search/kibana.nix
+++ b/nixos/modules/services/search/kibana.nix
@@ -7,37 +7,33 @@ let
 
   cfgFile = pkgs.writeText "kibana.json" (builtins.toJSON (
     (filterAttrsRecursive (n: v: v != null) ({
-      server = {
-        host = cfg.listenAddress;
-        port = cfg.port;
-        ssl = {
-          cert = cfg.cert;
-          key = cfg.key;
-        };
-      };
-
-      kibana = {
-        index = cfg.index;
-        defaultAppId = cfg.defaultAppId;
-      };
-
-      elasticsearch = {
-        url = cfg.elasticsearch.url;
-        username = cfg.elasticsearch.username;
-        password = cfg.elasticsearch.password;
-        ssl = {
-          cert = cfg.elasticsearch.cert;
-          key = cfg.elasticsearch.key;
-          ca = cfg.elasticsearch.ca;
-        };
-      };
-
-      logging = {
-        verbose = cfg.logLevel == "verbose";
-        quiet = cfg.logLevel == "quiet";
-        silent = cfg.logLevel == "silent";
-        dest = "stdout";
-      };
+      host = cfg.listenAddress;
+      port = cfg.port;
+      ssl_cert_file = cfg.cert;
+      ssl_key_file = cfg.key;
+
+      kibana_index = cfg.index;
+      default_app_id = cfg.defaultAppId;
+
+      elasticsearch_url = cfg.elasticsearch.url;
+      kibana_elasticsearch_username = cfg.elasticsearch.username;
+      kibana_elasticsearch_password = cfg.elasticsearch.password;
+      kibana_elasticsearch_cert = cfg.elasticsearch.cert;
+      kibana_elasticsearch_key = cfg.elasticsearch.key;
+      ca = cfg.elasticsearch.ca;
+
+      bundled_plugin_ids = [
+        "plugins/dashboard/index"
+        "plugins/discover/index"
+        "plugins/doc/index"
+        "plugins/kibana/index"
+        "plugins/markdown_vis/index"
+        "plugins/metric_vis/index"
+        "plugins/settings/index"
+        "plugins/table_vis/index"
+        "plugins/vis_types/index"
+        "plugins/visualize/index"
+      ];
     } // cfg.extraConf)
   )));
 in {
@@ -118,12 +114,6 @@ in {
       };
     };
 
-    logLevel = mkOption {
-      description = "Kibana log level";
-      default = "normal";
-      type = types.enum ["verbose" "normal" "silent" "quiet"];
-    };
-
     package = mkOption {
       description = "Kibana package to use";
       default = pkgs.kibana;
@@ -149,6 +139,7 @@ in {
       description = "Kibana Service";
       wantedBy = [ "multi-user.target" ];
       after = [ "network-interfaces.target" "elasticsearch.service" ];
+      environment = { BABEL_CACHE_PATH = "${cfg.dataDir}/.babelcache.json"; };
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/kibana --config ${cfgFile}";
         User = "kibana";
diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix
index 548aee29b266..e4e5c1253b77 100644
--- a/nixos/modules/services/security/clamav.nix
+++ b/nixos/modules/services/security/clamav.nix
@@ -16,6 +16,7 @@ let
 
     ${cfg.daemon.extraConfig}
   '';
+  pkg = pkgs.clamav.override { freshclamConf = cfg.updater.config; };
 in
 {
   options = {
@@ -54,7 +55,7 @@ in
   };
 
   config = mkIf cfg.updater.enable or cfg.daemon.enable {
-    environment.systemPackages = [ pkgs.clamav ];
+    environment.systemPackages = [ pkg ];
     users.extraUsers = singleton {
       name = clamavUser;
       uid = config.ids.uids.clamav;
@@ -76,7 +77,7 @@ in
 
     systemd.services.clamd = mkIf cfg.daemon.enable {
       description = "ClamAV daemon (clamd)";
-      path = [ pkgs.clamav ];
+      path = [ pkg ];
       after = [ "network.target" "freshclam.service" ];
       requires = [ "freshclam.service" ];
       wantedBy = [ "multi-user.target" ];
@@ -87,7 +88,7 @@ in
         chown ${clamavUser}:${clamavGroup} ${runDir}
       '';
       serviceConfig = {
-        ExecStart = "${pkgs.clamav}/bin/clamd --config-file=${clamdConfigFile}";
+        ExecStart = "${pkg}/bin/clamd --config-file=${clamdConfigFile}";
         Type = "forking";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         Restart = "on-failure";
@@ -100,13 +101,13 @@ in
       description = "ClamAV updater (freshclam)";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      path = [ pkgs.clamav ];
+      path = [ pkg ];
       preStart = ''
         mkdir -m 0755 -p ${stateDir}
         chown ${clamavUser}:${clamavGroup} ${stateDir}
       '';
       serviceConfig = {
-        ExecStart = "${pkgs.clamav}/bin/freshclam --daemon --config-file=${pkgs.writeText "freshclam.conf" cfg.updater.config}";
+        ExecStart = "${pkg}/bin/freshclam --daemon --config-file=${pkgs.writeText "freshclam.conf" cfg.updater.config}";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         Restart = "on-failure";
         RestartSec = "10s";
diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix
index 1d3e18dcab25..afbd81be91f2 100644
--- a/nixos/modules/services/security/fail2ban.nix
+++ b/nixos/modules/services/security/fail2ban.nix
@@ -50,20 +50,20 @@ in
 
       jails = mkOption {
         default = { };
-        example =
-          { "apache-nohome-iptables" =
-              ''
-                # Block an IP address if it accesses a non-existent
-                # home directory more than 5 times in 10 minutes,
-                # since that indicates that it's scanning.
-                filter   = apache-nohome
-                action   = iptables-multiport[name=HTTP, port="http,https"]
-                logpath  = /var/log/httpd/error_log*
-                findtime = 600
-                bantime  = 600
-                maxretry = 5
-              '';
-          };
+        example = literalExample ''
+          { apache-nohome-iptables = '''
+              # Block an IP address if it accesses a non-existent
+              # home directory more than 5 times in 10 minutes,
+              # since that indicates that it's scanning.
+              filter   = apache-nohome
+              action   = iptables-multiport[name=HTTP, port="http,https"]
+              logpath  = /var/log/httpd/error_log*
+              findtime = 600
+              bantime  = 600
+              maxretry = 5
+            ''';
+          }
+        '';
         type = types.attrsOf types.lines;
         description =
           ''
diff --git a/nixos/modules/services/security/haka.nix b/nixos/modules/services/security/haka.nix
new file mode 100644
index 000000000000..f48a79b1f7f1
--- /dev/null
+++ b/nixos/modules/services/security/haka.nix
@@ -0,0 +1,157 @@
+# This module defines global configuration for Haka.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.haka;
+
+  haka = cfg.package;
+
+  hakaConf = pkgs.writeText "haka.conf"
+  ''
+    [general]
+    configuration = ${if lib.strings.hasPrefix "/" cfg.configFile
+      then "${cfg.configFile}"
+      else "${haka}/share/haka/sample/${cfg.configFile}"}
+    ${optionalString (builtins.lessThan 0 cfg.threads) "thread = ${cfg.threads}"}
+
+    [packet]
+    ${optionalString cfg.pcap ''module = "packet/pcap"''}
+    ${optionalString cfg.nfqueue ''module = "packet/nqueue"''}
+    ${optionalString cfg.dump.enable ''dump = "yes"''}
+    ${optionalString cfg.dump.enable ''dump_input = "${cfg.dump.input}"''}
+    ${optionalString cfg.dump.enable ''dump_output = "${cfg.dump.output}"''}
+
+    interfaces = "${lib.strings.concatStringsSep "," cfg.interfaces}"
+
+    [log]
+    # Select the log module
+    module = "log/syslog"
+
+    # Set the default logging level
+    #level = "info,packet=debug"
+
+    [alert]
+    # Select the alert module
+    module = "alert/syslog"
+
+    # Disable alert on standard output
+    #alert_on_stdout = no
+
+    # alert/file module option
+    #file = "/dev/null"
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.haka = {
+
+      enable = mkEnableOption "Haka";
+
+      package = mkOption {
+        default = pkgs.haka;
+        defaultText = "pkgs.haka";
+        type = types.package;
+        description = "
+          Which Haka derivation to use.
+        ";
+      };
+
+      configFile = mkOption {
+        default = "empty.lua";
+        example = "/srv/haka/myfilter.lua";
+        type = types.string;
+        description = ''
+          Specify which configuration file Haka uses.
+          It can be absolute path or a path relative to the sample directory of
+          the haka git repo.
+        '';
+      };
+
+      interfaces = mkOption {
+        default = [ "eth0" ];
+        example = [ "any" ];
+        type = with types; listOf string;
+        description = ''
+          Specify which interface(s) Haka listens to.
+          Use 'any' to listen to all interfaces.
+        '';
+      };
+
+      threads = mkOption {
+        default = 0;
+        example = 4;
+        type = types.int;
+        description = ''
+          The number of threads that will be used.
+          All system threads are used by default.
+        '';
+      };
+
+      pcap = mkOption {
+        default = true;
+        example = false;
+        type = types.bool;
+        description = "Whether to enable pcap";
+      };
+
+      nfqueue = mkEnableOption "nfqueue";
+
+      dump.enable = mkEnableOption "dump";
+      dump.input  = mkOption {
+        default = "/tmp/input.pcap";
+        example = "/path/to/file.pcap";
+        type = types.path;
+        description = "Path to file where incoming packets are dumped";
+      };
+
+      dump.output  = mkOption {
+        default = "/tmp/output.pcap";
+        example = "/path/to/file.pcap";
+        type = types.path;
+        description = "Path to file where outgoing packets are dumped";
+      };
+    };
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    assertions = [
+      { assertion = cfg.pcap != cfg.nfqueue;
+        message = "either pcap or nfqueue can be enabled, not both.";
+      }
+      { assertion = cfg.nfqueue -> !dump.enable;
+        message = "dump can only be used with nfqueue.";
+      }
+      { assertion = cfg.interfaces != [];
+        message = "at least one interface must be specified.";
+      }];
+
+
+    environment.systemPackages = [ haka ];
+
+    systemd.services.haka = {
+      description = "Haka";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      serviceConfig = {
+        ExecStart = "${haka}/bin/haka -c ${hakaConf}";
+        ExecStop = "${haka}/bin/hakactl stop";
+        User = "root";
+        Type = "forking";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix
index 77427ce9606e..2e29ef6a8f53 100644
--- a/nixos/modules/services/system/dbus.nix
+++ b/nixos/modules/services/system/dbus.nix
@@ -121,7 +121,7 @@ in
 
     security.setuidOwners = singleton
       { program = "dbus-daemon-launch-helper";
-        source = "${pkgs.dbus_daemon}/libexec/dbus-daemon-launch-helper";
+        source = "${pkgs.dbus_daemon.lib}/libexec/dbus-daemon-launch-helper";
         owner = "root";
         group = "messagebus";
         setuid = true;
diff --git a/nixos/modules/services/system/uptimed.nix b/nixos/modules/services/system/uptimed.nix
index 5f8916bbf9a4..b20d60968032 100644
--- a/nixos/modules/services/system/uptimed.nix
+++ b/nixos/modules/services/system/uptimed.nix
@@ -1,66 +1,55 @@
-{pkgs, config, lib, ...}:
+{ config, lib, pkgs, ... }:
 
-let
-
-  inherit (lib) mkOption mkIf singleton;
-
-  inherit (pkgs) uptimed;
+with lib;
 
+let
+  cfg = config.services.uptimed;
   stateDir = "/var/spool/uptimed";
-
-  uptimedUser = "uptimed";
-
 in
-
 {
-
-  ###### interface
-
   options = {
-
     services.uptimed = {
-
       enable = mkOption {
         default = false;
         description = ''
-          Uptimed allows you to track your highest uptimes.
+          Enable <literal>uptimed</literal>, allowing you to track
+          your highest uptimes.
         '';
       };
-
     };
-
   };
 
-
-  ###### implementation
-
-  config = mkIf config.services.uptimed.enable {
-
-    environment.systemPackages = [ uptimed ];
-
-    users.extraUsers = singleton
-      { name = uptimedUser;
-        uid = config.ids.uids.uptimed;
-        description = "Uptimed daemon user";
-        home = stateDir;
-      };
+  config = mkIf cfg.enable {
+    users.extraUsers.uptimed = {
+      description = "Uptimed daemon user";
+      home        = stateDir;
+      createHome  = true;
+      uid         = config.ids.uids.uptimed;
+    };
 
     systemd.services.uptimed = {
-      description = "Uptimed daemon";
-      wantedBy = [ "multi-user.target" ];
+      unitConfig.Documentation = "man:uptimed(8) man:uprecords(1)";
+      description = "uptimed service";
+      wantedBy    = [ "multi-user.target" ];
+
+      serviceConfig = {
+        Restart                 = "on-failure";
+        User                    = "uptimed";
+        Nice                    = 19;
+        IOSchedulingClass       = "idle";
+        PrivateTmp              = "yes";
+        PrivateNetwork          = "yes";
+        NoNewPrivileges         = "yes";
+        ReadWriteDirectories    = stateDir;
+        InaccessibleDirectories = "/home";
+        ExecStart               = "${pkgs.uptimed}/sbin/uptimed -f -p ${stateDir}/pid";
+      };
 
       preStart = ''
-        mkdir -m 0755 -p ${stateDir}
-        chown ${uptimedUser} ${stateDir}
-
         if ! test -f ${stateDir}/bootid ; then
-          ${uptimed}/sbin/uptimed -b
+          ${pkgs.uptimed}/sbin/uptimed -b
         fi
       '';
-
-      script = "${uptimed}/sbin/uptimed";
     };
-
   };
-
 }
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index c4dc6512a0dd..59ef915af6d4 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -21,7 +21,7 @@ let
     else toString ''"${x}"'';
 
   # for users in group "transmission" to have access to torrents
-  fullSettings = { download-dir = downloadDir; incomplete-dir = incompleteDir; } // cfg.settings // { umask = 2; };
+  fullSettings = { umask = 2; download-dir = downloadDir; incomplete-dir = incompleteDir; } // cfg.settings;
 in
 {
   options = {
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 880cd9f39c44..760d7e147d7c 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -12,7 +12,7 @@ let
 
   httpdConf = mainCfg.configFile;
 
-  php = pkgs.php.override { apacheHttpd = httpd; };
+  php = pkgs.php.override { apacheHttpd = httpd.dev; /* otherwise it only gets .out */ };
 
   getPort = cfg: if cfg.port != 0 then cfg.port else if cfg.enableSSL then 443 else 80;
 
@@ -173,7 +173,8 @@ let
     SSLRandomSeed connect builtin
 
     SSLProtocol All -SSLv2 -SSLv3
-    SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!EXP
+    SSLCipherSuite HIGH:!aNULL:!MD5:!EXP
+    SSLHonorCipherOrder on
   '';
 
 
diff --git a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
index 52d8c89baff2..0fe8d1a89cf3 100644
--- a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
@@ -83,11 +83,11 @@ let
 
   # Unpack Mediawiki and put the config file in its root directory.
   mediawikiRoot = pkgs.stdenv.mkDerivation rec {
-    name= "mediawiki-1.23.9";
+    name= "mediawiki-1.23.13";
 
     src = pkgs.fetchurl {
       url = "http://download.wikimedia.org/mediawiki/1.23/${name}.tar.gz";
-      sha256 = "1l7k4g0pgz92yvrfr52w26x740s4362v0gc95pk0i30vn2sp5bql";
+      sha256 = "168wpf53n4ksj2g5q5r0hxapx6238dvsfng5ff9ixk6axsn0j5d0";
     };
 
     skins = config.skins;
diff --git a/nixos/modules/services/web-servers/apache-httpd/moodle.nix b/nixos/modules/services/web-servers/apache-httpd/moodle.nix
index 84c8281ecd8d..87b1fba5aa10 100644
--- a/nixos/modules/services/web-servers/apache-httpd/moodle.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/moodle.nix
@@ -46,16 +46,16 @@ let
     '';
   # Unpack Moodle and put the config file in its root directory.
   moodleRoot = pkgs.stdenv.mkDerivation rec {
-    name= "moodle-2.8.5";
+    name= "moodle-2.8.10";
 
     src = pkgs.fetchurl {
       url = "https://download.moodle.org/stable28/${name}.tgz";
-      sha256 = "1a159a193010cddedce10ee009184502e6f732e4d7c85167d8597fe5dff9e190";
+      sha256 = "0c3r5081ipcwc9s6shakllnrkd589y2ln5z5m1q09l4h6a7cy4z2";
     };
 
     buildPhase =
       ''
-      ''; 
+      '';
 
     installPhase =
       ''
@@ -132,7 +132,7 @@ in
         cleartext in the Nix store!
       '';
     };
-    
+
     dbPrefix = mkOption {
       default = "mdl_";
       example = "my_other_mdl_";
@@ -158,7 +158,7 @@ in
       type = types.path;
       };
 
-    
+
     extraConfig = mkOption {
       default = "";
       example =
diff --git a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix
index 9994de0f9b40..94e85f1f4289 100644
--- a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix
@@ -333,7 +333,7 @@ let
 
       'version' => '${config.package.version}',
 
-      'openssl' => '${pkgs.openssl}/bin/openssl'
+      'openssl' => '${pkgs.openssl.bin}/bin/openssl'
 
       );
 
@@ -370,6 +370,7 @@ rec {
     package = mkOption {
       type = types.package;
       default = pkgs.owncloud70;
+      defaultText = "pkgs.owncloud70";
       example = literalExample "pkgs.owncloud70";
       description = ''
           PostgreSQL package to use.
diff --git a/nixos/modules/services/web-servers/phpfpm.nix b/nixos/modules/services/web-servers/phpfpm.nix
index bdd41ed702b5..6a60000ce19e 100644
--- a/nixos/modules/services/web-servers/phpfpm.nix
+++ b/nixos/modules/services/web-servers/phpfpm.nix
@@ -46,24 +46,26 @@ in {
 
       phpIni = mkOption {
         type = types.path;
-        description = "PHP configuration file to use.";
+        default = "${cfg.phpPackage}/etc/php-recommended.ini";
+        description = "php.ini file to use.";
       };
 
       poolConfigs = mkOption {
         type = types.attrsOf types.lines;
         default = {};
-        example = {
-          mypool = ''
-            listen = /run/phpfpm/mypool
-            user = nobody
-            pm = dynamic
-            pm.max_children = 75
-            pm.start_servers = 10
-            pm.min_spare_servers = 5
-            pm.max_spare_servers = 20
-            pm.max_requests = 500
-          '';
-        };
+        example = literalExample ''
+          { mypool = '''
+              listen = /run/phpfpm/mypool
+              user = nobody
+              pm = dynamic
+              pm.max_children = 75
+              pm.start_servers = 10
+              pm.min_spare_servers = 5
+              pm.max_spare_servers = 20
+              pm.max_requests = 500
+            ''';
+          }
+        '';
         description = ''
           A mapping between PHP FPM pool names and their configurations.
           See the documentation on <literal>php-fpm.conf</literal> for
@@ -87,7 +89,5 @@ in {
       };
     };
 
-    services.phpfpm.phpIni = mkDefault "${cfg.phpPackage}/etc/php-recommended.ini";
-
   };
 }
diff --git a/nixos/modules/services/web-servers/uwsgi.nix b/nixos/modules/services/web-servers/uwsgi.nix
index 3e18a6f0e986..e6c25e6215c1 100644
--- a/nixos/modules/services/web-servers/uwsgi.nix
+++ b/nixos/modules/services/web-servers/uwsgi.nix
@@ -5,43 +5,85 @@ with lib;
 let
   cfg = config.services.uwsgi;
 
-  python2Pkgs = pkgs.python2Packages.override {
-    python = pkgs.uwsgi.python2;
-    self = python2Pkgs;
+  uwsgi = pkgs.uwsgi.override {
+    plugins = cfg.plugins;
   };
 
-  python3Pkgs = pkgs.python3Packages.override {
-    python = pkgs.uwsgi.python3;
-    self = python3Pkgs;
-  };
+  buildCfg = name: c:
+    let
+      plugins =
+        if any (n: !any (m: m == n) cfg.plugins) (c.plugins or [])
+        then throw "`plugins` attribute in UWSGI configuration contains plugins not in config.services.uwsgi.plugins"
+        else c.plugins or cfg.plugins;
+
+      hasPython = v: filter (n: n == "python${v}") plugins != [];
+      hasPython2 = hasPython "2";
+      hasPython3 = hasPython "3";
+
+      python =
+        if hasPython2 && hasPython3 then
+          throw "`plugins` attribute in UWSGI configuration shouldn't contain both python2 and python3"
+        else if hasPython2 then uwsgi.python2
+        else if hasPython3 then uwsgi.python3
+        else null;
+
+      pythonPackages = pkgs.pythonPackages.override {
+        inherit python;
+        self = pythonPackages;
+      };
 
-  buildCfg = c: if builtins.typeOf c != "set" then builtins.readFile c else builtins.toJSON {
-    uwsgi =
-      if c.type == "normal"
-        then {
-          pythonpath =
-               (if c ? python2Packages
-                then builtins.map (x: "${x}/${pkgs.uwsgi.python2.sitePackages}") (c.python2Packages python2Pkgs)
-                else [])
-            ++ (if c ? python3Packages
-                then builtins.map (x: "${x}/${pkgs.uwsgi.python3.sitePackages}") (c.python3Packages python3Pkgs)
-                else []);
-          plugins = cfg.plugins;
-        } // removeAttrs c [ "type" "python2Packages" "python3Packages" ]
-      else if c.type == "emperor"
-        then {
-          emperor = if builtins.typeOf c.vassals != "set" then c.vassals
-                    else pkgs.buildEnv {
-                      name = "vassals";
-                      paths = mapAttrsToList (n: c: pkgs.writeTextDir "${n}.json" (buildCfg c)) c.vassals;
-                    };
-        } // removeAttrs c [ "type" "vassals" ]
-      else abort "type should be either 'normal' or 'emperor'";
-  };
+      json = builtins.toJSON {
+        uwsgi =
+          if c.type == "normal"
+            then {
+              inherit plugins;
+            } // removeAttrs c [ "type" "pythonPackages" ]
+              // optionalAttrs (python != null) {
+                pythonpath = "@PYTHONPATH@";
+                env = (c.env or {}) // {
+                  PATH = optionalString (c ? env.PATH) "${c.env.PATH}:" + "@PATH@";
+                };
+              }
+          else if c.type == "emperor"
+            then {
+              emperor = if builtins.typeOf c.vassals != "set" then c.vassals
+                        else pkgs.buildEnv {
+                          name = "vassals";
+                          paths = mapAttrsToList buildCfg c.vassals;
+                        };
+            } // removeAttrs c [ "type" "vassals" ]
+          else throw "`type` attribute in UWSGI configuration should be either 'normal' or 'emperor'";
+      };
 
-  uwsgi = pkgs.uwsgi.override {
-    plugins = cfg.plugins;
-  };
+    in
+      if python == null || c.type != "normal"
+      then pkgs.writeTextDir "${name}.json" json
+      else pkgs.stdenv.mkDerivation {
+        name = "uwsgi-config";
+        inherit json;
+        passAsFile = [ "json" ];
+        nativeBuildInputs = [ pythonPackages.wrapPython ];
+        pythonInputs = (c.pythonPackages or (self: [])) pythonPackages;
+
+        buildCommand = ''
+          mkdir $out
+          declare -A pythonPathsSeen=()
+          program_PYTHONPATH=
+          program_PATH=
+          if [ -n "$pythonInputs" ]; then
+            for i in $pythonInputs; do
+              _addToPythonPath $i
+            done
+          fi
+          # A hack to replace "@PYTHONPATH@" with a JSON list
+          if [ -n "$program_PYTHONPATH" ]; then
+            program_PYTHONPATH="\"''${program_PYTHONPATH//:/\",\"}\""
+          fi
+          substitute $jsonPath $out/${name}.json \
+            --replace '"@PYTHONPATH@"' "[$program_PYTHONPATH]" \
+            --subst-var-by PATH "$program_PATH"
+        '';
+      };
 
 in {
 
@@ -71,21 +113,24 @@ in {
             vassals = {
               moin = {
                 type = "normal";
-                python2Packages = self: with self; [ moinmoin ];
+                pythonPackages = self: with self; [ moinmoin ];
                 socket = "${config.services.uwsgi.runDir}/uwsgi.sock";
               };
             };
           }
         '';
         description = ''
-          uWSGI configuration. This awaits either a path to file or a set which will be made into one.
-          If given a set, it awaits an attribute <literal>type</literal> which can be either <literal>normal</literal>
-          or <literal>emperor</literal>.
+          uWSGI configuration. It awaits an attribute <literal>type</literal> inside which can be either
+          <literal>normal</literal> or <literal>emperor</literal>.
+
+          For <literal>normal</literal> mode you can specify <literal>pythonPackages</literal> as a function
+          from libraries set into a list of libraries. <literal>pythonpath</literal> will be set accordingly.
 
-          For <literal>normal</literal> mode you can specify <literal>python2Packages</literal> and
-          <literal>python3Packages</literal> as functions from libraries set into lists of libraries.
           For <literal>emperor</literal> mode, you should use <literal>vassals</literal> attribute
           which should be either a set of names and configurations or a path to a directory.
+
+          Other attributes will be used in configuration file as-is. Notice that you can redefine
+          <literal>plugins</literal> setting here.
         '';
       };
 
@@ -118,7 +163,7 @@ in {
       '';
       serviceConfig = {
         Type = "notify";
-        ExecStart = "${uwsgi}/bin/uwsgi --uid ${cfg.user} --gid ${cfg.group} --json ${pkgs.writeText "uwsgi.json" (buildCfg cfg.instance)}";
+        ExecStart = "${uwsgi}/bin/uwsgi --uid ${cfg.user} --gid ${cfg.group} --json ${buildCfg "server" cfg.instance}/server.json";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID";
         NotifyAccess = "main";
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index 998bcd354c53..3e91450a39d2 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -64,7 +64,13 @@ in
           else if any (w: w.name == defaultDM) cfg.session.list then
             defaultDM
           else
-            throw "Default desktop manager ($(defaultDM)) not found.";
+            throw ''
+              Default desktop manager (${defaultDM}) not found.
+              Probably you want to change
+                services.xserver.desktopManager.default = "${defaultDM}";
+              to one of
+                ${concatMapStringsSep "\n  " (w: "services.xserver.desktopManager.default = \"${w.name}\";") cfg.session.list}
+            '';
       };
 
     };
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 55d7fd80cf97..b112fc2422a7 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -27,19 +27,24 @@ let
 
   nixos-gsettings-desktop-schemas = pkgs.stdenv.mkDerivation {
     name = "nixos-gsettings-desktop-schemas";
-    buildInputs = [ pkgs.nixos-artwork ];
     buildCommand = ''
-     mkdir -p $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas
-     cp -rf ${gnome3.gsettings_desktop_schemas}/share/gsettings-schemas/gsettings-desktop-schemas*/glib-2.0 $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/
-     chmod -R a+w $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas
-     cat - > $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/glib-2.0/schemas/nixos-defaults.gschema.override <<- EOF
+     mkdir -p $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas
+     cp -rf ${gnome3.gsettings_desktop_schemas}/share/gsettings-schemas/gsettings-desktop-schemas*/glib-2.0/schemas/*.xml $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas
+
+     ${concatMapStrings (pkg: "cp -rf ${pkg}/share/gsettings-schemas/*/glib-2.0/schemas/*.xml $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas\n") cfg.extraGSettingsOverridePackages}
+
+     chmod -R a+w $out/share/gsettings-schemas/nixos-gsettings-overrides
+     cat - > $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/nixos-defaults.gschema.override <<- EOF
        [org.gnome.desktop.background]
        picture-uri='${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png'
 
        [org.gnome.desktop.screensaver]
        picture-uri='${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png'
+
+       ${cfg.extraGSettingsOverrides}
      EOF
-     ${pkgs.glib}/bin/glib-compile-schemas $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/glib-2.0/schemas/
+
+     ${pkgs.glib}/bin/glib-compile-schemas $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/
     '';
   };
 
@@ -47,24 +52,38 @@ in {
 
   options = {
 
-    services.xserver.desktopManager.gnome3.enable = mkOption {
-      default = false;
-      example = true;
-      description = "Enable Gnome 3 desktop manager.";
-    };
+    services.xserver.desktopManager.gnome3 = {
+      enable = mkOption {
+        default = false;
+        example = true;
+        description = "Enable Gnome 3 desktop manager.";
+      };
 
-    services.xserver.desktopManager.gnome3.sessionPath = mkOption {
-      default = [];
-      example = literalExample "[ pkgs.gnome3.gpaste ]";
-      description = "Additional list of packages to be added to the session search path.
-                     Useful for gnome shell extensions or gsettings-conditionated autostart.";
-      apply = list: list ++ [ gnome3.gnome_shell gnome3.gnome-shell-extensions ];
-    };
+      sessionPath = mkOption {
+        default = [];
+        example = literalExample "[ pkgs.gnome3.gpaste ]";
+        description = "Additional list of packages to be added to the session search path.
+                       Useful for gnome shell extensions or gsettings-conditionated autostart.";
+        apply = list: list ++ [ gnome3.gnome_shell gnome3.gnome-shell-extensions ];
+      };
+
+      extraGSettingsOverrides = mkOption {
+        default = "";
+        type = types.lines;
+        description = "Additional gsettings overrides.";
+      };
+
+      extraGSettingsOverridePackages = mkOption {
+        default = [];
+        type = types.listOf types.path;
+        description = "List of packages for which gsettings are overridden.";
+      };
+    };  
 
     environment.gnome3.packageSet = mkOption {
       type = types.nullOr types.package;
       default = null;
-      example = literalExample "pkgs.gnome3_16";
+      example = literalExample "pkgs.gnome3_18";
       description = "Which GNOME 3 package set to use.";
       apply = p: if p == null then pkgs.gnome3 else p;
     };
@@ -130,7 +149,7 @@ in {
           export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${mimeAppsList}/share
 
           # Override gsettings-desktop-schema
-          export XDG_DATA_DIRS=${nixos-gsettings-desktop-schemas}/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS
+          export XDG_DATA_DIRS=${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS
 
           # Let nautilus find extensions
           export NAUTILUS_EXTENSION_DIR=${config.system.path}/lib/nautilus/extensions-3.0/
diff --git a/nixos/modules/services/x11/desktop-managers/kde4.nix b/nixos/modules/services/x11/desktop-managers/kde4.nix
index 29cca248cde3..80e408be4923 100644
--- a/nixos/modules/services/x11/desktop-managers/kde4.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde4.nix
@@ -108,6 +108,12 @@ in
                 sed -e '/nix\\store\|nix\/store/ d' -i $HOME/.config/Trolltech.conf
             fi
 
+            # Load PulseAudio module for routing support.
+            # See http://colin.guthr.ie/2009/10/so-how-does-the-kde-pulseaudio-support-work-anyway/
+            ${optionalString config.hardware.pulseaudio.enable ''
+              ${config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1"
+            ''}
+
             # Start KDE.
             exec ${kde_workspace}/bin/startkde
           '';
diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index e8c768e41fad..2dc03b7fe637 100644
--- a/nixos/modules/services/x11/desktop-managers/kde5.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde5.nix
@@ -55,12 +55,20 @@ in
     services.xserver.desktopManager.session = singleton {
       name = "kde5";
       bgSupport = true;
-      start = ''exec ${kde5.plasma-workspace}/bin/startkde;'';
+      start = ''
+        # Load PulseAudio module for routing support.
+        # See http://colin.guthr.ie/2009/10/so-how-does-the-kde-pulseaudio-support-work-anyway/
+        ${optionalString config.hardware.pulseaudio.enable ''
+          ${config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1"
+        ''}
+
+        exec startkde
+      '';
     };
 
     security.setuidOwners = singleton {
       program = "kcheckpass";
-      source = "${kde5.plasma-workspace}/lib/libexec/kcheckpass";
+      source = "${kde5.plasma-workspace.out}/lib/libexec/kcheckpass";
       owner = "root";
       group = "root";
       setuid = true;
@@ -68,8 +76,6 @@ in
 
     environment.systemPackages =
       [
-        pkgs.qt4 # qtconfig is the only way to set Qt 4 theme
-
         kde5.frameworkintegration
         kde5.kinit
 
@@ -95,16 +101,12 @@ in
         kde5.plasma-workspace
         kde5.plasma-workspace-wallpapers
 
-        kde5.ark
         kde5.dolphin
         kde5.dolphin-plugins
         kde5.ffmpegthumbs
-        kde5.gwenview
-        kde5.kate
         kde5.kdegraphics-thumbnailers
         kde5.kio-extras
         kde5.konsole
-        kde5.okular
         kde5.print-manager
 
         # Oxygen icons moved to KDE Frameworks 5.16 and later.
@@ -168,12 +170,12 @@ in
 
     # Enable GTK applications to load SVG icons
     environment.variables = mkIf (lib.hasAttr "breeze-icons" kde5) {
-      GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache";
+      GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache";
     };
 
     fonts.fonts = [ (kde5.oxygen-fonts or pkgs.noto-fonts) ];
 
-    programs.ssh.askPassword = "${kde5.ksshaskpass}/bin/ksshaskpass";
+    programs.ssh.askPassword = "${kde5.ksshaskpass.out}/bin/ksshaskpass";
 
     # Enable helpful DBus services.
     services.udisks2.enable = true;
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 3aa09193a66e..da7be748d8b2 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -16,13 +16,6 @@ let
   cfg = config.services.xserver;
   xorg = pkgs.xorg;
 
-  vaapiDrivers = pkgs.buildEnv {
-    name = "vaapi-drivers";
-    paths = cfg.vaapiDrivers;
-    # We only want /lib/dri, but with a single input path, we need "/" for it to work
-    pathsToLink = [ "/" ];
-  };
-
   fontconfig = config.fonts.fontconfig;
   xresourcesXft = pkgs.writeText "Xresources-Xft" ''
     ${optionalString (fontconfig.dpi != 0) ''Xft.dpi: ${toString fontconfig.dpi}''}
@@ -56,18 +49,6 @@ let
         fi
       ''}
 
-      ${optionalString cfg.displayManager.desktopManagerHandlesLidAndPower ''
-        # Stop systemd from handling the power button and lid switch,
-        # since presumably the desktop environment will handle these.
-        if [ -z "$_INHIBITION_LOCK_TAKEN" ]; then
-          export _INHIBITION_LOCK_TAKEN=1
-          if ! ${config.systemd.package}/bin/loginctl show-session $XDG_SESSION_ID | grep -q '^RemoteHost='; then
-            exec ${config.systemd.package}/bin/systemd-inhibit --what=handle-lid-switch:handle-power-key --why="Desktop environment handles power events" "$0" "$sessionType"
-          fi
-        fi
-
-      ''}
-
       ${optionalString cfg.startGnuPGAgent ''
         if test -z "$SSH_AUTH_SOCK"; then
             # Restart this script as a child of the GnuPG agent.
@@ -90,9 +71,6 @@ let
 
         # Publish access credentials in the root window.
         ${config.hardware.pulseaudio.package.out}/bin/pactl load-module module-x11-publish "display=$DISPLAY"
-
-        # Keep track of devices.  Mostly useful for Phonon/KDE.
-        ${config.hardware.pulseaudio.package.out}/bin/pactl load-module module-device-manager "do_routing=1"
       ''}
 
       # Tell systemd about our $DISPLAY. This is needed by the
@@ -107,8 +85,6 @@ let
           ${xorg.xrdb}/bin/xrdb -merge ~/.Xdefaults
       fi
 
-      export LIBVA_DRIVERS_PATH=${vaapiDrivers}/lib/dri
-
       # Speed up application start by 50-150ms according to
       # http://kdemonkey.blogspot.nl/2008/04/magic-trick.html
       rm -rf $HOME/.compose-cache
@@ -231,17 +207,6 @@ in
         '';
       };
 
-      desktopManagerHandlesLidAndPower = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Whether the display manager should prevent systemd from handling
-          lid and power events. This is normally handled by the desktop
-          environment's power manager. Turn this off when using a minimal
-          X11 setup without a full power manager.
-        '';
-      };
-
       session = mkOption {
         default = [];
         example = literalExample
@@ -321,9 +286,11 @@ in
   };
 
   config = {
-
     services.xserver.displayManager.xserverBin = "${xorg.xorgserver.out}/bin/X";
-
   };
 
+  imports = [
+   (mkRemovedOptionModule [ "services" "xserver" "displayManager" "desktopManagerHandlesLidAndPower" ])
+  ];
+
 }
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index 9460395f86d6..ac7db3d9adc4 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -86,7 +86,8 @@ in
       };
 
       background = mkOption {
-        type = types.path;
+        type = types.str;
+        default = "${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png";
         description = ''
           The background image or color to use.
         '';
@@ -152,9 +153,6 @@ in
     };
 
     users.extraGroups.lightdm.gid = config.ids.gids.lightdm;
-
-    services.xserver.displayManager.lightdm.background = mkDefault "${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png";
-
     services.xserver.tty     = null; # We might start multiple X servers so let the tty increment themselves..
     services.xserver.display = null; # We specify our own display (and logfile) in xserver-wrapper up there
   };
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index 6b344822977f..7a17a222bcab 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -31,6 +31,9 @@ let
     [General]
     HaltCommand=${pkgs.systemd}/bin/systemctl poweroff
     RebootCommand=${pkgs.systemd}/bin/systemctl reboot
+    ${optionalString cfg.autoNumlock ''
+    Numlock=on
+    ''}
 
     [Theme]
     Current=${cfg.theme}
@@ -110,6 +113,14 @@ in
         '';
       };
 
+      autoNumlock = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable numlock at login.
+        '';
+      };
+
       setupScript = mkOption {
         type = types.str;
         default = "";
diff --git a/nixos/modules/services/x11/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix
new file mode 100644
index 000000000000..12cc1e7e6460
--- /dev/null
+++ b/nixos/modules/services/x11/hardware/libinput.nix
@@ -0,0 +1,230 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let cfg = config.services.xserver.libinput;
+    xorgBool = v: if v then "on" else "off";
+in {
+
+  options = {
+
+    services.xserver.libinput = {
+
+      enable = mkEnableOption "libinput";
+
+      dev = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "/dev/input/event0";
+        description =
+          ''
+            Path for touchpad device.  Set to null to apply to any
+            auto-detected touchpad.
+          '';
+      };
+
+      accelProfile = mkOption {
+        type = types.enum [ "flat" "adaptive" ];
+        default = "flat";
+        example = "adaptive";
+        description =
+          ''
+            Sets  the pointer acceleration profile to the given profile. Permitted values are adaptive, flat.
+            Not all devices support this option or all profiles. If a profile is unsupported, the default profile
+            for this is used. For a description on the profiles and their behavior, see the libinput documentation.
+          '';
+      };    
+      
+      accelSpeed = mkOption {
+        type = types.nullOr types.string;
+        default = null;
+        description = "Cursor acceleration (how fast speed increases from minSpeed to maxSpeed).";
+      };
+
+      buttonMapping = mkOption {
+        type = types.nullOr types.string;
+        default = null;
+        description =
+          ''
+            Sets the logical button mapping for this device, see XSetPointerMapping(3). The string  must
+            be  a  space-separated  list  of  button mappings in the order of the logical buttons on the
+            device, starting with button 1.  The default mapping is "1 2 3 ... 32". A mapping of 0 deac‐
+            tivates the button. Multiple buttons can have the same mapping.  Invalid mapping strings are
+            discarded and the default mapping is used for all buttons.  Buttons  not  specified  in  the
+            user's mapping use the default mapping. See section BUTTON MAPPING for more details.
+          '';
+      };
+
+      calibrationMatrix = mkOption {
+        type = types.nullOr types.string;
+        default = null;
+        description =
+          ''
+            A  string  of  9 space-separated floating point numbers.  Sets the calibration matrix to the
+            3x3 matrix where the first row is (abc), the second row is (def) and the third row is (ghi).
+          '';
+      };
+
+      clickMethod = mkOption {
+        type = types.nullOr (types.enum [ "none" "buttonareas" "clickfinger" ]);
+        default = null;
+        example = "none";
+        description =
+          ''
+            Enables a click method. Permitted values are none, buttonareas, clickfinger.
+            Not all devices support all methods, if an option is unsupported,
+            the default click method for this device is used. 
+          '';
+      };
+      
+      leftHanded = mkOption {
+        type = types.bool;
+        default = false;
+        example = true;
+        description = "Enables left-handed button orientation, i.e. swapping left and right buttons.";
+      };
+
+      middleEmulation = mkOption {
+        type = types.bool;
+        default = true;
+        example = false;
+        description =
+          ''
+            Enables middle button emulation. When enabled, pressing the left and right buttons
+            simultaneously produces a middle mouse button click.
+          '';
+      };
+      
+      naturalScrolling = mkOption {
+        type = types.bool;
+        default = false;
+        example = true;
+        description = "Enables or disables natural scrolling behavior.";
+      };
+
+      scrollButton = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 1;
+        description =
+          ''
+            Designates a button as scroll button. If the ScrollMethod is button and the button is logically
+            held down, x/y axis movement is converted into scroll events.
+          '';
+      };
+
+      scrollMethod = mkOption {
+        type = types.enum [ "twofinger" "edge" "none" ];
+        default = "twofinger";
+        example = "edge";
+        description =
+          ''
+            Specify the scrolling method.
+          '';
+      };
+
+      horizontalScrolling = mkOption {
+        type = types.bool;
+        default = true;
+        example = false;
+        description =
+          ''
+            Disables horizontal scrolling. When disabled, this driver will discard any horizontal scroll
+            events from libinput. Note that this does not disable horizontal scrolling, it merely
+            discards the horizontal axis from any scroll events.
+          '';
+      };
+
+      sendEventsMode = mkOption {
+        type = types.enum [ "disabled" "enabled" "disabled-on-external-mouse" ];
+        default = "enabled";
+        example = "disabled";
+        description =
+          ''
+            Sets the send events mode to disabled, enabled, or "disable when an external mouse is connected".
+          '';
+      };
+
+      tapping = mkOption {
+        type = types.bool;
+        default = true;
+        example = false;
+        description =
+          ''
+            Enables or disables tap-to-click behavior.
+          '';
+      };
+
+      tappingDragLock = mkOption {
+        type = types.bool;
+        default = true;
+        example = false;
+        description =
+          ''
+            Enables or disables drag lock during tapping behavior. When enabled, a finger up during tap-
+            and-drag will not immediately release the button. If the finger is set down again within the
+            timeout, the draging process continues.
+          '';
+      };
+
+      disableWhileTyping = mkOption {
+        type = types.bool;
+        default = true;
+        example = false;
+        description =
+          ''
+            Disable input method while typing.
+          '';
+      };
+
+      additionalOptions = mkOption {
+        type = types.str;
+        default = "";
+        example =
+        ''
+          Option "DragLockButtons" "L1 B1 L2 B2"
+        '';
+        description = "Additional options for libinput touchpad driver.";
+      };
+
+    };
+
+  };
+
+
+  config = mkIf cfg.enable {
+
+    services.xserver.modules = [ pkgs.xorg.xf86inputlibinput ];
+
+    environment.systemPackages = [ pkgs.xorg.xf86inputlibinput ];
+
+    services.xserver.config =
+      ''
+        # Automatically enable the libinput driver for all touchpads.
+        Section "InputClass"
+          Identifier "libinputConfiguration"
+          MatchIsTouchpad "on"
+          ${optionalString (cfg.dev != null) ''MatchDevicePath "${cfg.dev}"''}
+          Driver "libinput"
+          Option "AccelProfile" "${cfg.accelProfile}"
+          ${optionalString (cfg.accelSpeed != null) ''Option "AccelSpeed" "${cfg.accelSpeed}"''}
+          ${optionalString (cfg.buttonMapping != null) ''Option "ButtonMapping" "${cfg.buttonMapping}"''}
+          ${optionalString (cfg.calibrationMatrix != null) ''Option "CalibrationMatrix" "${cfg.calibrationMatrix}"''}
+          ${optionalString (cfg.clickMethod != null) ''Option "ClickMethod" "${cfg.clickMethod}"''}
+          Option "LeftHanded" "${xorgBool cfg.leftHanded}"
+          Option "MiddleEmulation" "${xorgBool cfg.middleEmulation}"
+          Option "NaturalScrolling" "${xorgBool cfg.naturalScrolling}"
+          ${optionalString (cfg.scrollButton != null) ''Option "ScrollButton" "${cfg.scrollButton}"''}
+          Option "ScrollMethod" "${cfg.scrollMethod}"
+          Option "HorizontalScrolling" "${xorgBool cfg.horizontalScrolling}"
+          Option "SendEventsMode" "${cfg.sendEventsMode}"
+          Option "Tapping" "${xorgBool cfg.tapping}"
+          Option "TappingDragLock" "${xorgBool cfg.tappingDragLock}"
+          Option "DisableWhileTyping" "${xorgBool cfg.disableWhileTyping}"
+          ${cfg.additionalOptions}
+        EndSection
+      '';
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/hardware/synaptics.nix b/nixos/modules/services/x11/hardware/synaptics.nix
index e50ed08a218a..2981e7545e81 100644
--- a/nixos/modules/services/x11/hardware/synaptics.nix
+++ b/nixos/modules/services/x11/hardware/synaptics.nix
@@ -62,6 +62,13 @@ in {
         description = "Cursor speed factor for highest-speed finger motion.";
       };
 
+      scrollDelta = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 75;
+        description = "Move distance of the finger for a scroll event.";
+      };
+
       twoFingerScroll = mkOption {
         type = types.bool;
         default = false;
@@ -122,6 +129,20 @@ in {
         description = "Whether to enable palm detection (hardware support required)";
       };
 
+      palmMinWidth = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 5;
+        description = "Minimum finger width at which touch is considered a palm";
+      };
+
+      palmMinZ = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 20;
+        description = "Minimum finger pressure at which touch is considered a palm";
+      };
+
       horizontalScroll = mkOption {
         type = types.bool;
         default = true;
@@ -174,8 +195,12 @@ in {
           Option "HorizTwoFingerScroll" "${if cfg.horizTwoFingerScroll then "1" else "0"}"
           Option "VertEdgeScroll" "${if cfg.vertEdgeScroll then "1" else "0"}"
           Option "HorizEdgeScroll" "${if cfg.horizEdgeScroll then "1" else "0"}"
-          ${if cfg.palmDetect then ''Option "PalmDetect" "1"'' else ""}
-          ${if cfg.horizontalScroll then "" else ''Option "HorizScrollDelta" "0"''}
+          ${optionalString cfg.palmDetect ''Option "PalmDetect" "1"''}
+          ${optionalString (cfg.palmMinWidth != null) ''Option "PalmMinWidth" "${toString cfg.palmMinWidth}"''}
+          ${optionalString (cfg.palmMinZ != null) ''Option "PalmMinZ" "${toString cfg.palmMinZ}"''}
+          ${optionalString (cfg.scrollDelta != null) ''Option "VertScrollDelta" "${toString cfg.scrollDelta}"''}
+          ${if !cfg.horizontalScroll then ''Option "HorizScrollDelta" "0"''
+            else (optionalString (cfg.scrollDelta != null) ''Option "HorizScrollDelta" "${toString cfg.scrollDelta}"'')}
           ${cfg.additionalOptions}
         EndSection
       '';
diff --git a/nixos/modules/services/x11/window-managers/bspwm.nix b/nixos/modules/services/x11/window-managers/bspwm.nix
index 8b4e91d25aa4..271b1b6cf5da 100644
--- a/nixos/modules/services/x11/window-managers/bspwm.nix
+++ b/nixos/modules/services/x11/window-managers/bspwm.nix
@@ -8,16 +8,39 @@ in
 
 {
   options = {
-    services.xserver.windowManager.bspwm.enable = mkEnableOption "bspwm";
+    services.xserver.windowManager.bspwm = {
+        enable = mkEnableOption "bspwm";
+        startThroughSession = mkOption {
+            type = with types; bool;
+            default = false;
+            description = "
+                Start the window manager through the script defined in 
+                sessionScript. Defaults to the the bspwm-session script
+                provided by bspwm
+            ";
+        };
+        sessionScript = mkOption {
+            default = "${pkgs.bspwm}/bin/bspwm-session";
+            defaultText = "(pkgs.bspwm)/bin/bspwm-session";
+            description = "
+                The start-session script to use. Defaults to the
+                provided bspwm-session script from the bspwm package.
+
+                Does nothing unless `bspwm.startThroughSession` is enabled
+            ";
+        };
+    };
   };
 
   config = mkIf cfg.enable {
     services.xserver.windowManager.session = singleton {
       name = "bspwm";
-      start = "
-        ${pkgs.sxhkd}/bin/sxhkd &
-        ${pkgs.bspwm}/bin/bspwm
-      ";
+      start = if cfg.startThroughSession
+        then cfg.sessionScript
+        else ''
+            SXHKD_SHELL=/bin/sh ${pkgs.sxhkd}/bin/sxhkd -f 100 &
+            ${pkgs.bspwm}/bin/bspwm
+        '';
     };
     environment.systemPackages = [ pkgs.bspwm ];
   };
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
index 37d3348b8a32..26dfbb1f4e18 100644
--- a/nixos/modules/services/x11/window-managers/default.nix
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -13,6 +13,7 @@ in
     ./clfswm.nix
     ./compiz.nix
     ./dwm.nix
+    ./exwm.nix
     ./fluxbox.nix
     ./herbstluftwm.nix
     ./i3.nix
diff --git a/nixos/modules/services/x11/window-managers/exwm.nix b/nixos/modules/services/x11/window-managers/exwm.nix
new file mode 100644
index 000000000000..dbbd8a125d66
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/exwm.nix
@@ -0,0 +1,55 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.xserver.windowManager.exwm;
+  loadScript = pkgs.writeText "emacs-exwm-load" ''
+    (require 'exwm)
+    ${optionalString cfg.enableDefaultConfig ''
+      (require 'exwm-config)
+      (exwm-config-default)
+    ''}
+  '';
+  packages = epkgs: cfg.extraPackages epkgs ++ [ epkgs.exwm ];
+  exwm-emacs = pkgs.emacsWithPackages packages;
+in
+
+{
+  options = {
+    services.xserver.windowManager.exwm = {
+      enable = mkEnableOption "exwm";
+      enableDefaultConfig = mkOption {
+        default = true;
+        example = false;
+        type = lib.types.bool;
+        description = "Enable an uncustomised exwm configuration.";
+      };
+      extraPackages = mkOption {
+        default = self: [];
+        example = literalExample ''
+          epkgs: [
+            epkgs.emms
+            epkgs.magit
+            epkgs.proofgeneral
+          ]
+        '';
+        description = ''
+          Extra packages available to Emacs. The value must be a
+          function which receives the attrset defined in
+          <varname>emacsPackages</varname> as the sole argument.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.xserver.windowManager.session = singleton {
+      name = "exwm";
+      start = ''
+        ${exwm-emacs}/bin/emacs -l ${loadScript}
+      '';
+    };
+    environment.systemPackages = [ exwm-emacs ];
+  };
+}
diff --git a/nixos/modules/services/x11/window-managers/i3.nix b/nixos/modules/services/x11/window-managers/i3.nix
index 0d5816e363d6..2e2e10cc33b0 100644
--- a/nixos/modules/services/x11/window-managers/i3.nix
+++ b/nixos/modules/services/x11/window-managers/i3.nix
@@ -34,6 +34,6 @@ in
         '';
       }];
     };
-    environment.systemPackages = [ pkgs.i3 ];
+    environment.systemPackages = with pkgs; [ i3 ];
   };
 }
diff --git a/nixos/modules/services/x11/window-managers/metacity.nix b/nixos/modules/services/x11/window-managers/metacity.nix
index 3e5229be634f..2957ad91be45 100644
--- a/nixos/modules/services/x11/window-managers/metacity.nix
+++ b/nixos/modules/services/x11/window-managers/metacity.nix
@@ -20,7 +20,7 @@ in
     services.xserver.windowManager.session = singleton
       { name = "metacity";
         start = ''
-          env LD_LIBRARY_PATH=${xorg.libX11}/lib:${xorg.libXext}/lib:/usr/lib/
+          env LD_LIBRARY_PATH=${xorg.libX11.out}/lib:${xorg.libXext.out}/lib:/usr/lib/
           # !!! Hack: load the schemas for Metacity.
           GCONF_CONFIG_SOURCE=xml::~/.gconf ${gnome.GConf}/bin/gconftool-2 \
             --makefile-install-rule ${gnome.metacity}/etc/gconf/schemas/*.schemas # */
diff --git a/nixos/modules/services/x11/window-managers/openbox.nix b/nixos/modules/services/x11/window-managers/openbox.nix
index 091b533b28be..07ef77151e95 100644
--- a/nixos/modules/services/x11/window-managers/openbox.nix
+++ b/nixos/modules/services/x11/window-managers/openbox.nix
@@ -8,7 +8,7 @@ in
 
 {
   options = {
-    services.xserver.windowManager.openbox.enable = mkEnableOption "oroborus";
+    services.xserver.windowManager.openbox.enable = mkEnableOption "openbox";
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index 86f0641b0e37..60b6a97416ab 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -156,13 +156,16 @@ in
       inputClassSections = mkOption {
         type = types.listOf types.lines;
         default = [];
-        example = [ ''
-           Identifier      "Trackpoint Wheel Emulation"
-           MatchProduct    "ThinkPad USB Keyboard with TrackPoint"
-           Option          "EmulateWheel"          "true
-           Option          "EmulateWheelButton"    "2"
-           Option          "Emulate3Buttons"       "false"
-          '' ];
+        example = literalExample ''
+          [ '''
+              Identifier      "Trackpoint Wheel Emulation"
+              MatchProduct    "ThinkPad USB Keyboard with TrackPoint"
+              Option          "EmulateWheel"          "true
+              Option          "EmulateWheelButton"    "2"
+              Option          "Emulate3Buttons"       "false"
+            '''
+          ]
+        '';
         description = "Content of additional InputClass sections of the X server configuration file.";
       };
 
@@ -216,15 +219,6 @@ in
         '';
       };
 
-      vaapiDrivers = mkOption {
-        type = types.listOf types.path;
-        default = [ ];
-        example = literalExample "[ pkgs.vaapiIntel pkgs.vaapiVdpau ]";
-        description = ''
-          Packages providing libva acceleration drivers.
-        '';
-      };
-
       startGnuPGAgent = mkOption {
         type = types.bool;
         default = false;
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index dd2ce1894ae6..9d61d64f7553 100644
--- a/nixos/modules/system/activation/activation-script.nix
+++ b/nixos/modules/system/activation/activation-script.nix
@@ -31,18 +31,19 @@ in
     system.activationScripts = mkOption {
       default = {};
 
-      example = {
-        stdio = {
-          text = ''
-            # Needed by some programs.
-            ln -sfn /proc/self/fd /dev/fd
-            ln -sfn /proc/self/fd/0 /dev/stdin
-            ln -sfn /proc/self/fd/1 /dev/stdout
-            ln -sfn /proc/self/fd/2 /dev/stderr
-          '';
-          deps = [];
-        };
-      };
+      example = literalExample ''
+        { stdio = {
+            text = '''
+              # Needed by some programs.
+              ln -sfn /proc/self/fd /dev/fd
+              ln -sfn /proc/self/fd/0 /dev/stdin
+              ln -sfn /proc/self/fd/1 /dev/stdout
+              ln -sfn /proc/self/fd/2 /dev/stderr
+            ''';
+            deps = [];
+          };
+        }
+      '';
 
       description = ''
         A set of shell script fragments that are executed when a NixOS
@@ -95,6 +96,18 @@ in
 
     };
 
+    environment.usrbinenv = mkOption {
+      default = "${pkgs.coreutils}/bin/env";
+      example = literalExample ''
+        "''${pkgs.busybox}/bin/env"
+      '';
+      type = types.nullOr types.path;
+      visible = false;
+      description = ''
+        The env(1) executable that is linked system-wide to
+        <literal>/usr/bin/env</literal>.
+      '';
+    };
   };
 
 
@@ -129,11 +142,15 @@ in
         mkdir -m 0555 -p /var/empty
       '';
 
-    system.activationScripts.usrbinenv =
-      ''
+    system.activationScripts.usrbinenv = if config.environment.usrbinenv != null
+      then ''
         mkdir -m 0755 -p /usr/bin
-        ln -sfn ${pkgs.coreutils}/bin/env /usr/bin/.env.tmp
+        ln -sfn ${config.environment.usrbinenv} /usr/bin/.env.tmp
         mv /usr/bin/.env.tmp /usr/bin/env # atomically replace /usr/bin/env
+      ''
+      else ''
+        rm -f /usr/bin/env
+        rmdir --ignore-fail-on-non-empty /usr/bin /usr
       '';
 
     system.activationScripts.tmpfs =
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index 655fbab2a843..093b7f1ff225 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -261,12 +261,12 @@ while (my ($unit, $state) = each %{$activePrev}) {
 
 sub pathToUnitName {
     my ($path) = @_;
-    die unless substr($path, 0, 1) eq "/";
-    return "-" if $path eq "/";
-    $path = substr($path, 1);
-    $path =~ s/\//-/g;
-    # FIXME: handle - and unprintable characters.
-    return $path;
+    open my $cmd, "-|", "systemd-escape", "--suffix=mount", "-p", $path
+        or die "Unable to escape $path!\n";
+    my $escaped = join "", <$cmd>;
+    chomp $escaped;
+    close $cmd or die;
+    return $escaped;
 }
 
 sub unique {
@@ -290,7 +290,7 @@ my ($newFss, $newSwaps) = parseFstab "$out/etc/fstab";
 foreach my $mountPoint (keys %$prevFss) {
     my $prev = $prevFss->{$mountPoint};
     my $new = $newFss->{$mountPoint};
-    my $unit = pathToUnitName($mountPoint) . ".mount";
+    my $unit = pathToUnitName($mountPoint);
     if (!defined $new) {
         # Filesystem entry disappeared, so unmount it.
         $unitsToStop{$unit} = 1;
@@ -323,7 +323,7 @@ foreach my $device (keys %$prevSwaps) {
 
 
 # Should we have systemd re-exec itself?
-my $prevSystemd = abs_path("/proc/1/exe") or die;
+my $prevSystemd = abs_path("/proc/1/exe") // "/unknown";
 my $newSystemd = abs_path("@systemd@/lib/systemd/systemd") or die;
 my $restartSystemd = $prevSystemd ne $newSystemd;
 
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index d66580b7b9be..2d1b0ffb54ce 100644
--- a/nixos/modules/system/activation/top-level.nix
+++ b/nixos/modules/system/activation/top-level.nix
@@ -178,9 +178,10 @@ in
       default = false;
       description = ''
         If enabled, copies the NixOS configuration file
-        <literal>$NIXOS_CONFIG</literal> (usually
-        <filename>/etc/nixos/configuration.nix</filename>)
-        to the system store path.
+        (usually <filename>/etc/nixos/configuration.nix</filename>)
+        and links it from the resulting system
+        (getting to <filename>/run/current-system/configuration.nix</filename>).
+        Note that only this single file is copied, even if it imports others.
       '';
     };
 
@@ -238,7 +239,9 @@ in
     system.extraSystemBuilderCmds =
       optionalString
         config.system.copySystemConfiguration
-        "cp ${maybeEnv "NIXOS_CONFIG" "/etc/nixos/configuration.nix"} $out";
+        ''ln -s '${import ../../../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>}' \
+            "$out/configuration.nix"
+        '';
 
     system.build.toplevel = system;
 
diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix
index 6c6e2fafad43..6e226c190609 100644
--- a/nixos/modules/system/boot/initrd-network.nix
+++ b/nixos/modules/system/boot/initrd-network.nix
@@ -3,9 +3,28 @@
 with lib;
 
 let
+
   cfg = config.boot.initrd.network;
 
+  udhcpcScript = pkgs.writeScript "udhcp-script"
+    ''
+      #! /bin/sh
+      if [ "$1" = bound ]; then
+        ip address add "$ip/$mask" dev "$interface"
+        if [ -n "$router" ]; then
+          ip route add default via "$router" dev "$interface"
+        fi
+        if [ -n "$dns" ]; then
+          rm -f /etc/resolv.conf
+          for i in $dns; do
+            echo "nameserver $dns" >> /etc/resolv.conf
+          done
+        fi
+      fi
+    '';
+
 in
+
 {
 
   options = {
@@ -14,82 +33,25 @@ in
       type = types.bool;
       default = false;
       description = ''
-        Add network connectivity support to initrd.
-
-        Network options are configured via <literal>ip</literal> kernel
-        option, according to the kernel documentation.
-      '';
-    };
-
-    boot.initrd.network.ssh.enable = mkOption {
-      type = types.bool;
-      default = false;
-      description = ''
-        Start SSH service during initrd boot. It can be used to debug failing
-        boot on a remote server, enter pasphrase for an encrypted partition etc.
-        Service is killed when stage-1 boot is finished.
-      '';
-    };
-
-    boot.initrd.network.ssh.port = mkOption {
-      type = types.int;
-      default = 22;
-      description = ''
-        Port on which SSH initrd service should listen.
-      '';
-    };
-
-    boot.initrd.network.ssh.shell = mkOption {
-      type = types.str;
-      default = "/bin/ash";
-      description = ''
-        Login shell of the remote user. Can be used to limit actions user can do.
+        Add network connectivity support to initrd. The network may be
+        configured using the <literal>ip</literal> kernel parameter,
+        as described in <link
+        xlink:href="https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt">the
+        kernel documentation</link>.  Otherwise, if
+        <option>networking.useDHCP</option> is enabled, an IP address
+        is acquired using DHCP.
       '';
     };
 
-    boot.initrd.network.ssh.hostRSAKey = mkOption {
-      type = types.nullOr types.path;
-      default = null;
+    boot.initrd.network.postCommands = mkOption {
+      default = "";
+      type = types.lines;
       description = ''
-        RSA SSH private key file in the Dropbear format.
-
-        WARNING: This key is contained insecurely in the global Nix store. Do NOT
-        use your regular SSH host private keys for this purpose or you'll expose
-        them to regular users!
-      '';
-    };
-
-    boot.initrd.network.ssh.hostDSSKey = mkOption {
-      type = types.nullOr types.path;
-      default = null;
-      description = ''
-        DSS SSH private key file in the Dropbear format.
-
-        WARNING: This key is contained insecurely in the global Nix store. Do NOT
-        use your regular SSH host private keys for this purpose or you'll expose
-        them to regular users!
-      '';
-    };
-
-    boot.initrd.network.ssh.hostECDSAKey = mkOption {
-      type = types.nullOr types.path;
-      default = null;
-      description = ''
-        ECDSA SSH private key file in the Dropbear format.
-
-        WARNING: This key is contained insecurely in the global Nix store. Do NOT
-        use your regular SSH host private keys for this purpose or you'll expose
-        them to regular users!
+        Shell commands to be executed after stage 1 of the
+        boot has initialised the network.
       '';
     };
 
-    boot.initrd.network.ssh.authorizedKeys = mkOption {
-      type = types.listOf types.str;
-      default = config.users.extraUsers.root.openssh.authorizedKeys.keys;
-      description = ''
-        Authorized keys for the root user on initrd.
-      '';
-    };
 
   };
 
@@ -99,51 +61,43 @@ in
 
     boot.initrd.extraUtilsCommands = ''
       copy_bin_and_libs ${pkgs.mkinitcpio-nfs-utils}/bin/ipconfig
-    '' + optionalString cfg.ssh.enable ''
-      copy_bin_and_libs ${pkgs.dropbear}/bin/dropbear
-
-      cp -pv ${pkgs.glibc}/lib/libnss_files.so.* $out/lib
     '';
 
-    boot.initrd.extraUtilsCommandsTest = optionalString cfg.ssh.enable ''
-      $out/bin/dropbear -V
-    '';
-
-    boot.initrd.postEarlyDeviceCommands = ''
-      # Search for interface definitions in command line
-      for o in $(cat /proc/cmdline); do
-        case $o in
-          ip=*)
-            ipconfig $o && hasNetwork=1
-            ;;
-        esac
-      done
-    '' + optionalString cfg.ssh.enable ''
-      if [ -n "$hasNetwork" ]; then
-        mkdir /dev/pts
-        mount -t devpts devpts /dev/pts
-
-        mkdir -p /etc
-        echo 'root:x:0:0:root:/root:${cfg.ssh.shell}' > /etc/passwd
-        echo '${cfg.ssh.shell}' > /etc/shells
-        echo 'passwd: files' > /etc/nsswitch.conf
-
-        mkdir -p /var/log
-        touch /var/log/lastlog
-
-        mkdir -p /etc/dropbear
-        ${optionalString (cfg.ssh.hostRSAKey != null) "ln -s ${cfg.ssh.hostRSAKey} /etc/dropbear/dropbear_rsa_host_key"}
-        ${optionalString (cfg.ssh.hostDSSKey != null) "ln -s ${cfg.ssh.hostDSSKey} /etc/dropbear/dropbear_dss_host_key"}
-        ${optionalString (cfg.ssh.hostECDSAKey != null) "ln -s ${cfg.ssh.hostECDSAKey} /etc/dropbear/dropbear_ecdsa_host_key"}
-
-        mkdir -p /root/.ssh
-        ${concatStrings (map (key: ''
-          echo -n ${escapeShellArg key} >> /root/.ssh/authorized_keys
-        '') cfg.ssh.authorizedKeys)}
-
-        dropbear -s -j -k -E -m -p ${toString cfg.ssh.port}
-      fi
-    '';
+    boot.initrd.preLVMCommands = mkBefore (
+      # Search for interface definitions in command line.
+      ''
+        for o in $(cat /proc/cmdline); do
+          case $o in
+            ip=*)
+              ipconfig $o && hasNetwork=1
+              ;;
+          esac
+        done
+      ''
+
+      # Otherwise, use DHCP.
+      + optionalString config.networking.useDHCP ''
+        if [ -z "$hasNetwork" ]; then
+
+          # Bring up all interfaces.
+          for iface in $(cd /sys/class/net && ls); do
+            echo "bringing up network interface $iface..."
+            ip link set "$iface" up
+          done
+
+          # Acquire a DHCP lease.
+          echo "acquiring IP address via DHCP..."
+          udhcpc --quit --now --script ${udhcpcScript} && hasNetwork=1
+        fi
+      ''
+
+      + ''
+        if [ -n "$hasNetwork" ]; then
+          echo "networking is up!"
+          ${cfg.postCommands}
+        fi
+      '');
 
   };
+
 }
diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix
new file mode 100644
index 000000000000..4cdc81541955
--- /dev/null
+++ b/nixos/modules/system/boot/initrd-ssh.nix
@@ -0,0 +1,124 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.boot.initrd.network.ssh;
+
+in
+
+{
+
+  options = {
+
+    boot.initrd.network.ssh.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Start SSH service during initrd boot. It can be used to debug failing
+        boot on a remote server, enter pasphrase for an encrypted partition etc.
+        Service is killed when stage-1 boot is finished.
+      '';
+    };
+
+    boot.initrd.network.ssh.port = mkOption {
+      type = types.int;
+      default = 22;
+      description = ''
+        Port on which SSH initrd service should listen.
+      '';
+    };
+
+    boot.initrd.network.ssh.shell = mkOption {
+      type = types.str;
+      default = "/bin/ash";
+      description = ''
+        Login shell of the remote user. Can be used to limit actions user can do.
+      '';
+    };
+
+    boot.initrd.network.ssh.hostRSAKey = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        RSA SSH private key file in the Dropbear format.
+
+        WARNING: This key is contained insecurely in the global Nix store. Do NOT
+        use your regular SSH host private keys for this purpose or you'll expose
+        them to regular users!
+      '';
+    };
+
+    boot.initrd.network.ssh.hostDSSKey = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        DSS SSH private key file in the Dropbear format.
+
+        WARNING: This key is contained insecurely in the global Nix store. Do NOT
+        use your regular SSH host private keys for this purpose or you'll expose
+        them to regular users!
+      '';
+    };
+
+    boot.initrd.network.ssh.hostECDSAKey = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        ECDSA SSH private key file in the Dropbear format.
+
+        WARNING: This key is contained insecurely in the global Nix store. Do NOT
+        use your regular SSH host private keys for this purpose or you'll expose
+        them to regular users!
+      '';
+    };
+
+    boot.initrd.network.ssh.authorizedKeys = mkOption {
+      type = types.listOf types.str;
+      default = config.users.extraUsers.root.openssh.authorizedKeys.keys;
+      description = ''
+        Authorized keys for the root user on initrd.
+      '';
+    };
+
+  };
+
+  config = mkIf (config.boot.initrd.network.enable && cfg.enable) {
+
+    boot.initrd.extraUtilsCommands = ''
+      copy_bin_and_libs ${pkgs.dropbear}/bin/dropbear
+      cp -pv ${pkgs.glibc}/lib/libnss_files.so.* $out/lib
+    '';
+
+    boot.initrd.extraUtilsCommandsTest = ''
+      $out/bin/dropbear -V
+    '';
+
+    boot.initrd.network.postCommands = ''
+      mkdir /dev/pts
+      mount -t devpts devpts /dev/pts
+
+      echo '${cfg.shell}' > /etc/shells
+      echo 'root:x:0:0:root:/root:${cfg.shell}' > /etc/passwd
+      echo 'passwd: files' > /etc/nsswitch.conf
+
+      mkdir -p /var/log
+      touch /var/log/lastlog
+
+      mkdir -p /etc/dropbear
+      ${optionalString (cfg.hostRSAKey != null) "ln -s ${cfg.hostRSAKey} /etc/dropbear/dropbear_rsa_host_key"}
+      ${optionalString (cfg.hostDSSKey != null) "ln -s ${cfg.hostDSSKey} /etc/dropbear/dropbear_dss_host_key"}
+      ${optionalString (cfg.hostECDSAKey != null) "ln -s ${cfg.hostECDSAKey} /etc/dropbear/dropbear_ecdsa_host_key"}
+
+      mkdir -p /root/.ssh
+      ${concatStrings (map (key: ''
+        echo -n ${escapeShellArg key} >> /root/.ssh/authorized_keys
+      '') cfg.authorizedKeys)}
+
+      dropbear -s -j -k -E -m -p ${toString cfg.port}
+    '';
+
+  };
+
+}
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix
index 6bc046d02611..a6bbca9b30bb 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -184,6 +184,9 @@ in
         "ide_disk"
         "ide_generic"
 
+        # SD cards and internal eMMC drives.
+        "mmc_block"
+
         # Support USB keyboards, in case the boot fails and we only have
         # a USB keyboard.
         "uhci_hcd"
diff --git a/nixos/modules/system/boot/loader/init-script/init-script-builder.sh b/nixos/modules/system/boot/loader/init-script/init-script-builder.sh
index 502b3b63af2f..08d4ab14c9ca 100644
--- a/nixos/modules/system/boot/loader/init-script/init-script-builder.sh
+++ b/nixos/modules/system/boot/loader/init-script/init-script-builder.sh
@@ -80,8 +80,13 @@ for generation in $(
     | sort -n -r); do
     link=/nix/var/nix/profiles/system-$generation-link
     date=$(stat --printf="%y\n" $link | sed 's/\..*//')
-    kernelVersion=$(cd $(dirname $(readlink -f $link/kernel))/lib/modules && echo *)
-    addEntry "NixOS - Configuration $generation ($date - $kernelVersion)" $link "$generation ($date)"
+    if [ -d $link/kernel ]; then
+      kernelVersion=$(cd $(dirname $(readlink -f $link/kernel))/lib/modules && echo *)
+      suffix="($date - $kernelVersion)"
+    else
+      suffix="($date)"
+    fi
+    addEntry "NixOS - Configuration $generation $suffix" $link "$generation ($date)"
 done
 
 mv $tmpOther $targetOther
diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix
index 59bff5472e84..77a82547031a 100644
--- a/nixos/modules/system/boot/luksroot.nix
+++ b/nixos/modules/system/boot/luksroot.nix
@@ -436,9 +436,9 @@ in
       ${optionalString luks.yubikeySupport ''
         copy_bin_and_libs ${pkgs.ykpers}/bin/ykchalresp
         copy_bin_and_libs ${pkgs.ykpers}/bin/ykinfo
-        copy_bin_and_libs ${pkgs.openssl}/bin/openssl
+        copy_bin_and_libs ${pkgs.openssl.bin}/bin/openssl
 
-        cc -O3 -I${pkgs.openssl}/include -L${pkgs.openssl}/lib ${./pbkdf2-sha512.c} -o pbkdf2-sha512 -lcrypto
+        cc -O3 -I${pkgs.openssl}/include -L${pkgs.openssl.out}/lib ${./pbkdf2-sha512.c} -o pbkdf2-sha512 -lcrypto
         strip -s pbkdf2-sha512
         copy_bin_and_libs pbkdf2-sha512
 
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index 34eea9af83b1..ab7485500261 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -93,11 +93,13 @@ let
 
   checkNetwork = checkUnitConfig "Network" [
     (assertOnlyFields [
-      "Description" "DHCP" "DHCPServer" "IPv4LL" "IPv4LLRoute"
+      "Description" "DHCP" "DHCPServer" "IPForward" "IPMasquerade" "IPv4LL" "IPv4LLRoute"
       "LLMNR" "Domains" "Bridge" "Bond"
     ])
     (assertValueOneOf "DHCP" ["both" "none" "v4" "v6"])
     (assertValueOneOf "DHCPServer" boolValues)
+    (assertValueOneOf "IPForward" ["yes" "no" "ipv4" "ipv6"])
+    (assertValueOneOf "IPMasquerade" boolValues)
     (assertValueOneOf "IPv4LL" boolValues)
     (assertValueOneOf "IPv4LLRoute" boolValues)
     (assertValueOneOf "LLMNR" boolValues)
@@ -129,6 +131,16 @@ let
     (assertValueOneOf "RequestBroadcast" boolValues)
   ];
 
+  checkDhcpServer = checkUnitConfig "DHCPServer" [
+    (assertOnlyFields [
+      "PoolOffset" "PoolSize" "DefaultLeaseTimeSec" "MaxLeaseTimeSec"
+      "EmitDNS" "DNS" "EmitNTP" "NTP" "EmitTimezone" "Timezone"
+    ])
+    (assertValueOneOf "EmitDNS" boolValues)
+    (assertValueOneOf "EmitNTP" boolValues)
+    (assertValueOneOf "EmitTimezone" boolValues)
+  ];
+
   commonNetworkOptions = {
 
     enable = mkOption {
@@ -341,6 +353,18 @@ let
       '';
     };
 
+    dhcpServerConfig = mkOption {
+      default = {};
+      example = { PoolOffset = 50; EmitDNS = false; };
+      type = types.addCheck (types.attrsOf unitOption) checkDhcpServer;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[DHCPServer]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
     name = mkOption {
       type = types.nullOr types.str;
       default = null;
@@ -566,6 +590,11 @@ let
             ${attrsToSection def.dhcpConfig}
 
           ''}
+          ${optionalString (def.dhcpServerConfig != { }) ''
+            [DHCPServer]
+            ${attrsToSection def.dhcpServerConfig}
+
+          ''}
           ${flip concatMapStrings def.addresses (x: ''
             [Address]
             ${attrsToSection x.addressConfig}
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 7fb368e8c44f..c0c2b6a94164 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -71,6 +71,23 @@ mount -t devtmpfs -o "size=@devSize@" devtmpfs /dev
 mkdir -p /run
 mount -t tmpfs -o "mode=0755,size=@runSize@" tmpfs /run
 
+# Log the script output to /dev/kmsg or /run/log/stage-1-init.log.
+mkdir -p /tmp
+mkfifo /tmp/stage-1-init.log.fifo
+logOutFd=8 && logErrFd=9
+eval "exec $logOutFd>&1 $logErrFd>&2"
+if test -w /dev/kmsg; then
+    tee -i < /tmp/stage-1-init.log.fifo /proc/self/fd/"$logOutFd" | while read -r line; do
+        if test -n "$line"; then
+            echo "<7>stage-1-init: $line" > /dev/kmsg
+        fi
+    done &
+else
+    mkdir -p /run/log
+    tee -i < /tmp/stage-1-init.log.fifo /run/log/stage-1-init.log &
+fi
+exec > /tmp/stage-1-init.log.fifo 2>&1
+
 
 # Process the kernel command line.
 export stage2Init=/init
@@ -150,10 +167,6 @@ udevadm trigger --action=add
 udevadm settle
 
 
-# Additional devices initialization.
-@postEarlyDeviceCommands@
-
-
 # Load boot-time keymap before any LVM/LUKS initialization
 @extraUtils@/bin/busybox loadkmap < "@busyboxKeymap@"
 
@@ -419,6 +432,14 @@ fi
 # Stop udevd.
 udevadm control --exit
 
+# Reset the logging file descriptors.
+# Do this just before pkill, which will kill the tee process.
+if test -n "@logCommands@"
+then
+    exec 1>&$logOutFd 2>&$logErrFd
+    eval "exec $logOutFd>&- $logErrFd>&-"
+fi
+
 # Kill any remaining processes, just to be sure we're not taking any
 # with us into stage 2. But keep storage daemons like unionfs-fuse.
 pkill -9 -v -f '@'
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 81418bdf1c15..3367fedc2865 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -66,10 +66,6 @@ let
         copy_bin_and_libs $BIN
       done
 
-      # Copy modprobe.
-      copy_bin_and_libs ${pkgs.kmod}/bin/kmod
-      ln -sf kmod $out/bin/modprobe
-
       # Copy resize2fs if needed.
       ${optionalString (any (fs: fs.autoResize) (attrValues config.fileSystems)) ''
         # We need mke2fs in the initrd.
@@ -161,7 +157,9 @@ let
             --replace /sbin/blkid ${extraUtils}/bin/blkid \
             --replace ${pkgs.lvm2}/sbin ${extraUtils}/bin \
             --replace /sbin/mdadm ${extraUtils}/bin/mdadm \
-            --replace /bin/sh ${extraUtils}/bin/sh
+            --replace /bin/sh ${extraUtils}/bin/sh \
+            --replace /usr/bin/readlink ${extraUtils}/bin/readlink \
+            --replace /usr/bin/basename ${extraUtils}/bin/basename
       done
 
       # Work around a bug in QEMU, which doesn't implement the "READ
@@ -203,13 +201,13 @@ let
     inherit (config.boot) resumeDevice devSize runSize;
 
     inherit (config.boot.initrd) checkJournalingFS
-      preLVMCommands preDeviceCommands postEarlyDeviceCommands postDeviceCommands postMountCommands kernelModules;
+      preLVMCommands preDeviceCommands postDeviceCommands postMountCommands kernelModules;
 
     resumeDevices = map (sd: if sd ? device then sd.device else "/dev/disk/by-label/${sd.label}")
                     (filter (sd: (sd ? label || hasPrefix "/dev/" sd.device) && !sd.randomEncryption) config.swapDevices);
 
     fsInfo =
-      let f = fs: [ fs.mountPoint (if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}") fs.fsType fs.options ];
+      let f = fs: [ fs.mountPoint (if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}") fs.fsType (builtins.concatStringsSep "," fs.options) ];
       in pkgs.writeText "initrd-fsinfo" (concatStringsSep "\n" (concatMap f fileSystems));
 
     setHostId = optionalString (config.networking.hostId != null) ''
@@ -322,14 +320,6 @@ in
       '';
     };
 
-    boot.initrd.postEarlyDeviceCommands = mkOption {
-      default = "";
-      type = types.lines;
-      description = ''
-        Shell commands to be executed early after creation of device nodes.
-      '';
-    };
-
     boot.initrd.postMountCommands = mkOption {
       default = "";
       type = types.lines;
diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh
index a73070ab332f..1b5b22c2005a 100644
--- a/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixos/modules/system/boot/stage-2-init.sh
@@ -155,6 +155,21 @@ mkdir -m 0755 -p /var/setuid-wrappers
 mount -t tmpfs -o "mode=0755" tmpfs /var/setuid-wrappers
 
 
+# Log the script output to /dev/kmsg or /run/log/stage-2-init.log.
+# Only at this point are all the necessary prerequisites ready for these commands.
+exec {logOutFd}>&1 {logErrFd}>&2
+if test -w /dev/kmsg; then
+    exec > >(tee -i /proc/self/fd/"$logOutFd" | while read -r line; do
+        if test -n "$line"; then
+            echo "<7>stage-2-init: $line" > /dev/kmsg
+        fi
+    done) 2>&1
+else
+    mkdir -p /run/log
+    exec > >(tee -i /run/log/stage-2-init.log) 2>&1
+fi
+
+
 # Run the script that performs all configuration activation that does
 # not have to be done at boot time.
 echo "running activation script..."
@@ -182,6 +197,11 @@ ln -sfn /run/booted-system /nix/var/nix/gcroots/booted-system
 @shell@ @postBootCommands@
 
 
+# Reset the logging file descriptors.
+exec 1>&$logOutFd 2>&$logErrFd
+exec {logOutFd}>&- {logErrFd}>&-
+
+
 # Start systemd.
 echo "starting systemd..."
 PATH=/run/current-system/systemd/lib/systemd \
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 211e0423216e..a3c83521c354 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -61,6 +61,8 @@ let
       "systemd-user-sessions.service"
       "dbus-org.freedesktop.login1.service"
       "dbus-org.freedesktop.machine1.service"
+      "org.freedesktop.login1.busname"
+      "org.freedesktop.machine1.busname"
       "user@.service"
 
       # Journal.
@@ -147,13 +149,18 @@ let
       "systemd-tmpfiles-setup-dev.service"
 
       # Misc.
+      "org.freedesktop.systemd1.busname"
       "systemd-sysctl.service"
       "dbus-org.freedesktop.timedate1.service"
       "dbus-org.freedesktop.locale1.service"
       "dbus-org.freedesktop.hostname1.service"
+      "org.freedesktop.timedate1.busname"
+      "org.freedesktop.locale1.busname"
+      "org.freedesktop.hostname1.busname"
       "systemd-timedated.service"
       "systemd-localed.service"
       "systemd-hostnamed.service"
+      "systemd-binfmt.service"
     ]
 
     ++ cfg.additionalUpstreamSystemUnits;
@@ -773,6 +780,7 @@ in
     systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
     systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true;
     systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true;
+    systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.automount" ];
 
     # Don't bother with certain units in containers.
     systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container";
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index d0dd7670157e..4d1466db22d0 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -41,11 +41,15 @@ let
       };
 
       options = mkOption {
-        default = "defaults";
-        example = "data=journal";
-        type = types.commas; # FIXME: should be a list
+        default = [ "defaults" ];
+        example = [ "data=journal" ];
         description = "Options used to mount the file system.";
-      };
+      } // (if versionAtLeast lib.nixpkgsVersion "16.09" then {
+        type = types.listOf types.str;
+      } else {
+        type = types.either types.commas (types.listOf types.str);
+        apply = x: if isList x then x else lib.strings.splitString "," (builtins.trace "warning: passing a comma-separated string for filesystem options is deprecated; use a list of strings instead. This will become a hard error in 16.09." x);
+      });
 
       autoFormat = mkOption {
         default = false;
@@ -112,7 +116,7 @@ in
         "/data" = {
           device = "/dev/hda2";
           fsType = "ext3";
-          options = "data=journal";
+          options = [ "data=journal" ];
         };
         "/bigdisk".label = "bigdisk";
       };
@@ -127,7 +131,7 @@ in
         <command>mount</command>; defaults to
         <literal>"auto"</literal>), and <literal>options</literal>
         (the mount options passed to <command>mount</command> using the
-        <option>-o</option> flag; defaults to <literal>"defaults"</literal>).
+        <option>-o</option> flag; defaults to <literal>[ "defaults" ]</literal>).
 
         Instead of specifying <literal>device</literal>, you can also
         specify a volume label (<literal>label</literal>) for file
@@ -177,7 +181,7 @@ in
              else throw "No device specified for mount point ‘${fs.mountPoint}’.")
             + " " + fs.mountPoint
             + " " + fs.fsType
-            + " " + fs.options
+            + " " + builtins.concatStringsSep "," fs.options
             + " 0"
             + " " + (if skipCheck fs then "0" else
                      if fs.mountPoint == "/" then "1" else "2")
diff --git a/nixos/modules/tasks/kbd.nix b/nixos/modules/tasks/kbd.nix
index e1574fa68ad9..02721bb3bea2 100644
--- a/nixos/modules/tasks/kbd.nix
+++ b/nixos/modules/tasks/kbd.nix
@@ -12,6 +12,8 @@ let
     FONT=${config.i18n.consoleFont}
     ${colors}
   '';
+
+  setVconsole = !config.boot.isContainer;
 in
 
 {
@@ -41,26 +43,33 @@ in
 
   ###### implementation
 
-  config = {
-
-    environment.systemPackages = [ pkgs.kbd ];
-
-    # Let systemd-vconsole-setup.service do the work of setting up the
-    # virtual consoles.  FIXME: trigger a restart of
-    # systemd-vconsole-setup.service if /etc/vconsole.conf changes.
-    environment.etc."vconsole.conf".source = vconsoleConf;
-
-    # This is identical to the systemd-vconsole-setup.service unit
-    # shipped with systemd, except that it uses /dev/tty1 instead of
-    # /dev/tty0 to prevent putting the X server in non-raw mode, and
-    # it has a restart trigger.
-    systemd.services."systemd-vconsole-setup" =
-      { wantedBy = [ "multi-user.target" ];
-        before = [ "display-manager.service" ];
-        after = [ "systemd-udev-settle.service" ];
-        restartTriggers = [ vconsoleConf ];
-      };
-
-  };
+  config = mkMerge [
+    (mkIf (!setVconsole) {
+      systemd.services."systemd-vconsole-setup".enable = false;
+    })
+
+    (mkIf setVconsole {
+      environment.systemPackages = [ pkgs.kbd ];
+
+      # Let systemd-vconsole-setup.service do the work of setting up the
+      # virtual consoles.  FIXME: trigger a restart of
+      # systemd-vconsole-setup.service if /etc/vconsole.conf changes.
+      environment.etc = [ {
+        target = "vconsole.conf";
+        source = vconsoleConf;
+      } ];
+
+      # This is identical to the systemd-vconsole-setup.service unit
+      # shipped with systemd, except that it uses /dev/tty1 instead of
+      # /dev/tty0 to prevent putting the X server in non-raw mode, and
+      # it has a restart trigger.
+      systemd.services."systemd-vconsole-setup" =
+        { wantedBy = [ "multi-user.target" ];
+          before = [ "display-manager.service" ];
+          after = [ "systemd-udev-settle.service" ];
+          restartTriggers = [ vconsoleConf ];
+        };
+    })
+  ];
 
 }
diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix
index f07e7baeb119..c960e401f9b1 100644
--- a/nixos/modules/tasks/network-interfaces-scripted.nix
+++ b/nixos/modules/tasks/network-interfaces-scripted.nix
@@ -144,15 +144,12 @@ in
                   fi
                   ${config.systemd.package}/bin/systemctl start ip-up.target
                 '';
-            preStop =
-              ''
-                echo "releasing configured ip's..."
-              '' + flip concatMapStrings (ips) (ip:
+            preStop = flip concatMapStrings (ips) (ip:
                 let
                   address = "${ip.address}/${toString ip.prefixLength}";
                 in
                 ''
-                  echo -n "Deleting ${address}..."
+                  echo -n "deleting ${address}..."
                   ip addr del "${address}" dev "${i.name}" >/dev/null 2>&1 || echo -n " Failed"
                   echo ""
                 '');
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index e72c0f8956ed..503d3813611f 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -927,7 +927,7 @@ in
         pkgs.nettools
         pkgs.openresolv
       ]
-      ++ optionals (!config.boot.isContainer) [
+      ++ optionals config.networking.wireless.enable [
         pkgs.wirelesstools # FIXME: obsolete?
         pkgs.iw
         pkgs.rfkill
diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix
index c233beb63ca7..f0f56b17f20f 100644
--- a/nixos/modules/testing/test-instrumentation.nix
+++ b/nixos/modules/testing/test-instrumentation.nix
@@ -20,7 +20,15 @@ let kernel = config.boot.kernelPackages.kernel; in
             export USER=root
             export HOME=/root
             export DISPLAY=:0.0
+
             source /etc/profile
+
+            # Don't use a pager when executing backdoor
+            # actions. Because we use a tty, commands like systemctl
+            # or nix-store get confused into thinking they're running
+            # interactively.
+            export PAGER=
+
             cd /tmp
             exec < /dev/hvc0 > /dev/hvc0
             while ! exec 2> /dev/ttyS0; do sleep 0.1; done
@@ -38,11 +46,6 @@ let kernel = config.boot.kernelPackages.kernel; in
     systemd.services."serial-getty@ttyS0".enable = false;
     systemd.services."serial-getty@hvc0".enable = false;
 
-    # Don't use a pager when executing backdoor actions. Because we
-    # use a tty, commands like systemctl or nix-store get confused
-    # into thinking they're running interactively.
-    environment.variables.PAGER = "";
-
     boot.initrd.preDeviceCommands =
       ''
         echo 600 > /proc/sys/kernel/hung_task_timeout_secs
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index 7ccc9df740e5..a895f66db8ef 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -20,8 +20,7 @@ let cfg = config.ec2; in
       autoResize = true;
     };
 
-    boot.initrd.kernelModules = [ "xen-blkfront" ];
-    boot.kernelModules = [ "xen-netfront" ];
+    boot.initrd.kernelModules = [ "xen-blkfront" "xen-netfront" ];
     boot.kernelParams = mkIf cfg.hvm [ "console=ttyS0" ];
 
     # Prevent the nouveau kernel module from being loaded, as it
@@ -44,6 +43,8 @@ let cfg = config.ec2; in
         kill -9 -1
       '';
 
+    boot.initrd.network.enable = true;
+
     # Mount all formatted ephemeral disks and activate all swap devices.
     # We cannot do this with the ‘fileSystems’ and ‘swapDevices’ options
     # because the set of devices is dependent on the instance type
@@ -55,6 +56,28 @@ let cfg = config.ec2; in
     # Nix operations.
     boot.initrd.postMountCommands =
       ''
+        metaDir=$targetRoot/etc/ec2-metadata
+        mkdir -m 0755 -p "$metaDir"
+
+        echo "getting EC2 instance metadata..."
+
+        if ! [ -e "$metaDir/ami-manifest-path" ]; then
+          wget -q -O "$metaDir/ami-manifest-path" http://169.254.169.254/1.0/meta-data/ami-manifest-path
+        fi
+
+        if ! [ -e "$metaDir/user-data" ]; then
+          wget -q -O "$metaDir/user-data" http://169.254.169.254/1.0/user-data
+          chmod 600 "$metaDir/user-data"
+        fi
+
+        if ! [ -e "$metaDir/hostname" ]; then
+          wget -q -O "$metaDir/hostname" http://169.254.169.254/1.0/meta-data/hostname
+        fi
+
+        if ! [ -e "$metaDir/public-keys-0-openssh-key" ]; then
+          wget -q -O "$metaDir/public-keys-0-openssh-key" http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key
+        fi
+
         diskNr=0
         diskForUnionfs=
         for device in /dev/xvd[abcde]*; do
@@ -81,7 +104,7 @@ let cfg = config.ec2; in
             mkdir -m 1777 -p $targetRoot/$diskForUnionfs/root/tmp $targetRoot/tmp
             mount --bind $targetRoot/$diskForUnionfs/root/tmp $targetRoot/tmp
 
-            if [ ! -e $targetRoot/.ebs ]; then
+            if [ "$(cat "$metaDir/ami-manifest-path")" != "(unknown)" ]; then
                 mkdir -m 755 -p $targetRoot/$diskForUnionfs/root/var $targetRoot/var
                 mount --bind $targetRoot/$diskForUnionfs/root/var $targetRoot/var
 
diff --git a/nixos/modules/virtualisation/amazon-init.nix b/nixos/modules/virtualisation/amazon-init.nix
index 96cd57e6db5d..886552f33c2c 100644
--- a/nixos/modules/virtualisation/amazon-init.nix
+++ b/nixos/modules/virtualisation/amazon-init.nix
@@ -4,18 +4,17 @@
 
 let
   bootScript = pkgs.writeScript "bootscript.sh" ''
-    #!${pkgs.stdenv.shell} -eux
+    #!${pkgs.stdenv.shell} -eu
 
-    echo "attempting to fetch configuration from user-data..."
+    echo "attempting to fetch configuration from EC2 user data..."
 
-    export PATH=${config.nix.package}/bin:${pkgs.wget}/bin:${pkgs.systemd}/bin:${pkgs.gnugrep}/bin:${pkgs.gnused}/bin:${config.system.build.nixos-rebuild}/bin:$PATH
+    export PATH=${config.nix.package}/bin:${pkgs.systemd}/bin:${pkgs.gnugrep}/bin:${pkgs.gnused}/bin:${config.system.build.nixos-rebuild}/bin:$PATH
     export NIX_PATH=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels
 
-    userData="$(mktemp)"
-    wget -q --wait=1 --tries=0 --retry-connrefused -O - http://169.254.169.254/2011-01-01/user-data > "$userData"
+    userData=/etc/ec2-metadata/user-data
+
+    if [ -s "$userData" ]; then
 
-    if [[ $? -eq 0 ]]; then
-      echo "user-data fetched"
       # If the user-data looks like it could be a nix expression,
       # copy it over. Also, look for a magic three-hash comment and set
       # that as the channel.
@@ -30,17 +29,17 @@ let
           nix-channel --update
         fi
 
-        echo "setting configuration"
+        echo "setting configuration from EC2 user data"
         cp "$userData" /etc/nixos/configuration.nix
       else
-        echo "user-data does not appear to be a nix expression; ignoring"
+        echo "user data does not appear to be a Nix expression; ignoring"
+        exit
       fi
     else
-      echo "failed to fetch user-data"
+      echo "no user data is available"
+      exit
     fi
 
-    type -f nixos-rebuild
-
     nixos-rebuild switch
   '';
 in {
diff --git a/nixos/modules/virtualisation/azure-agent.nix b/nixos/modules/virtualisation/azure-agent.nix
index ef4e3e1e48d4..640519758c74 100644
--- a/nixos/modules/virtualisation/azure-agent.nix
+++ b/nixos/modules/virtualisation/azure-agent.nix
@@ -8,10 +8,11 @@ let
 
   waagent = with pkgs; stdenv.mkDerivation rec {
     name = "waagent-2.0";
-    src = pkgs.fetchgit {
-      url = https://github.com/Phreedom/WALinuxAgent.git;
-      rev = "9dba81c7b1239c7971ec96e405e403c7cd224e6b";
-      sha256 = "0khxk3ns3z37v26f2qj6m3m698a0vqpc9bxg5p7fyr3xza5gzwhs";
+    src = pkgs.fetchFromGitHub {
+      owner = "Azure";
+      repo = "WALinuxAgent";
+      rev = "1b3a8407a95344d9d12a2a377f64140975f1e8e4";
+      sha256 = "10byzvmpgrmr4d5mdn2kq04aapqb3sgr1admk13wjmy5cd6bwd2x";
     };
     buildInputs = [ makeWrapper python pythonPackages.wrapPython ];
     runtimeDeps = [ findutils gnugrep gawk coreutils openssl openssh
@@ -156,12 +157,6 @@ in
       after = [ "ip-up.target" ];
       wants = [ "ip-up.target" ];
 
-      environment = {
-        GIT_SSL_CAINFO = "/etc/ssl/certs/ca-certificates.crt";
-        OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
-        SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
-      };
-
       path = [ pkgs.e2fsprogs ];
       description = "Windows Azure Agent Service";
       unitConfig.ConditionPathExists = "/etc/waagent.conf";
diff --git a/nixos/modules/virtualisation/azure-config-user.nix b/nixos/modules/virtualisation/azure-config-user.nix
new file mode 100644
index 000000000000..de1b3857923f
--- /dev/null
+++ b/nixos/modules/virtualisation/azure-config-user.nix
@@ -0,0 +1,12 @@
+{ config, pkgs, modulesPath, ... }:
+
+{
+  # To build the configuration or use nix-env, you need to run
+  # either nixos-rebuild --upgrade or nix-channel --update
+  # to fetch the nixos channel.
+
+  # This configures everything but bootstrap services,
+  # which only need to be run once and have already finished
+  # if you are able to see this comment.
+  imports = [ "${modulesPath}/virtualisation/azure-common.nix" ];
+}
diff --git a/nixos/modules/virtualisation/azure-image.nix b/nixos/modules/virtualisation/azure-image.nix
index 08944e641d76..79d1f7d7cc43 100644
--- a/nixos/modules/virtualisation/azure-image.nix
+++ b/nixos/modules/virtualisation/azure-image.nix
@@ -16,14 +16,14 @@ in
               cyl=$(((${diskSize}*1024*1024)/(512*63*255)))
               size=$(($cyl*255*63*512))              
               roundedsize=$((($size/(1024*1024)+1)*(1024*1024)))
-              ${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage $roundedsize
+              ${pkgs.vmTools.qemu-220}/bin/qemu-img create -f raw $diskImage $roundedsize
               mv closure xchg/
             '';
 
           postVM =
             ''
               mkdir -p $out
-              ${pkgs.vmTools.qemu}/bin/qemu-img convert -f raw -O vpc $diskImage $out/disk.vhd
+              ${pkgs.vmTools.qemu-220}/bin/qemu-img convert -f raw -O vpc -o subformat=fixed $diskImage $out/disk.vhd
               rm $diskImage
             '';
           diskImageBase = "nixos-image-${config.system.nixosLabel}-${pkgs.stdenv.system}.raw";
@@ -78,7 +78,7 @@ in
 
           echo Install a configuration.nix.
           mkdir -p /mnt/etc/nixos /mnt/boot/grub
-          cp ${./azure-config.nix} /mnt/etc/nixos/configuration.nix
+          cp ${./azure-config-user.nix} /mnt/etc/nixos/configuration.nix
 
           echo Generate the GRUB menu.
           ln -s vda /dev/sda
diff --git a/nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch b/nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch
new file mode 100644
index 000000000000..81d29feea3de
--- /dev/null
+++ b/nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch
@@ -0,0 +1,14 @@
+diff --git a/Makefile b/Makefile
+index d6b9dc1..ce7c493 100644
+--- a/Makefile
++++ b/Makefile
+@@ -384,8 +384,7 @@ install-confdir:
+ install-sysconfig: install-datadir install-confdir
+ 	$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
+ 
+-install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \
+-install-datadir install-localstatedir
++install: all $(if $(BUILD_DOCS),install-doc) install-datadir
+ ifneq ($(TOOLS),)
+ 	$(call install-prog,$(TOOLS),$(DESTDIR)$(bindir))
+ endif
diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix
index c210c8d5f25e..b4f9d8b6fc17 100644
--- a/nixos/modules/virtualisation/container-config.nix
+++ b/nixos/modules/virtualisation/container-config.nix
@@ -19,6 +19,9 @@ with lib;
     # Shut up warnings about not having a boot loader.
     system.build.installBootLoader = "${pkgs.coreutils}/bin/true";
 
+    # Not supported in systemd-nspawn containers.
+    security.audit.enable = false;
+
   };
 
 }
diff --git a/nixos/modules/virtualisation/ec2-data.nix b/nixos/modules/virtualisation/ec2-data.nix
index 383750520ab7..db3dd9949c12 100644
--- a/nixos/modules/virtualisation/ec2-data.nix
+++ b/nixos/modules/virtualisation/ec2-data.nix
@@ -1,6 +1,6 @@
-# This module defines a systemd service that obtains the SSH key and
-# host name of virtual machines running on Amazon EC2, Eucalyptus and
-# OpenStack Compute (Nova).
+# This module defines a systemd service that sets the SSH host key and
+# authorized client key and host name of virtual machines running on
+# Amazon EC2, Eucalyptus and OpenStack Compute (Nova).
 
 { config, lib, pkgs, ... }:
 
@@ -9,58 +9,54 @@ with lib;
 {
   config = {
 
-    systemd.services.fetch-ec2-data =
-      { description = "Fetch EC2 Data";
+    systemd.services.apply-ec2-data =
+      { description = "Apply EC2 Data";
 
         wantedBy = [ "multi-user.target" "sshd.service" ];
         before = [ "sshd.service" ];
-        wants = [ "ip-up.target" ];
-        after = [ "ip-up.target" ];
 
-        path = [ pkgs.wget pkgs.iproute ];
+        path = [ pkgs.iproute ];
 
         script =
           ''
-            wget="wget -q --retry-connrefused -O -"
-
             ${optionalString (config.networking.hostName == "") ''
               echo "setting host name..."
-              ${pkgs.nettools}/bin/hostname $($wget http://169.254.169.254/1.0/meta-data/hostname)
+              if [ -s /etc/ec2-metadata/hostname ]; then
+                  ${pkgs.nettools}/bin/hostname $(cat /etc/ec2-metadata/hostname)
+              fi
             ''}
 
-            # Don't download the SSH key if it has already been injected
-            # into the image (a Nova feature).
             if ! [ -e /root/.ssh/authorized_keys ]; then
                 echo "obtaining SSH key..."
                 mkdir -m 0700 -p /root/.ssh
-                $wget http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key > /root/key.pub
-                if [ $? -eq 0 -a -e /root/key.pub ]; then
-                    cat /root/key.pub >> /root/.ssh/authorized_keys
+                if [ -s /etc/ec2-metadata/public-keys-0-openssh-key ]; then
+                    cat /etc/ec2-metadata/public-keys-0-openssh-key >> /root/.ssh/authorized_keys
                     echo "new key added to authorized_keys"
                     chmod 600 /root/.ssh/authorized_keys
-                    rm -f /root/key.pub
                 fi
             fi
 
             # Extract the intended SSH host key for this machine from
             # the supplied user data, if available.  Otherwise sshd will
             # generate one normally.
-            $wget http://169.254.169.254/2011-01-01/user-data > /root/user-data || true
+            userData=/etc/ec2-metadata/user-data
 
             mkdir -m 0755 -p /etc/ssh
 
-            key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' /root/user-data)"
-            key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' /root/user-data)"
-            if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then
-                (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key)
-                echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub
-            fi
-
-            key="$(sed 's/|/\n/g; s/SSH_HOST_ED25519_KEY://; t; d' /root/user-data)"
-            key_pub="$(sed 's/SSH_HOST_ED25519_KEY_PUB://; t; d' /root/user-data)"
-            if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_ed25519_key ]; then
-                (umask 077; echo "$key" > /etc/ssh/ssh_host_ed25519_key)
-                echo "$key_pub" > /etc/ssh/ssh_host_ed25519_key.pub
+            if [ -s "$userData" ]; then
+              key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' $userData)"
+              key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' $userData)"
+              if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then
+                  (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key)
+                  echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub
+              fi
+
+              key="$(sed 's/|/\n/g; s/SSH_HOST_ED25519_KEY://; t; d' $userData)"
+              key_pub="$(sed 's/SSH_HOST_ED25519_KEY_PUB://; t; d' $userData)"
+              if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_ed25519_key ]; then
+                  (umask 077; echo "$key" > /etc/ssh/ssh_host_ed25519_key)
+                  echo "$key_pub" > /etc/ssh/ssh_host_ed25519_key.pub
+              fi
             fi
           '';
 
diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl
index 004385f728c6..eda57a9751eb 100644..100755
--- a/nixos/modules/virtualisation/nixos-container.pl
+++ b/nixos/modules/virtualisation/nixos-container.pl
@@ -97,10 +97,10 @@ if ($action eq "create") {
     if ($ensureUniqueName) {
         my $base = $containerName;
         for (my $nr = 0; ; $nr++) {
-            $containerName = "$base-$nr";
             $confFile = "/etc/containers/$containerName.conf";
             $root = "/var/lib/containers/$containerName";
             last unless -e $confFile || -e $root;
+            $containerName = "$base-$nr";
         }
     }
 
diff --git a/nixos/modules/virtualisation/nova.nix b/nixos/modules/virtualisation/nova.nix
index f356445abe46..c2837d0e2e24 100644
--- a/nixos/modules/virtualisation/nova.nix
+++ b/nixos/modules/virtualisation/nova.nix
@@ -146,7 +146,7 @@ in
 
         path =
           [ pkgs.sudo pkgs.vlan pkgs.nettools pkgs.iptables pkgs.qemu_kvm
-            pkgs.e2fsprogs pkgs.utillinux pkgs.multipath_tools pkgs.iproute
+            pkgs.e2fsprogs pkgs.utillinux pkgs.multipath-tools pkgs.iproute
             pkgs.bridge-utils
           ];
 
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 82b58aa67a3d..7dfbc38efee6 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -110,6 +110,7 @@ let
 
   # Generate a hard disk image containing a /boot partition and GRUB
   # in the MBR.  Used when the `useBootLoader' option is set.
+  # FIXME: use nixos/lib/make-disk-image.nix.
   bootDisk =
     pkgs.vmTools.runInLinuxVM (
       pkgs.runCommand "nixos-boot-disk"
@@ -427,38 +428,38 @@ in
         ${if cfg.writableStore then "/nix/.ro-store" else "/nix/store"} =
           { device = "store";
             fsType = "9p";
-            options = "trans=virtio,version=9p2000.L,cache=loose";
+            options = [ "trans=virtio" "version=9p2000.L" "cache=loose" ];
             neededForBoot = true;
           };
         "/tmp/xchg" =
           { device = "xchg";
             fsType = "9p";
-            options = "trans=virtio,version=9p2000.L,cache=loose";
+            options = [ "trans=virtio" "version=9p2000.L" "cache=loose" ];
             neededForBoot = true;
           };
         "/tmp/shared" =
           { device = "shared";
             fsType = "9p";
-            options = "trans=virtio,version=9p2000.L";
+            options = [ "trans=virtio" "version=9p2000.L" ];
             neededForBoot = true;
           };
       } // optionalAttrs cfg.writableStore
       { "/nix/store" =
           { fsType = "unionfs-fuse";
             device = "unionfs";
-            options = "allow_other,cow,nonempty,chroot=/mnt-root,max_files=32768,hide_meta_files,dirs=/nix/.rw-store=rw:/nix/.ro-store=ro";
+            options = [ "allow_other" "cow" "nonempty" "chroot=/mnt-root" "max_files=32768" "hide_meta_files" "dirs=/nix/.rw-store=rw:/nix/.ro-store=ro" ];
           };
       } // optionalAttrs (cfg.writableStore && cfg.writableStoreUseTmpfs)
       { "/nix/.rw-store" =
           { fsType = "tmpfs";
-            options = "mode=0755";
+            options = [ "mode=0755" ];
             neededForBoot = true;
           };
       } // optionalAttrs cfg.useBootLoader
       { "/boot" =
           { device = "/dev/vdb2";
             fsType = "vfat";
-            options = "ro";
+            options = [ "ro" ];
             noCheck = true; # fsck fails on a r/o filesystem
           };
       });
diff --git a/nixos/modules/virtualisation/rkt.nix b/nixos/modules/virtualisation/rkt.nix
index 7b4d46e0749e..c4c5cb3380e8 100644
--- a/nixos/modules/virtualisation/rkt.nix
+++ b/nixos/modules/virtualisation/rkt.nix
@@ -58,5 +58,7 @@ in
         ExecStart = "${pkgs.rkt}/bin/rkt gc ${cfg.gc.options}";
       };
     };
+
+    users.extraGroups.rkt = {};
   };
 }